csv-grid 3.3.0__tar.gz → 3.7.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -18,3 +18,5 @@ __pycache__/
18
18
  hacks/
19
19
 
20
20
  CSV-VIEWER.*
21
+
22
+ .obsidian
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: csv-grid
3
- Version: 3.3.0
3
+ Version: 3.7.1
4
4
  Summary: Emit csv-viewer's CsvGrid interactive tables from pandas DataFrames (Jupyter / Quarto / static HTML).
5
5
  Project-URL: Homepage, https://github.com/mynl/CSV_Viewer
6
6
  Project-URL: Live viewer, https://mynl.github.io/CSV_Viewer/
@@ -62,26 +62,40 @@ show(df, align="llrcr", fmt=[None, None, ",d", "year", ",.2f"])
62
62
  html = to_html(df, name="results.df", assets="inline") # fragment string
63
63
  ```
64
64
 
65
- - `show(df, **options)` displays via IPython. The JS + CSS assets are
66
- emitted once per kernel session (so once per rendered page); pass
67
- `assets="inline"` to force re-emission, or `assets="https://…/base"`
68
- to load them from a URL instead of inlining.
69
- - `to_html(df, **options)` returns an HTML fragment. The first fragment
70
- on a page should carry the assets (`assets="inline"` — the default —
71
- or a base URL); pass `assets=False` for subsequent tables.
65
+ - `show(df, **options)` displays via IPython. Each grid carries the JS +
66
+ CSS via an idempotent `<head>` guard (`assets="inline"`, the default),
67
+ so fragments are self-contained and re-running/clearing a notebook cell
68
+ can't strip a shared stylesheet. Use `assets="https://…/base"` to link
69
+ the assets from a URL instead, or `assets=False` if they are already on
70
+ the page.
71
+ - `to_html(df, **options)` returns a self-contained HTML fragment;
72
+ fragments compose freely (no need to mark a "first" one).
72
73
  - `payload(df)` returns the `{records, columns}` dict the grid consumes,
73
74
  if you want to ship data yourself.
74
75
  - Options mirror the JS API in snake_case: `global_search`,
75
76
  `column_filters`, `sortable`, `status_bar`, `expand_buttons`, `align`
76
77
  (`'llrcr…'`), `formats`/`fmt` (per-column `[,][.N](f|d|%|e|s)`,
77
78
  `'year'`, `'eng'`, None = auto), `width_mode` (`'equal-risk'` default,
78
- or `'coverage'` to maximize the count of fully-shown cells), `rows`
79
+ or `'coverage'` to maximize the count of fully-shown cells),
80
+ `display_mode` (`'auto'` formatted / `'raw'` verbatim), `rows`
79
81
  (cap the viewport to ~N rows, vertical scroll for the rest) /
80
82
  `max_height` (raw CSS, e.g. `'400px'`), `render_cap`, `eager_cells`,
81
83
  `worker` (default False — data is inlined), plus `name` (status line)
82
84
  and `index` (include the DataFrame index as leading columns). Dark mode
83
85
  follows the host page (`prefers-color-scheme`; JupyterLab dark themes
84
- included).
86
+ included) unless `theme="light"`/`"dark"` forces it.
87
+ - **Clickable rows/cells** (`selectable=True`): a body click fires a
88
+ bubbling `csvgrid:cellclick` DOM event whose `detail` carries the clicked
89
+ cell and the whole row keyed by column name (raw + formatted) with the
90
+ original row index — wire it to HTMX/JS for drill-down. `select_mode`
91
+ (`'row'`/`'cell'`/`'none'`) controls the highlight; `hidden_columns=[…]`
92
+ ships a key column in the payload without displaying it. No Python
93
+ callback — `to_html` stays a pure string emitter.
94
+
95
+ ```python
96
+ to_html(df, name="transactions", selectable=True,
97
+ select_mode="row", hidden_columns=["trans_id"])
98
+ ```
85
99
 
86
100
  Dates are emitted ISO (`yyyy-mm-dd`, with `hh:mm` only when a column has
87
101
  non-midnight times); integral float columns are emitted as integers so
@@ -36,26 +36,40 @@ show(df, align="llrcr", fmt=[None, None, ",d", "year", ",.2f"])
36
36
  html = to_html(df, name="results.df", assets="inline") # fragment string
37
37
  ```
38
38
 
39
- - `show(df, **options)` displays via IPython. The JS + CSS assets are
40
- emitted once per kernel session (so once per rendered page); pass
41
- `assets="inline"` to force re-emission, or `assets="https://…/base"`
42
- to load them from a URL instead of inlining.
43
- - `to_html(df, **options)` returns an HTML fragment. The first fragment
44
- on a page should carry the assets (`assets="inline"` — the default —
45
- or a base URL); pass `assets=False` for subsequent tables.
39
+ - `show(df, **options)` displays via IPython. Each grid carries the JS +
40
+ CSS via an idempotent `<head>` guard (`assets="inline"`, the default),
41
+ so fragments are self-contained and re-running/clearing a notebook cell
42
+ can't strip a shared stylesheet. Use `assets="https://…/base"` to link
43
+ the assets from a URL instead, or `assets=False` if they are already on
44
+ the page.
45
+ - `to_html(df, **options)` returns a self-contained HTML fragment;
46
+ fragments compose freely (no need to mark a "first" one).
46
47
  - `payload(df)` returns the `{records, columns}` dict the grid consumes,
47
48
  if you want to ship data yourself.
48
49
  - Options mirror the JS API in snake_case: `global_search`,
49
50
  `column_filters`, `sortable`, `status_bar`, `expand_buttons`, `align`
50
51
  (`'llrcr…'`), `formats`/`fmt` (per-column `[,][.N](f|d|%|e|s)`,
51
52
  `'year'`, `'eng'`, None = auto), `width_mode` (`'equal-risk'` default,
52
- or `'coverage'` to maximize the count of fully-shown cells), `rows`
53
+ or `'coverage'` to maximize the count of fully-shown cells),
54
+ `display_mode` (`'auto'` formatted / `'raw'` verbatim), `rows`
53
55
  (cap the viewport to ~N rows, vertical scroll for the rest) /
54
56
  `max_height` (raw CSS, e.g. `'400px'`), `render_cap`, `eager_cells`,
55
57
  `worker` (default False — data is inlined), plus `name` (status line)
56
58
  and `index` (include the DataFrame index as leading columns). Dark mode
57
59
  follows the host page (`prefers-color-scheme`; JupyterLab dark themes
58
- included).
60
+ included) unless `theme="light"`/`"dark"` forces it.
61
+ - **Clickable rows/cells** (`selectable=True`): a body click fires a
62
+ bubbling `csvgrid:cellclick` DOM event whose `detail` carries the clicked
63
+ cell and the whole row keyed by column name (raw + formatted) with the
64
+ original row index — wire it to HTMX/JS for drill-down. `select_mode`
65
+ (`'row'`/`'cell'`/`'none'`) controls the highlight; `hidden_columns=[…]`
66
+ ships a key column in the payload without displaying it. No Python
67
+ callback — `to_html` stays a pure string emitter.
68
+
69
+ ```python
70
+ to_html(df, name="transactions", selectable=True,
71
+ select_mode="row", hidden_columns=["trans_id"])
72
+ ```
59
73
 
60
74
  Dates are emitted ISO (`yyyy-mm-dd`, with `hh:mm` only when a column has
61
75
  non-midnight times); integral float columns are emitted as integers so
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "csv-grid"
3
- version = "3.3.0"
3
+ version = "3.7.1"
4
4
  description = "Emit csv-viewer's CsvGrid interactive tables from pandas DataFrames (Jupyter / Quarto / static HTML)."
5
5
  readme = "README.md"
6
6
  license = "MIT"
@@ -18,7 +18,7 @@ import json
18
18
  import uuid
19
19
  from importlib import resources
20
20
 
21
- __version__ = "3.3.0"
21
+ __version__ = "3.7.1"
22
22
  __all__ = ["show", "to_html", "payload"]
23
23
 
24
24
  # python snake_case -> CsvGrid option names (see src/grid/grid.js)
@@ -31,11 +31,15 @@ _OPTION_MAP = {
31
31
  "align": "align",
32
32
  "formats": "formats",
33
33
  "width_mode": "widthMode",
34
+ "display_mode": "displayMode",
34
35
  "rows": "maxRows",
35
36
  "max_height": "height",
36
37
  "render_cap": "renderCap",
37
38
  "eager_cells": "eagerCells",
38
39
  "worker": "worker",
40
+ "selectable": "selectable",
41
+ "select_mode": "selectMode",
42
+ "hidden_columns": "hiddenColumns",
39
43
  }
40
44
  _CAMEL = set(_OPTION_MAP.values())
41
45
 
@@ -112,20 +116,49 @@ def _asset_text(fname: str) -> str:
112
116
  return resources.files("csv_grid").joinpath("assets", fname).read_text(encoding="utf-8")
113
117
 
114
118
 
115
- def _assets_fragment(assets) -> str:
116
- """'inline' -> embed css+js; a string -> <link>/<script src> against
117
- that base URL; False/None -> '' (already on the page). The iife build
118
- is used (not umd): pages rendered by Quarto/Jupyter can carry
119
- RequireJS, which hijacks a umd wrapper via define.amd and the global
120
- CsvGrid never appears."""
119
+ def _js_str(text: str) -> str:
120
+ """A JS string literal (double-quoted, JSON-escaped) safe inside a
121
+ <script>: the `</` -> `<\\/` guard stops an embedded '</script>' in the
122
+ payload from closing our tag."""
123
+ return json.dumps(text, ensure_ascii=False).replace("</", "<\\/")
124
+
125
+
126
+ def _assets_html(assets) -> str:
127
+ """The CSS + JS the grid needs, emitted with EVERY grid (no per-kernel
128
+ state — that was the notebook bug: assets parked in one cell's output
129
+ vanish when that cell is cleared/re-run, and every grid shares them).
130
+
131
+ 'inline' (default): a guard that idempotently injects the CSS and the
132
+ iife into the document <head>. <head> lives outside cell output, so
133
+ clearing/re-running a cell can't strip the assets, and any grid
134
+ re-establishes them if missing. The injected <script> sets its code via
135
+ textContent, so it runs synchronously on insertion — window.CsvGrid is
136
+ defined before the grid-construction script that follows.
137
+
138
+ A base-URL string: plain <link>/<script src> tags (parser-ordered, so
139
+ they run before construction; the browser caches them, so re-emitting
140
+ per grid is cheap). False/None: nothing (assets already on the page).
141
+
142
+ The iife build is used (not umd): Quarto/Jupyter pages can carry
143
+ RequireJS, whose define.amd hijacks a umd wrapper so window.CsvGrid
144
+ never appears."""
145
+ if not assets:
146
+ return ""
121
147
  if assets == "inline":
122
- return (f"<style>\n{_asset_text('csv-grid.css')}\n</style>\n"
123
- f"<script>\n{_asset_text('csv-grid.iife.js')}\n</script>")
124
- if assets:
125
- base = str(assets).rstrip("/")
126
- return (f'<link rel="stylesheet" href="{base}/csv-grid.css">\n'
127
- f'<script src="{base}/csv-grid.iife.js"></script>')
128
- return ""
148
+ css = _js_str(_asset_text("csv-grid.css"))
149
+ js = _js_str(_asset_text("csv-grid.iife.js"))
150
+ body = (
151
+ "if(!document.getElementById('csvgrid-css')){"
152
+ "var s=document.createElement('style');s.id='csvgrid-css';"
153
+ f"s.textContent={css};document.head.appendChild(s);}}"
154
+ "if(!window.CsvGrid){"
155
+ "var j=document.createElement('script');j.id='csvgrid-js';"
156
+ f"j.textContent={js};document.head.appendChild(j);}}"
157
+ )
158
+ return f"<script>(function(){{{body}}})();</script>"
159
+ base = str(assets).rstrip("/")
160
+ return (f'<link rel="stylesheet" href="{base}/csv-grid.css">\n'
161
+ f'<script src="{base}/csv-grid.iife.js"></script>')
129
162
 
130
163
 
131
164
  def _dump(obj) -> str:
@@ -134,40 +167,37 @@ def _dump(obj) -> str:
134
167
 
135
168
 
136
169
  def to_html(df, *, name: str | None = None, assets="inline",
137
- index: bool = False, **options) -> str:
138
- """HTML fragment rendering `df` as a CsvGrid. The first fragment on a
139
- page should carry the assets (default 'inline'; or a base URL hosting
140
- csv-grid.umd.js + csv-grid.css); pass assets=False for later tables.
141
- Options are the grid's, in snake_case (see _OPTION_MAP); `fmt` is an
170
+ index: bool = False, theme: str = "auto", **options) -> str:
171
+ """HTML fragment rendering `df` as a CsvGrid, self-contained by default.
172
+
173
+ Every fragment carries the assets via an idempotent guard (see
174
+ ``assets``), so fragments compose freely no need to mark a "first"
175
+ one. Options are the grid's, in snake_case (see ``show``); `fmt` is an
142
176
  alias for `formats`; `worker` defaults to False (data is inlined).
177
+ `assets='inline'` embeds the CSS + JS (injected once into <head>); a
178
+ base-URL string links them; False omits them. `theme` forces the color
179
+ scheme via ``data-theme`` ('auto' follows prefers-color-scheme).
143
180
  """
144
181
  opts = _map_options(options)
145
182
  opts.setdefault("worker", False)
146
183
  div = f"csvgrid-{uuid.uuid4().hex[:12]}"
184
+ theme_attr = f' data-theme="{theme}"' if theme in ("light", "dark") else ""
147
185
  parts = []
148
- head = _assets_fragment(assets)
186
+ head = _assets_html(assets)
149
187
  if head:
150
188
  parts.append(head)
151
189
  parts.append(
152
- f'<div id="{div}"></div>\n'
190
+ f'<div id="{div}"{theme_attr}></div>\n'
153
191
  f'<script>new CsvGrid(document.getElementById("{div}"), '
154
192
  f'{_dump(payload(df, name, index))}, {_dump(opts)});</script>'
155
193
  )
156
194
  return "\n".join(parts)
157
195
 
158
196
 
159
- _assets_emitted = False
160
-
161
-
162
- def show(df, *, name: str | None = None, assets=None,
163
- index: bool = False, **options) -> None:
197
+ def show(df, *, name: str | None = None, assets="inline",
198
+ index: bool = False, theme: str = "auto", **options) -> None:
164
199
  """Display `df` as a CsvGrid in Jupyter / Quarto.
165
200
 
166
- Assets (the grid's JS + CSS) are emitted once per kernel session (=
167
- once per rendered page); ``assets='inline'`` forces re-emission (e.g.
168
- after reloading the browser page without restarting the kernel), and a
169
- base-URL string loads them from there instead of inlining.
170
-
171
201
  Parameters
172
202
  ----------
173
203
  df : pandas.DataFrame
@@ -176,12 +206,17 @@ def show(df, *, name: str | None = None, assets=None,
176
206
  integral float columns -> ints) exactly as the csv-viewer app does.
177
207
  name : str, optional
178
208
  Label shown in the grid's status line.
179
- assets : {None, 'inline', str, False}
180
- None (default) inlines on the first call per session, then dedupes;
181
- 'inline' forces inlining; a base-URL string links the assets from
182
- there; False omits them (already on the page).
209
+ assets : {'inline', str, False}, default 'inline'
210
+ 'inline' embeds the grid's CSS + JS, injected into the document
211
+ <head> by an idempotent guard emitted with every grid — clearing or
212
+ re-running a cell can't strip them, and any grid re-establishes them
213
+ if missing. A base-URL string links the assets from there instead.
214
+ False emits nothing (use only when the assets are already present).
183
215
  index : bool, default False
184
216
  Include the DataFrame index as leading column(s).
217
+ theme : {'auto', 'light', 'dark'}, default 'auto'
218
+ 'auto' follows the host page / OS via prefers-color-scheme; 'light'
219
+ or 'dark' forces the grid's color scheme (sets ``data-theme``).
185
220
 
186
221
  Other options (keyword, snake_case; mirror the JS CsvGrid API)
187
222
  --------------------------------------------------------------
@@ -203,26 +238,45 @@ def show(df, *, name: str | None = None, assets=None,
203
238
  with equal probability; coverage =
204
239
  maximize the count of cells shown
205
240
  in full.
241
+ display_mode : {'auto', 'raw'}, default 'auto'
242
+ 'auto' = type-aware formatting;
243
+ 'raw' = verbatim source text (a view
244
+ lens; types still drive alignment
245
+ and sort).
206
246
  rows : int, optional cap the scroll viewport to ~N rows
207
247
  (vertical scroll for the rest).
208
248
  max_height : str, optional raw CSS max-height (e.g. '400px');
209
249
  overrides ``rows`` when set.
210
- render_cap : int, default 2000 rows rendered before "show all".
211
- eager_cells : int, default 200000 below this, format everything up
250
+ render_cap : int, default 2048 rows rendered before "show all".
251
+ eager_cells : int, default 262144 below this, format everything up
212
252
  front (else lazy).
213
253
  worker : bool, default False parse worker (off by default here
214
254
  — the data is inlined, not fetched).
255
+ selectable : bool, default False emit a bubbling, cancelable
256
+ ``csvgrid:cellclick`` DOM event on a
257
+ body click (off = no event, no cost).
258
+ ``event.detail`` carries the clicked
259
+ cell and the whole row keyed by column
260
+ name (raw + formatted) with the
261
+ original row index, so an embedder
262
+ (HTMX, JS) can drill down. The grid
263
+ takes no action beyond an optional
264
+ highlight; no Python callback.
265
+ select_mode : {'row', 'cell', 'none'}, default 'row'
266
+ the visual highlight on click ('none'
267
+ still emits the event).
268
+ hidden_columns : list[str], optional header names carried in the event
269
+ payload (and export) but not shown as
270
+ columns — e.g. ship a key column
271
+ without displaying it.
215
272
 
216
- Dark mode follows the host page automatically (prefers-color-scheme;
217
- JupyterLab dark themes included).
273
+ Dark mode follows the host page automatically unless ``theme`` forces
274
+ it (prefers-color-scheme; JupyterLab dark themes included).
218
275
  """
219
- global _assets_emitted
220
276
  try:
221
277
  from IPython.display import HTML, display
222
278
  except ImportError as e: # pragma: no cover
223
279
  raise ImportError("csv_grid.show() needs IPython; "
224
280
  "use to_html() outside Jupyter/Quarto") from e
225
- if assets is None:
226
- assets = False if _assets_emitted else "inline"
227
- _assets_emitted = True
228
- display(HTML(to_html(df, name=name, assets=assets, index=index, **options)))
281
+ display(HTML(to_html(df, name=name, assets=assets, index=index,
282
+ theme=theme, **options)))
@@ -21,6 +21,7 @@
21
21
  --csvgrid-grip-hover: rgba(13, 110, 253, 0.3);
22
22
  --csvgrid-blank: #adb5bd;
23
23
  --csvgrid-filter-active-bg: #e7f1ff;
24
+ --csvgrid-selected-bg: rgba(13, 110, 253, 0.12);
24
25
  --csvgrid-error-fg: #842029;
25
26
  --csvgrid-error-bg: #f8d7da;
26
27
  --csvgrid-error-border: #f5c2c7;
@@ -45,6 +46,7 @@
45
46
  --csvgrid-grip-hover: rgba(110, 168, 254, 0.4);
46
47
  --csvgrid-blank: #6c757d;
47
48
  --csvgrid-filter-active-bg: #2b3a55;
49
+ --csvgrid-selected-bg: rgba(110, 168, 254, 0.22);
48
50
  --csvgrid-error-fg: #ea868f;
49
51
  --csvgrid-error-bg: #2c0b0e;
50
52
  --csvgrid-error-border: #842029;
@@ -62,6 +64,7 @@
62
64
  --csvgrid-grip-hover: rgba(110, 168, 254, 0.4);
63
65
  --csvgrid-blank: #6c757d;
64
66
  --csvgrid-filter-active-bg: #2b3a55;
67
+ --csvgrid-selected-bg: rgba(110, 168, 254, 0.22);
65
68
  --csvgrid-error-fg: #ea868f;
66
69
  --csvgrid-error-bg: #2c0b0e;
67
70
  --csvgrid-error-border: #842029;
@@ -135,6 +138,15 @@
135
138
  }
136
139
  .csvgrid .csvgrid-table tbody tr:hover td { background: var(--csvgrid-row-hover); }
137
140
 
141
+ /* Windowed-render spacer rows: reserve off-screen height only — no padding,
142
+ * border, hover or selection chrome (they're not real rows). */
143
+ .csvgrid .csvgrid-table tbody tr.csvgrid-spacer td,
144
+ .csvgrid .csvgrid-table tbody tr.csvgrid-spacer:hover td {
145
+ padding: 0;
146
+ border: 0;
147
+ background: none;
148
+ }
149
+
138
150
  .csvgrid .csvgrid-table thead th {
139
151
  position: sticky;
140
152
  top: 0;
@@ -208,6 +220,17 @@ body.csvgrid-resizing { cursor: col-resize; user-select: none; }
208
220
  .csvgrid .csvgrid-table .align-right { text-align: right; }
209
221
  .csvgrid .csvgrid-table td.blank { color: var(--csvgrid-blank); }
210
222
 
223
+ /* Clickable rows/cells (opt-in selectable option). The cursor affordance
224
+ * shows only when on; selection rules sit after the hover rule so a selected
225
+ * row stays visibly selected even while hovered. Reads in light and dark. */
226
+ .csvgrid[data-selectable] .csvgrid-table tbody tr { cursor: pointer; }
227
+ .csvgrid .csvgrid-table tbody tr.csvgrid-selected td,
228
+ .csvgrid .csvgrid-table tbody tr.csvgrid-selected-row td { background: var(--csvgrid-selected-bg); }
229
+ .csvgrid .csvgrid-table tbody td.csvgrid-selected {
230
+ outline: 2px solid var(--csvgrid-accent);
231
+ outline-offset: -2px;
232
+ }
233
+
211
234
  /* "Showing first N — show all" note below the table */
212
235
  .csvgrid-capnote {
213
236
  text-align: center;
@@ -0,0 +1,6 @@
1
+ var CsvGrid=(function(){var e=typeof document<`u`&&document.currentScript&&document.currentScript.src||(typeof document<`u`?document.baseURI:``);function t(e){return(e??``).replace(/^\uFEFF/,``).replace(/^(?:[ \t]*(?:\r\n|\n|\r))+/,``)}function n(e){let t=[`,`,` `,`;`,`|`],n=e.split(/\r\n|\n|\r/,20).filter(e=>e.length),i=`,`,a=0;for(let e of t){let t=n.map(t=>r(t,e).length),o=t[0];if(o<2)continue;let s=o*(t.every(e=>e===o)?10:1);s>a&&(a=s,i=e)}return i}function r(e,t){let n=[],r=``,i=!1;for(let a=0;a<e.length;a++){let o=e[a];i?o===`"`?i=!1:r+=o:o===`"`?i=!0:o===t?(n.push(r),r=``):r+=o}return n.push(r),n}function i(e,t){let n=[],r=[],i=``,a=!1,o=0,s=e.length;for(;o<s;){let s=e[o];if(a){if(s===`"`){if(e[o+1]===`"`){i+=`"`,o+=2;continue}a=!1,o++;continue}i+=s,o++;continue}if(s===`"`){a=!0,o++;continue}if(s===t){r.push(i),i=``,o++;continue}if(s===`\r`||s===`
2
+ `){r.push(i),i=``,n.push(r),r=[],s===`\r`&&e[o+1]===`
3
+ `&&o++,o++;continue}i+=s,o++}for((i.length||r.length)&&(r.push(i),n.push(r));n.length&&n[n.length-1].every(e=>e.trim()===``);)n.pop();return n}function a(e){e=e.trim(),e.startsWith(`|`)&&(e=e.slice(1)),e.endsWith(`|`)&&!e.endsWith(`\\|`)&&(e=e.slice(0,-1));let t=[],n=``;for(let r=0;r<e.length;r++){let i=e[r];i===`\\`&&e[r+1]===`|`?(n+=`|`,r++):i===`|`?(t.push(n),n=``):n+=i}return t.push(n),t.map(e=>e.trim())}var o=/^:?-+:?$/;function s(e){let t=e.split(/\r\n|\n|\r/).filter(e=>e.trim()!==``);if(t.length<2||!t[0].includes(`|`))return!1;let n=a(t[1]);return n.length>0&&n.every(e=>o.test(e))}function c(e){let t=e.split(/\r\n|\n|\r/).filter(e=>e.trim()!==``),n=a(t[0]).map((e,t)=>e||`col${t+1}`),r=a(t[1]).map(e=>{let t=e.startsWith(`:`),n=e.endsWith(`:`);return t&&n?`center`:n?`right`:t?`left`:null});for(;r.length<n.length;)r.push(null);return{headers:n,rows:t.slice(2).filter(e=>e.includes(`|`)).map(e=>{let t=a(e).slice(0,n.length);for(;t.length<n.length;)t.push(``);return t}),aligns:r}}var l=/[$£€¥¥]/,u=/^\(?(?:[+-]?[$£€¥¥]?|[$£€¥¥][+-]?)(?:[0-9][0-9,]*(?:\.[0-9]+)?|\.[0-9]+)(?:[eE][+-]?[0-9]+)?%?\)?$/,ee=/^\(?[+-]?(?:inf(?:inity)?|∞)\)?$/i,d=/^(\d{4})-(\d{1,2})-(\d{1,2})(?:[T ](\d{1,2}):(\d{2})(?::(\d{2})(?:\.\d+)?)?Z?)?$/,f=/^(\d{1,4})([\/\-.])(\d{1,2})\2(\d{1,4})$/,p=/^(\d{1,2})[ \-]([A-Za-z]{3,9})\.?,?[ \-](\d{2,4})$/,te=/^([A-Za-z]{3,9})\.?,?[ \-](\d{1,2}),?[ \-](\d{2,4})$/,ne=[`january`,`february`,`march`,`april`,`may`,`june`,`july`,`august`,`september`,`october`,`november`,`december`],re=new Set([`nan`,`na`,`n/a`,`#n/a`,`null`,`none`,`-`,`--`,`.`]);function m(e){return re.has((e??``).trim().toLowerCase())}function h(e){if(e=e.trim(),ee.test(e)){let t=e;return t.startsWith(`(`)&&t.endsWith(`)`)&&(t=`-`+t.slice(1,-1)),{v:t.startsWith(`-`)?-1/0:1/0,dec:0}}if(!u.test(e))return null;let t=!1;e.startsWith(`(`)&&e.endsWith(`)`)&&(t=!0,e=e.slice(1,-1));let n=``,r=l.exec(e);r&&(n=r[0],e=e.replace(l,``));let i=!1;e.endsWith(`%`)&&(i=!0,e=e.slice(0,-1)),e=e.replace(/,/g,``);let a=parseFloat(e);if(!isFinite(a))return null;t&&(a=-a),i&&(a/=100);let o=/^([^eE]*)[eE]([+-]?\d+)$/.exec(e),s=o?o[1]:e,c=o?+o[2]:0,d=s.indexOf(`.`),f=Math.max(0,(d<0?0:s.length-d-1)-c);return i&&(f+=2),{v:a,dec:f,sym:n}}var g=`9007199254740991`;function _(e){return e=e.trim(),e.endsWith(`%`)||(e.startsWith(`(`)&&e.endsWith(`)`)&&(e=e.slice(1,-1)),e=e.replace(/[$£€¥¥,]/g,``).replace(/^[+-]/,``),!/^\d+$/.test(e))?!1:(e=e.replace(/^0+(?=\d)/,``),e.length>16||e.length===16&&e>g)}function v(e){let t=e.toLowerCase(),n=ne.findIndex(e=>e.startsWith(t)||t===`sept`&&e===`september`);return n<0||t.length<3?null:n+1}function y(e){return e=+e,e<100?e<50?2e3+e:1900+e:e}function b(e,t,n,r=0,i=0,a=0,o=!1){let s=new Date(e,t-1,n,r,i,a);return s.getFullYear()!==e||s.getMonth()!==t-1||s.getDate()!==+n?null:{t:s.getTime(),hasTime:o}}function x(e,t=!1){e=e.trim();let n=d.exec(e);if(n){let[,e,t,r,i,a,o]=n;return b(+e,+t,+r,+(i||0),+(a||0),+(o||0),i!==void 0)}if(n=f.exec(e),n){let[,e,,r,i]=n;if(e.length===4&&i.length<=2)return b(+e,+r,+i);if(e.length<=2&&(i.length===4||i.length===2)){let n=y(i);return+e>12&&+r<=12?b(n,+r,+e):+r>12&&+e<=12?b(n,+e,+r):t?b(n,+r,+e):b(n,+e,+r)}return null}if(n=p.exec(e),n){let e=v(n[2]);return e?b(y(n[3]),e,+n[1]):null}if(n=te.exec(e),n){let e=v(n[1]);return e?b(y(n[3]),e,+n[2]):null}return null}function ie(e){let t=f.exec(e.trim());if(!t)return null;let n=t[1],r=t[3],i=t[4];return n.length===4||!(i.length===4||i.length===2)?null:+n>12&&+r<=12?`day`:+r>12&&+n<=12?`month`:+n<=12&&+r<=12?`ambiguous`:null}function S(e){return e.some(e=>{let t=(e??``).trim();return t!==``&&(h(t)!==null||x(t)!==null)})}function C(e){let t=e=>e.type===`date`?`Date`:e.type===`number`?e.format===`year`?`Year`:`Amount`:`Description`,n={},r={};e.forEach(e=>{let r=t(e);n[r]=(n[r]||0)+1}),e.forEach(e=>{let i=t(e);r[i]=(r[i]||0)+1,e.name=n[i]>1?`${i} ${r[i]}`:i})}var w=/\b(year|yr|vintage|cohort)\b/i,T=/\b(amount|amt|balance|bal|price|cost|fee|fees|charge|paid|payment|debit|credit|total|premium|loss|salary|wage|income|expense|revenue|usd|gbp|eur|cad)\b|[$£€]/i,E=/\b(id|no|num|number|account|acct|code|zip|postal|phone|fax|ssn|ein|tin|invoice|inv|ref|reference|sku|upc|isbn|order|customer|cust|member|policy|claim|seq)\b/i,D=/(?<![a-z])(ratio|rate|roe|roa|coc|lr|elr|plr|margin|yield|return|growth|retention|cede|ceded|discount|apr|apy|coupon|util|utilization|share|pct|percent|frequency)(?![a-z])/i;function O(e,t,n,r=!1){if(r)return{format:`float`,dec:2};let i=t.filter(e=>e!==null);if(i.every(e=>Number.isInteger(e))&&i.length)return w.test(e)||i.every(e=>e>=1800&&e<=2100)?{format:`year`,dec:0}:E.test(e)&&!T.test(e)?{format:`plain`,dec:0}:T.test(e)?{format:`float`,dec:2}:{format:`int`,dec:0};let a=0,o=0,s=1/0,c=0;for(let e of i){if(e===0||!Number.isFinite(e))continue;let t=Math.abs(e);a++,t>o&&(o=t),t<s&&(s=t),c+=t}if(!a)return{format:`float`,dec:Math.min(n,6)};if(D.test(e)&&o<=2)return{format:`pct`,dec:Math.max(1,Math.min(4,n-2))};if(T.test(e)||n<=2&&o<1e5)return{format:`float`,dec:2};if(o/s>1e6)return{format:`eng`,dec:0};let l=c/a;return{format:`float`,dec:Math.max(0,Math.min(n,3-Math.floor(Math.log10(l)),6))}}var k={"-9":`n`,"-6":`µ`,"-3":`m`,0:``,3:`k`,6:`M`,9:`G`,12:`T`};function A(e){if(!Number.isFinite(e))return e>0?`inf`:`-inf`;if(e===0)return`0`;let t=Math.abs(e),n=Math.floor(Math.log10(t)/3)*3;n=Math.max(-9,Math.min(12,n));let r=t/10**n;return(e<0?`-`:``)+Number(r.toPrecision(3))+k[n]}function j(e,t){if(e<=t)return Array.from({length:e},(e,t)=>t);let n=Array(t),r=e/t;for(let e=0;e<t;e++)n[e]=Math.floor(e*r);return n}var M=2048,N=/^-?0\d/;function P(e,t){let n=j(t.length,M);return e.map((e,r)=>{let i=!0,a=!0,o=!1,s=!1,c=0;for(let e of n){let n=(t[e][r]??``).trim();if(!(n===``||m(n))&&(c++,i&&(h(n)===null?i=!1:(!o&&N.test(n)&&(o=!0),!s&&_(n)&&(s=!0))),a&&x(n,!1)===null&&(a=!1),o||s||!i&&!a))break}if(c===0||o||s)return s?{name:e,type:`text`,align:`right`,values:null}:{name:e,type:`text`,values:null};if(i){let n=Array(t.length).fill(null),i=0,a=!1;for(let e=0;e<t.length;e++){let o=(t[e][r]??``).trim();if(o===``||m(o))continue;let s=h(o);s&&(n[e]=s.v,s.dec>i&&(i=s.dec),s.sym&&(a=!0))}let o=O(e,n,i,a);return{name:e,type:`number`,format:o.format,dec:o.dec,hasCurrency:a,values:n}}if(a){let n=!1,i=!1,a=!1,o=!1,s=Array(t.length).fill(null);for(let e=0;e<t.length;e++){let c=(t[e][r]??``).trim();if(c===``||m(c))continue;let l=x(c,!1);l&&(s[e]=l.t,i||=l.hasTime);let u=ie(c);u===`day`?(n=!0,o=!0):u===`month`?o=!0:u===`ambiguous`&&(a=!0)}if(n){s=Array(t.length).fill(null);for(let e=0;e<t.length;e++){let n=(t[e][r]??``).trim();if(n===``||m(n))continue;let i=x(n,!0);i&&(s[e]=i.t)}}return{name:e,type:`date`,hasTime:i,ambiguousOrder:a&&!o,values:s}}return{name:e,type:`text`,values:null}})}function F(e,t=null){let r,a,o=null,l;if(s(e)){if({headers:r,rows:a,aligns:o}=c(e),l=t===!1,l&&(a=[r,...a],r=r.map((e,t)=>`col${t+1}`)),!a.length)throw Error(`Markdown table has no data rows.`)}else{let o=i(e,n(e));if(o.length<2)throw Error(`Need a header row and at least one data row.`);l=t===null?S(o[0]):!t,r=l?o[0].map((e,t)=>`col${t+1}`):o[0].map((e,t)=>e.trim()||`col${t+1}`),a=(l?o:o.slice(1)).map(e=>{if(e.length===r.length)return e;let t=e.slice(0,r.length);for(;t.length<r.length;)t.push(``);return t})}let u=P(r,a);return l&&C(u),o&&u.forEach((e,t)=>{o[t]&&(e.align=o[t])}),{headers:u.map(e=>e.name),rows:a,cols:u,headerless:l}}var I=new Map;function L(e){let t=I.get(e);return t||(t=new Intl.NumberFormat(`en-US`,{minimumFractionDigits:e,maximumFractionDigits:e}),I.set(e,t)),t}function R(e){if(e==null||e===``)return null;if(e===`year`||e===`eng`)return{kind:e};let t=/^(,)?(?:\.(\d+))?([fd%es])$/.exec(e);if(!t)throw Error(`CsvGrid: unrecognized format spec '${e}'`);return{kind:t[3],comma:!!t[1],dec:t[2]===void 0?null:+t[2]}}var z=[[0xe8d4a51000,`T`],[1e9,`G`],[1e6,`M`],[1e3,`k`],[1,``],[.001,`m`],[1e-6,`µ`],[1e-9,`n`]];function B(e,t){switch(t.kind){case`year`:return String(e);case`eng`:return A(e);case`d`:{let n=Math.round(e);return t.comma?L(0).format(n):String(n)}case`f`:{let n=t.dec??2;return t.comma?L(n).format(e):e.toFixed(n)}case`%`:{let n=t.dec??0,r=e*100;return(t.comma?L(n).format(r):r.toFixed(n))+`%`}case`e`:return e.toExponential(t.dec??2);case`s`:{if(t.dec===null||t.dec===void 0)return A(e);if(e===0)return 0 .toFixed(t.dec);let n=Math.abs(e);for(let[r,i]of z)if(n>=r)return(e/r).toFixed(t.dec)+i;return(e/1e-9).toFixed(t.dec)+`n`}}}function V(e){return[...e].map(e=>({l:`left`,r:`right`,c:`center`})[e]??null)}function H(e,t,n,r=`auto`){if(e=(e??``).trim(),e===``)return``;if(r===`raw`)return e;if(t.type===`number`){let r=t.values[n];if(r===null)return m(e)?``:e;if(!Number.isFinite(r))return r>0?`inf`:`-inf`;if(t.fmt)return B(r,t.fmt);if(t.format===`year`||t.format===`plain`)return String(r);if(t.format===`eng`)return A(r);if(t.format===`pct`)return L(t.dec).format(r*100)+`%`;let i=L(t.dec).format(r);if(t.hasCurrency){let t=l.exec(e);if(t)return i[0]===`-`?`-`+t[0]+i.slice(1):t[0]+i}return i}if(t.type===`date`){let r=t.values[n];if(r===null)return m(e)?``:e;let i=new Date(r),a=e=>String(e).padStart(2,`0`),o=`${i.getFullYear()}-${a(i.getMonth()+1)}-${a(i.getDate())}`;return t.hasTime&&(o+=` ${a(i.getHours())}:${a(i.getMinutes())}`),o}return e}function U(e,t){let n=e=>(e=(e??``)+``,/[",\r\n]/.test(e)?`"`+e.replace(/"/g,`""`)+`"`:e),r=e=>e.map(n).join(`,`),i=[r(e)];for(let e of t)i.push(r(e));return i.join(`\r
4
+ `)}function W(e,t,n=[]){let r=e=>((e??``)+``).replace(/\|/g,`\\|`).replace(/\s*\r?\n\s*/g,` `),i=e=>e===`right`?`---:`:e===`center`?`:--:`:e===`left`?`:---`:`---`,a=e=>`| `+e.map(r).join(` | `)+` |`,o=`|`+e.map((e,t)=>i(n[t])).join(`|`)+`|`,s=[a(e),o];for(let e of t)s.push(a(e));return s.join(`
5
+ `)}function G(e,t){if(!Array.isArray(e))throw Error(`CsvGrid: records must be an array.`);let n=e=>e==null||typeof e==`number`&&Number.isNaN(e)?``:String(e),r,i;if(e.length&&Array.isArray(e[0])){if(!t)throw Error(`CsvGrid: columns are required with array-of-arrays records.`);r=t.map(String),i=e.map(e=>r.map((t,r)=>n(e[r])))}else r=(t??Object.keys(e[0]??{})).map(String),i=e.map(e=>r.map(t=>n(e[t])));let a=P(r,i);return{headers:r,rows:i,cols:a,headerless:!1}}function K(e){let t=[];for(let n of e.trim().split(/\s+/)){if(!n)continue;let e={kind:`fuzzy`,negate:!1};n.startsWith(`!`)&&(e.negate=!0,e.kind=`exact`,n=n.slice(1)),n.startsWith(`'`)&&(e.kind=`exact`,n=n.slice(1)),n.startsWith(`^`)&&(e.kind=`prefix`,n=n.slice(1)),n.endsWith(`$`)&&(e.kind=e.kind===`prefix`?`exact`:`suffix`,n=n.slice(0,-1)),n&&(e.cs=/[A-Z]/.test(n),e.str=e.cs?n:n.toLowerCase(),t.push(e))}return t}var q=/[\s_\-\/\\.,:;()[\]{}"']/;function J(e,t){let n=t.length,r=e.length;if(r===0)return 0;if(r>n)return-1;let i=0,a=-1;for(let o=0;o<n;o++)if(t[o]===e[i]&&(i++,i===r)){a=o;break}if(a<0)return-1;i=r-1;let o=a;for(let n=a;n>=0&&!(t[n]===e[i]&&(o=n,i--,i<0));n--);let s=100-3*(a-o+1-r)-Math.min(o,20);i=0;let c=!1;for(let n=o;n<=a&&i<r;n++)t[n]===e[i]?((n===0||q.test(t[n-1]))&&(s+=8),c&&(s+=4),c=!0,i++):c=!1;return s}function Y(e,t,n){let r=e.cs?n:t,i,a=0;switch(e.kind){case`exact`:i=r.includes(e.str);break;case`prefix`:i=r.startsWith(e.str);break;case`suffix`:i=r.endsWith(e.str);break;default:{let t=J(e.str,r);i=t>=0,a=t}}return e.negate&&(i=!i),i?a:-1}function ae(e){return e=(e??``).trim(),e===``?``:(e=e.toLowerCase().normalize(`NFKD`).replace(/\p{Diacritic}/gu,``),e.replace(/\d+/g,e=>(e=e.replace(/^0+(?=\d)/,``),``+String.fromCharCode(e.length)+e)))}function oe(e,t,n,r=`equal-risk`){return r===`coverage`?ce(e,t,n):se(e,t,n)}function se(e,t,n){let r=(e,t)=>e.length?e[Math.floor(t*(e.length-1))]:0,i=n=>e.map((e,i)=>Math.max(t[i],r(e,n))),a=e=>e.reduce((e,t)=>e+t,0),o=i(1);if(a(o)<=n)return o;if(a(i(0))>=n)return i(0);let s=0,c=1;for(let e=0;e<32;e++){let e=(s+c)/2;a(i(e))<=n?s=e:c=e}return i(s)}function ce(e,t,n){let r=e.map((e,n)=>Math.max(t[n],e.length?e[e.length-1]:0)),i=e=>e.reduce((e,t)=>e+t,0);if(i(r)<=n)return r;if(i(t)>=n)return t.slice();let a=t.slice(),o=n-i(t),s=[];for(let n=0;n<e.length;n++){let r=le(e[n],t[n]);for(let e=1;e<r.length;e++){let t=r[e].w-r[e-1].w,i=r[e].cells-r[e-1].cells;t>0&&i>0&&s.push({j:n,dw:t,slope:i/t})}}s.sort((e,t)=>t.slope-e.slope);for(let e of s){if(o<=0)break;let t=Math.min(e.dw,o);a[e.j]+=t,o-=t}return a}function le(e,t){let n=e.length,r=0;for(;r<n&&e[r]<=t;)r++;let i=[{w:t,cells:r}];for(;r<n;){let t=e[r];for(;r<n&&e[r]===t;)r++;i.push({w:t,cells:r})}let a=[];for(let e of i){for(;a.length>=2;){let t=a[a.length-2],n=a[a.length-1];if((n.w-t.w)*(e.cells-t.cells)-(n.cells-t.cells)*(e.w-t.w)>=0)a.pop();else break}a.push(e)}return a}function ue(e,t){let n=e.trim();if(!n)return null;if(t.type===`number`||t.type===`date`){let e=t.type===`number`?e=>{let t=h(e);return t?t.v:NaN}:e=>{let t=x(e);return t?t.t:NaN},r=/^(>=|<=|>|<|=)\s*(.+)$/.exec(n);if(r){let n=e(r[2]);if(!isNaN(n)){let e=r[1];return(r,i)=>{let a=t.values[i];if(a===null)return!1;switch(e){case`>`:return a>n;case`>=`:return a>=n;case`<`:return a<n;case`<=`:return a<=n;default:return a===n}}}}if(r=/^(.+?)\.\.(.+)$/.exec(n),r){let n=e(r[1]),i=e(r[2]);if(!isNaN(n)&&!isNaN(i))return(e,r)=>{let a=t.values[r];return a!==null&&a>=n&&a<=i}}}let r=n.toLowerCase();return(e,t)=>e.toLowerCase().includes(r)}function X(e){return e.align?`col-${e.type} align-${e.align}`:`col-${e.type}`}function Z(e){return e.replace(/&/g,`&amp;`).replace(/</g,`&lt;`).replace(/>/g,`&gt;`).replace(/"/g,`&quot;`)}var de=1e6,fe=2048,pe=1e4,Q=10;function $(e,t){let n=document.createElement(e);return t&&(n.className=t),n}return class n{constructor(e,t,n={}){let r=typeof e==`string`?document.querySelector(e):e;if(!r)throw Error(`CsvGrid: target element not found.`);this.root=r,r.csvgrid=this,this.opts={globalSearch:!0,columnFilters:!0,sortable:!0,statusBar:!0,expandButtons:!0,align:null,formats:null,renderCap:2048,eagerCells:262144,worker:!0,headerMode:`auto`,widthMode:`equal-risk`,maxRows:null,height:null,displayMode:`auto`,selectable:!1,selectMode:`row`,hiddenColumns:null,...n},this.displayMode=this.opts.displayMode===`raw`?`raw`:`auto`,this.fileName=``,this.headers=[],this.rows=[],this.cols=[],this.formatted=[],this.searchRaw=null,this.searchLow=null,this.searchReady=!1,this.indexing=null,this.loadGen=0,this.scores=[],this.sortedOrder=null,this.layout=null,this.expandAll=!1,this.manualWidths=new Map,this.guessedHeaders=!1,this.ambiguousDateCols=[],this.view=[],this.sortCol=null,this.sortDir=1,this.globalFilter=``,this.colFilters=[],this.showAll=!1,this.visibleCols=[],this.selected=null,this._rowH=0,this._winStart=0,this._winEnd=0,this._windowed=!1,this._scrollRaf=0,this._worker=void 0,this._pending=new Map,this._buildScaffold(),t&&this.setData(t)}_buildScaffold(){let e=this.opts,t=this.root;if(t.classList.add(`csvgrid`),t.replaceChildren(),this.els={},e.globalSearch||e.expandButtons){let n=$(`div`,`csvgrid-toolbar`);if(e.globalSearch){let e=$(`input`,`csvgrid-search`);e.type=`text`,e.placeholder=`fzf search: term 'exact !not ^pre fix$`,e.title=`Space-separated terms AND together. Fuzzy by default; 'exact, !exclude, ^prefix, suffix$. Uppercase = case-sensitive.`,e.addEventListener(`input`,()=>this.setGlobalFilter(e.value)),e.addEventListener(`keydown`,t=>{t.key===`Escape`&&(t.preventDefault(),e.value=``,e.blur(),this.setGlobalFilter(``))}),n.appendChild(e),this.els.search=e}if(e.expandButtons){let e=$(`button`,`csvgrid-btn`);e.type=`button`,e.textContent=`Expand`,e.title=`Expand all columns to their full natural width (table scrolls horizontally)`,e.addEventListener(`click`,()=>this.expand());let t=$(`button`,`csvgrid-btn`);t.type=`button`,t.textContent=`Contract`,t.title=`Back to fitted widths (equal-risk squeeze); also clears any dragged widths`,t.addEventListener(`click`,()=>this.contract()),n.append(e,t)}t.appendChild(n)}let n=$(`div`,`csvgrid-scroll`);n.addEventListener(`scroll`,()=>this._onScroll());let r=$(`table`,`csvgrid-table`),i=$(`thead`),a=$(`tbody`);r.append(i,a),n.appendChild(r),t.appendChild(n);let o=$(`div`,`csvgrid-capnote csvgrid-hidden`),s=$(`button`,`csvgrid-btn`);s.type=`button`,s.addEventListener(`click`,()=>{this.showAll=!0,this.renderBody(),this.renderStatus()}),o.appendChild(s),t.appendChild(o);let c=$(`div`,`csvgrid-error csvgrid-hidden`);t.appendChild(c);let l=null;e.statusBar===!0?(l=$(`div`,`csvgrid-status`),t.appendChild(l)):e.statusBar&&(l=e.statusBar),Object.assign(this.els,{table:r,head:i,body:a,scroll:n,capNote:o,showAllBtn:s,error:c,status:l}),r.addEventListener(`mouseover`,e=>{let t=e.target.closest(`td, th`);t&&!t.title&&t.scrollWidth>t.clientWidth&&(t.title=t.textContent)}),this.opts.selectable&&(t.dataset.selectable=``,a.addEventListener(`click`,e=>this._onBodyClick(e)))}setData(e){let t=++this.loadGen,n=new Promise((n,r)=>{this._resolveData(e,t).then(({d:e,name:r})=>{t===this.loadGen&&(this._install(e,r),n())},e=>{t===this.loadGen&&(this._showError(e.message||String(e)),r(e))})});return n.catch(()=>{}),n}async _resolveData(e,t){if(!e||typeof e!=`object`)throw Error(`CsvGrid: data must be {csv}, {records[, columns]}, or {url}.`);if(this._headerMode=e.headerMode??this.opts.headerMode,e.url!==void 0){let n=String(e.url),r=e.name??decodeURIComponent(n.split(`/`).pop()||n),i=await fetch(n);if(!i.ok)throw Error(`HTTP ${i.status}`);return{d:await this._parse(await i.text(),t,r),name:r}}if(e.csv!==void 0){let n=e.name??``;return{d:await this._parse(e.csv,t,n),name:n}}if(e.records!==void 0)return{d:G(e.records,e.columns),name:e.name??``};throw Error(`CsvGrid: data must be {csv}, {records[, columns]}, or {url}.`)}_parse(e,n,r){if(e=t(e),!e.trim())throw Error(`No data found.`);let i=this._headerMode===`first-row`?!0:this._headerMode===`headerless`?!1:null,a=this.opts.worker!==!1&&e.length>=de?this._getWorker():null;return a?(this._setStatus(`parsing ${r||`data`} (${(e.length/1e6).toFixed(1)} MB)…`),new Promise((t,r)=>{this._pending.set(n,{resolve:t,reject:r}),a.postMessage({gen:n,text:e,headerOverride:i})})):F(e,i)}_getWorker(){if(this._worker===void 0){this._worker=null;try{let t=typeof this.opts.worker==`string`?new Worker(this.opts.worker):new Worker(new URL(``+new URL(`csv-grid.worker.js`,e).href,``+e),{type:`module`});t.onmessage=e=>{let{gen:t,result:n,error:r}=e.data,i=this._pending.get(t);i&&(this._pending.delete(t),r?i.reject(Error(r)):i.resolve(n))},t.onerror=()=>{let e=[...this._pending.values()];this._pending.clear();for(let t of e)t.reject(Error(`Background parse failed.`))},this._worker=t}catch{}}return this._worker}_install(e,t){let{rows:n,cols:r}=e;if(this.opts.align){let e=V(this.opts.align);r.forEach((t,n)=>{e[n]&&(t.align=e[n])})}this.opts.formats&&r.forEach((e,t)=>{e.fmt=R(this.opts.formats[t])}),this.fileName=t||``,this.guessedHeaders=e.headerless,this.ambiguousDateCols=r.filter(e=>e.ambiguousOrder).map(e=>e.name),this.headers=e.headers,this.rows=n,this.cols=r;let i=Array.isArray(this.opts.hiddenColumns)&&this.opts.hiddenColumns.length?new Set(this.opts.hiddenColumns):null;if(this.visibleCols=r.map((e,t)=>t).filter(e=>!i||!i.has(this.headers[e])),this.selected=null,this.formatted=Array(n.length),this.searchRaw=null,this.searchLow=null,this.searchReady=!1,this.indexing=null,n.length*r.length<=this.opts.eagerCells){for(let e=0;e<n.length;e++)this.getFormattedRow(e);this.searchRaw=this.formatted.map((e,t)=>e.join(` `)+` `+n[t].join(` `)),this.searchLow=this.searchRaw.map(e=>e.toLowerCase()),this.searchReady=!0}this.sortCol=null,this.sortDir=1,this.sortedOrder=null,this.globalFilter=``,this.colFilters=Array(r.length).fill(``),this.manualWidths=new Map,this.showAll=!1,this._rowH=0,this._winStart=this._winEnd=0,this._windowed=!1,this.els.search&&(this.els.search.value=``),this.els.error.classList.add(`csvgrid-hidden`),this.renderHead(),this.layout=this.measureLayout(),this.applyLayout(),this.refresh(),this._applyHeight()}_applyHeight(){let e=this.opts,t=!1;if(e.height)this.els.scroll.style.maxHeight=e.height,t=!0;else if(e.maxRows){let n=this.els.body.querySelector(`tr:not(.csvgrid-spacer)`),r=this._rowH||(n?n.offsetHeight:0);if(r){let n=this.els.head.offsetHeight;this.els.scroll.style.maxHeight=Math.ceil(n+r*e.maxRows+2)+`px`,t=!0}}t&&this.renderBody()}_showError(e){this.els.error.textContent=e,this.els.error.classList.remove(`csvgrid-hidden`)}_setStatus(e){this.els.status&&(this.els.status.textContent=e)}destroy(){this.loadGen++,this._pending.clear(),this._scrollRaf&&=(cancelAnimationFrame(this._scrollRaf),0),this._worker&&=(this._worker.terminate(),null),delete this.root.csvgrid,this.root.classList.remove(`csvgrid`),delete this.root.dataset.selectable,this.root.replaceChildren()}setGlobalFilter(e){this.globalFilter=e,this.refresh()}clearFilters(){this.globalFilter=``,this.colFilters=this.colFilters.map(()=>``),this.els.search&&(this.els.search.value=``),this.renderHead(),this.refresh()}expand(){this.expandAll=!0,this.applyLayout()}contract(){this.expandAll=!1,this.manualWidths.clear(),this.applyLayout()}export({scope:e=`view`,format:t=`csv`,values:n=`raw`}={}){let r=e===`all`?this.rows.map((e,t)=>t):this.view,i=n===`formatted`&&r.length<=this.opts.renderCap,a=r.map(e=>i?this.getFormattedRow(e):this.cols.map((t,n)=>this.rows[e][n]??``));if(t===`md`){let e=this.cols.map(e=>e.align||(e.type===`number`?`right`:e.type===`date`?`center`:`left`));return W(this.headers,a,e)}return U(this.headers,a)}setWidthMode(e){this.opts.widthMode=e===`coverage`?`coverage`:`equal-risk`,this.applyLayout()}setDisplayMode(e){if(e=e===`raw`?`raw`:`auto`,e===this.displayMode||!this.cols.length){this.displayMode=e;return}if(this.displayMode=e,this.formatted=Array(this.rows.length),this.searchRaw=null,this.searchLow=null,this.searchReady=!1,this.indexing=null,this.rows.length*this.cols.length<=this.opts.eagerCells){for(let e=0;e<this.rows.length;e++)this.getFormattedRow(e);this.searchRaw=this.formatted.map((e,t)=>e.join(` `)+` `+this.rows[t].join(` `)),this.searchLow=this.searchRaw.map(e=>e.toLowerCase()),this.searchReady=!0}this.layout=this.measureLayout(),this.applyLayout(),this.refresh()}measureLayout(){let e=(n._canvas||=document.createElement(`canvas`)).getContext(`2d`),t=getComputedStyle(this.els.table),r=`${t.fontSize} ${t.fontFamily}`,i=j(this.rows.length,fe),a=[],o=[];for(let t of this.visibleCols){e.font=`bold ${r}`,o.push(Math.max(50,Math.ceil(e.measureText(this.cols[t].name).width)+14+18)),e.font=r;let n=[];for(let r of i){let i=this.getFormattedRow(r)[t];i!==``&&n.push(Math.ceil(e.measureText(i).width)+18)}n.sort((e,t)=>e-t),a.push(n)}return{arrays:a,floors:o}}startColResize(e,t){e.preventDefault(),e.stopPropagation();let n=this.els.table,r=n.querySelectorAll(`colgroup col`)[t];if(!r)return;let i=e.clientX,a=parseFloat(r.style.width);document.body.classList.add(`csvgrid-resizing`);let o=()=>{let e=0;n.querySelectorAll(`colgroup col`).forEach(t=>{e+=parseFloat(t.style.width)}),n.style.width=e+`px`},s=e=>{let n=Math.max(24,Math.round(a+e.clientX-i));this.manualWidths.set(t,n),r.style.width=n+`px`,o()},c=()=>{document.body.classList.remove(`csvgrid-resizing`),document.removeEventListener(`mousemove`,s),document.removeEventListener(`mouseup`,c)};document.addEventListener(`mousemove`,s),document.addEventListener(`mouseup`,c)}fitColumn(e){let{arrays:t,floors:n}=this.layout,r=Math.max(n[e],t[e].length?t[e][t[e].length-1]:0);this.manualWidths.set(e,r),this.applyLayout()}applyLayout(){if(!this.layout)return;let e=this.els.table,t=this.expandAll?1/0:e.parentElement.clientWidth;if(!t)return;let n=oe(this.layout.arrays,this.layout.floors,t,this.opts.widthMode);for(let[e,t]of this.manualWidths)e<n.length&&(n[e]=t);let r=e.querySelector(`colgroup`);r&&r.remove(),r=document.createElement(`colgroup`);for(let e of n){let t=document.createElement(`col`);t.style.width=e+`px`,r.appendChild(t)}e.prepend(r),e.style.tableLayout=`fixed`,e.style.width=n.reduce((e,t)=>e+t,0)+`px`,this.view.length&&this.renderBody()}getFormattedRow(e){let t=this.formatted[e];return t||(t=this.cols.map((t,n)=>H(this.rows[e][n],t,e,this.displayMode)),this.formatted[e]=t),t}buildSearchIndexChunked(){let e=this.loadGen,t=this.rows.length,n=Array(t),r=Array(t),i=0;this.indexing=0;let a=()=>{if(e!==this.loadGen)return;let o=Math.min(t,i+pe);for(;i<o;i++){let e=this.getFormattedRow(i).join(` `)+` `+this.rows[i].join(` `);n[i]=e,r[i]=e.toLowerCase()}i<t?(this.indexing=i/t,this.renderStatus(),setTimeout(a,0)):(this.searchRaw=n,this.searchLow=r,this.searchReady=!0,this.indexing=null,this.refresh())};a()}_buildSortOrder(){let e=this.rows.length,t=Array(e);for(let n=0;n<e;n++)t[n]=n;let n=this.sortCol;if(n!==null){let r=this.cols[n],i=this.sortDir;if(r.type===`text`){let r=Array(e);for(let t=0;t<e;t++)r[t]=ae(this.rows[t][n]);t.sort((e,t)=>{let n=r[e],a=r[t];return n===``||a===``?n===a?0:n===``?1:-1:n<a?-i:n>a?i:0})}else{let e=r.values;t.sort((t,n)=>{let r=e[t],a=e[n];return r===null||a===null?r===a?0:r===null?1:-1:i*(r-a)})}}this.sortedOrder=t}rebuildView(){let{rows:e,cols:t}=this,n=K(this.globalFilter);n.length&&!this.searchReady&&(this.indexing===null&&this.buildSearchIndexChunked(),n=[]);let r=n.some(e=>e.kind===`fuzzy`&&!e.negate),i=this.colFilters.map((e,n)=>ue(e||``,t[n])),a=i.some(e=>e)||n.length,o=r&&this.sortCol===null;(!this.sortedOrder||this.sortedOrder.length!==e.length)&&this._buildSortOrder();let s=this.sortedOrder;if(!a){this.view=s.slice();return}let c=[];o&&(this.scores=[]);for(let t=0;t<s.length;t++){let r=s[t],a=!0,l=0;for(let e of n){let t=Y(e,this.searchLow[r],this.searchRaw[r]);if(t<0){a=!1;break}l+=t}if(a){for(let t=0;t<i.length;t++)if(i[t]&&!i[t](e[r][t]??``,r)){a=!1;break}}a&&(o&&(this.scores[r]=l),c.push(r))}o&&c.sort((e,t)=>this.scores[t]-this.scores[e]||e-t),this.view=c}renderHead(){let{cols:e}=this,t=this.els.head;t.innerHTML=``;let n=document.createElement(`tr`);if(this.visibleCols.forEach((t,r)=>{let i=e[t],a=document.createElement(`th`);a.className=X(i),this.opts.sortable?(a.innerHTML=`<span class="sort-arrow">${this.sortCol===t?this.sortDir===1?`▲`:`▼`:``}</span>${Z(i.name)}`,a.title=`${i.name} (${i.type}) — click to sort`,a.addEventListener(`click`,()=>this.onSort(t))):(a.innerHTML=`<span class="sort-arrow"></span>${Z(i.name)}`,a.title=`${i.name} (${i.type})`,a.classList.add(`csvgrid-nosort`));let o=document.createElement(`span`);o.className=`col-resizer`,o.title=`Drag to resize — double-click to fit content`,o.addEventListener(`mousedown`,e=>this.startColResize(e,r)),o.addEventListener(`dblclick`,e=>{e.stopPropagation(),this.fitColumn(r)}),o.addEventListener(`click`,e=>e.stopPropagation()),a.appendChild(o),n.appendChild(a)}),t.appendChild(n),!this.opts.columnFilters)return;let r=document.createElement(`tr`);r.className=`filter-row`,this.visibleCols.forEach(t=>{let n=e[t],i=document.createElement(`th`),a=document.createElement(`input`);a.type=`text`,a.className=`csvgrid-filter`,a.placeholder=n.type===`text`?`filter`:`filter, >, .. `,a.value=this.colFilters[t]||``,a.addEventListener(`input`,()=>{this.colFilters[t]=a.value,a.classList.toggle(`active-filter`,a.value.trim()!==``),this.refresh()}),a.addEventListener(`keydown`,e=>{e.key===`Escape`&&(e.preventDefault(),a.value=``,this.colFilters[t]=``,a.classList.remove(`active-filter`),a.blur(),this.refresh())}),i.appendChild(a),r.appendChild(i)}),t.appendChild(r)}renderBody(){let{view:e}=this,t=this.els.body,n=this.els.scroll;if(!e.length){t.innerHTML=``,this._winStart=this._winEnd=0,this._windowed=!1,this._updateCapNote();return}if(!this._rowH){this._renderSlice(0,Math.min(e.length,60),0,0);let n=t.querySelector(`tr:not(.csvgrid-spacer)`);if(this._rowH=n?n.offsetHeight:0,!this._rowH){let t=Math.min(e.length,this.opts.renderCap);this._renderSlice(0,t,0,0),this._winStart=0,this._winEnd=t,this._windowed=!1,this._updateCapNote();return}}let r=this._rowH,i=this._computeWindow();if(this._renderSlice(i.start,i.end,i.start*r,(e.length-i.end)*r),n.scrollHeight-n.clientHeight>1)this._windowed=!0,this._winStart=i.start,this._winEnd=i.end;else{this._windowed=!1;let t=this.showAll?e.length:Math.min(e.length,this.opts.renderCap);this._renderSlice(0,t,0,0),this._winStart=0,this._winEnd=t}this._updateCapNote()}_renderSlice(e,t,n,r){let{cols:i,view:a}=this,o=this.opts.selectable,s=this.visibleCols.length,c=[];n>0&&c.push(`<tr class="csvgrid-spacer"><td colspan="${s}" style="height:${n}px"></td></tr>`);for(let n=e;n<t;n++){let e=a[n],t=this.getFormattedRow(e),r=this.visibleCols.map(e=>{let n=i[e],r=t[e];return r===``?`<td class="${X(n)} blank">·</td>`:`<td class="${X(n)}">${Z(r)}</td>`});c.push(`<tr${o?` data-r="${e}"`:``}>${r.join(``)}</tr>`)}r>0&&c.push(`<tr class="csvgrid-spacer"><td colspan="${s}" style="height:${r}px"></td></tr>`),this.els.body.innerHTML=c.join(``),o&&this._paintSelection()}_computeWindow(){let{view:e,_rowH:t}=this,n=this.els.scroll,r=e.length,i=n.clientHeight||r*t,a=Math.max(1,Math.ceil(i/t)),o=Math.max(0,Math.floor(n.scrollTop/t)-Q);return{start:o,end:Math.min(r,o+a+2*Q)}}_onScroll(){!this._windowed||this._scrollRaf||(this._scrollRaf=requestAnimationFrame(()=>{if(this._scrollRaf=0,!this._windowed)return;let{start:e,end:t}=this._computeWindow();e===this._winStart&&t===this._winEnd||(this._winStart=e,this._winEnd=t,this._renderSlice(e,t,e*this._rowH,(this.view.length-t)*this._rowH))}))}_updateCapNote(){let e=this.els.capNote;if(!e)return;let t=this.view.length;!this._windowed&&this._winEnd<t?(e.classList.remove(`csvgrid-hidden`),this.els.showAllBtn.textContent=`Showing first ${this._winEnd.toLocaleString()} of ${t.toLocaleString()} rows — show all`):e.classList.add(`csvgrid-hidden`)}renderStatus(){if(!this.els.status)return;let e=e=>e.toLocaleString(),t=this.rows.length,n=this.view.length,r=this.fileName?this.fileName+` — `:``;r+=n===t?`${e(t)} rows`:`${e(n)} of ${e(t)} rows`,r+=` × ${this.cols.length} cols`,!this._windowed&&this._winEnd<n&&(r+=` — showing rows 1–${e(this._winEnd)}`),this.guessedHeaders&&(r+=` (headers guessed)`),this.indexing!==null&&(r+=` — indexing search ${Math.round(this.indexing*100)}%`),this.els.status.textContent=r}refresh(){this.rebuildView(),this.renderBody(),this.renderStatus()}onSort(e){this.sortCol===e?this.sortDir===1?this.sortDir=-1:(this.sortCol=null,this.sortDir=1):(this.sortCol=e,this.sortDir=1),this._buildSortOrder(),this.renderHead(),this.refresh()}static forElement(e){let t=typeof e==`string`?document.querySelector(e):e;return t&&t.csvgrid||null}_rawValue(e,t){let n=this.cols[t];if(n&&n.type===`number`){let t=n.values[e];if(t!=null)return t}return this.rows[e][t]??null}_rowDetail(e,t,n){let r=this.getFormattedRow(e),i={},a={};return this.headers.forEach((t,n)=>{i[t]=this._rawValue(e,n),a[t]=r[n]??``}),{name:this.fileName,rowIndex:e,viewIndex:this.view.indexOf(e),column:this.headers[t],columnIndex:t,value:this._rawValue(e,t),valueText:r[t]??``,row:i,rowText:a,originalEvent:n}}_onBodyClick(e){let t=e.target.closest(`td`),n=t&&t.parentElement;if(!t||!n||n.dataset.r===void 0)return;let r=+n.dataset.r,i=[...n.children].indexOf(t),a=this.visibleCols[i];if(a===void 0)return;let o=new CustomEvent(`csvgrid:cellclick`,{detail:this._rowDetail(r,a,e),bubbles:!0,composed:!0,cancelable:!0});this.root.dispatchEvent(o)&&this.opts.selectMode!==`none`&&(this.selected={rowIndex:r,columnIndex:a},this._paintSelection())}_paintSelection(){let e=this.els.body;if(e.querySelectorAll(`.csvgrid-selected, .csvgrid-selected-row`).forEach(e=>e.classList.remove(`csvgrid-selected`,`csvgrid-selected-row`)),!this.selected||this.opts.selectMode===`none`)return;let t=e.querySelector(`tr[data-r="${this.selected.rowIndex}"]`);if(t)if(this.opts.selectMode===`cell`){t.classList.add(`csvgrid-selected-row`);let e=t.children[this.visibleCols.indexOf(this.selected.columnIndex)];e&&e.classList.add(`csvgrid-selected`)}else t.classList.add(`csvgrid-selected`)}getSelection(){return this.selected?this._rowDetail(this.selected.rowIndex,this.selected.columnIndex,null):null}clearSelection(){this.selected=null,this.opts.selectable&&this._paintSelection()}selectRow(e){if(!this.opts.selectable)return;this.selected={rowIndex:e,columnIndex:this.selected?this.selected.columnIndex:this.visibleCols[0]};let t=this.view.indexOf(e);if(t<0){this._paintSelection();return}if(this._windowed&&this._rowH){let e=this._rowH,n=this.els.scroll,r=t*e;(r<n.scrollTop||r+e>n.scrollTop+n.clientHeight)&&(n.scrollTop=Math.max(0,r-e*Q)),this.renderBody();return}this._paintSelection();let n=this.els.body.querySelector(`tr[data-r="${e}"]`);n&&n.scrollIntoView({block:`nearest`})}}})();
6
+ //# sourceMappingURL=csv-grid.iife.js.map
@@ -12,7 +12,7 @@ resolution-markers = [
12
12
 
13
13
  [[package]]
14
14
  name = "csv-grid"
15
- version = "3.0.7"
15
+ version = "3.5.0"
16
16
  source = { editable = "." }
17
17
  dependencies = [
18
18
  { name = "pandas" },
@@ -1,6 +0,0 @@
1
- var CsvGrid=(function(){var e=typeof document<`u`&&document.currentScript&&document.currentScript.src||(typeof document<`u`?document.baseURI:``);function t(e){return(e??``).replace(/^\uFEFF/,``).replace(/^(?:[ \t]*(?:\r\n|\n|\r))+/,``)}function n(e){let t=[`,`,` `,`;`,`|`],n=e.split(/\r\n|\n|\r/,20).filter(e=>e.length),i=`,`,a=0;for(let e of t){let t=n.map(t=>r(t,e).length),o=t[0];if(o<2)continue;let s=o*(t.every(e=>e===o)?10:1);s>a&&(a=s,i=e)}return i}function r(e,t){let n=[],r=``,i=!1;for(let a=0;a<e.length;a++){let o=e[a];i?o===`"`?i=!1:r+=o:o===`"`?i=!0:o===t?(n.push(r),r=``):r+=o}return n.push(r),n}function i(e,t){let n=[],r=[],i=``,a=!1,o=0,s=e.length;for(;o<s;){let s=e[o];if(a){if(s===`"`){if(e[o+1]===`"`){i+=`"`,o+=2;continue}a=!1,o++;continue}i+=s,o++;continue}if(s===`"`){a=!0,o++;continue}if(s===t){r.push(i),i=``,o++;continue}if(s===`\r`||s===`
2
- `){r.push(i),i=``,n.push(r),r=[],s===`\r`&&e[o+1]===`
3
- `&&o++,o++;continue}i+=s,o++}for((i.length||r.length)&&(r.push(i),n.push(r));n.length&&n[n.length-1].every(e=>e.trim()===``);)n.pop();return n}function a(e){e=e.trim(),e.startsWith(`|`)&&(e=e.slice(1)),e.endsWith(`|`)&&!e.endsWith(`\\|`)&&(e=e.slice(0,-1));let t=[],n=``;for(let r=0;r<e.length;r++){let i=e[r];i===`\\`&&e[r+1]===`|`?(n+=`|`,r++):i===`|`?(t.push(n),n=``):n+=i}return t.push(n),t.map(e=>e.trim())}var o=/^:?-+:?$/;function s(e){let t=e.split(/\r\n|\n|\r/).filter(e=>e.trim()!==``);if(t.length<2||!t[0].includes(`|`))return!1;let n=a(t[1]);return n.length>0&&n.every(e=>o.test(e))}function c(e){let t=e.split(/\r\n|\n|\r/).filter(e=>e.trim()!==``),n=a(t[0]).map((e,t)=>e||`col${t+1}`),r=a(t[1]).map(e=>{let t=e.startsWith(`:`),n=e.endsWith(`:`);return t&&n?`center`:n?`right`:t?`left`:null});for(;r.length<n.length;)r.push(null);return{headers:n,rows:t.slice(2).filter(e=>e.includes(`|`)).map(e=>{let t=a(e).slice(0,n.length);for(;t.length<n.length;)t.push(``);return t}),aligns:r}}var l=/^\(?\$?-?(?:[0-9][0-9,]*(?:\.[0-9]+)?|\.[0-9]+)(?:[eE][+-]?[0-9]+)?%?\)?$/,u=/^(\d{4})-(\d{1,2})-(\d{1,2})(?:[T ](\d{1,2}):(\d{2})(?::(\d{2})(?:\.\d+)?)?Z?)?$/,d=/^(\d{1,4})([\/\-.])(\d{1,2})\2(\d{1,4})$/,f=/^(\d{1,2})[ \-]([A-Za-z]{3,9})\.?,?[ \-](\d{2,4})$/,p=/^([A-Za-z]{3,9})\.?,?[ \-](\d{1,2}),?[ \-](\d{2,4})$/,m=[`january`,`february`,`march`,`april`,`may`,`june`,`july`,`august`,`september`,`october`,`november`,`december`],h=new Set([`nan`,`na`,`n/a`,`#n/a`,`null`,`none`,`-`,`--`,`.`]);function g(e){return h.has((e??``).trim().toLowerCase())}function _(e){if(e=e.trim(),!l.test(e))return null;let t=!1;e.startsWith(`(`)&&e.endsWith(`)`)&&(t=!0,e=e.slice(1,-1));let n=!1;e.endsWith(`%`)&&(n=!0,e=e.slice(0,-1)),e=e.replace(/[$,]/g,``);let r=parseFloat(e);if(!isFinite(r))return null;t&&(r=-r),n&&(r/=100);let i=/^([^eE]*)[eE]([+-]?\d+)$/.exec(e),a=i?i[1]:e,o=i?+i[2]:0,s=a.indexOf(`.`),c=Math.max(0,(s<0?0:a.length-s-1)-o);return n&&(c+=2),{v:r,dec:c}}var v=`9007199254740991`;function y(e){return e=e.trim(),e.endsWith(`%`)||(e.startsWith(`(`)&&e.endsWith(`)`)&&(e=e.slice(1,-1)),e=e.replace(/[$,]/g,``).replace(/^[+-]/,``),!/^\d+$/.test(e))?!1:(e=e.replace(/^0+(?=\d)/,``),e.length>16||e.length===16&&e>v)}function b(e){let t=e.toLowerCase(),n=m.findIndex(e=>e.startsWith(t)||t===`sept`&&e===`september`);return n<0||t.length<3?null:n+1}function x(e){return e=+e,e<100?e<50?2e3+e:1900+e:e}function S(e,t,n,r=0,i=0,a=0,o=!1){let s=new Date(e,t-1,n,r,i,a);return s.getFullYear()!==e||s.getMonth()!==t-1||s.getDate()!==+n?null:{t:s.getTime(),hasTime:o}}function C(e,t=!1){e=e.trim();let n=u.exec(e);if(n){let[,e,t,r,i,a,o]=n;return S(+e,+t,+r,+(i||0),+(a||0),+(o||0),i!==void 0)}if(n=d.exec(e),n){let[,e,,r,i]=n;if(e.length===4&&i.length<=2)return S(+e,+r,+i);if(e.length<=2&&(i.length===4||i.length===2)){let n=x(i);return+e>12&&+r<=12?S(n,+r,+e):+r>12&&+e<=12?S(n,+e,+r):t?S(n,+r,+e):S(n,+e,+r)}return null}if(n=f.exec(e),n){let e=b(n[2]);return e?S(x(n[3]),e,+n[1]):null}if(n=p.exec(e),n){let e=b(n[1]);return e?S(x(n[3]),e,+n[2]):null}return null}function ee(e){let t=d.exec(e.trim());if(!t)return null;let n=t[1],r=t[3],i=t[4];return n.length===4||!(i.length===4||i.length===2)?null:+n>12&&+r<=12?`day`:+r>12&&+n<=12?`month`:+n<=12&&+r<=12?`ambiguous`:null}function te(e){return e.some(e=>{let t=(e??``).trim();return t!==``&&(_(t)!==null||C(t)!==null)})}function ne(e){let t=e=>e.type===`date`?`Date`:e.type===`number`?e.format===`year`?`Year`:`Amount`:`Description`,n={},r={};e.forEach(e=>{let r=t(e);n[r]=(n[r]||0)+1}),e.forEach(e=>{let i=t(e);r[i]=(r[i]||0)+1,e.name=n[i]>1?`${i} ${r[i]}`:i})}var re=/\b(year|yr|vintage|cohort)\b/i,w=/\b(amount|amt|balance|bal|price|cost|fee|fees|charge|paid|payment|debit|credit|total|premium|loss|salary|wage|income|expense|revenue|usd|gbp|eur|cad)\b|[$£€]/i,T=/\b(id|no|num|number|account|acct|code|zip|postal|phone|fax|ssn|ein|tin|invoice|inv|ref|reference|sku|upc|isbn|order|customer|cust|member|policy|claim|seq)\b/i,E=/(?<![a-z])(ratio|rate|roe|roa|coc|lr|elr|plr|margin|yield|return|growth|retention|cede|ceded|discount|apr|apy|coupon|util|utilization|share|pct|percent|frequency)(?![a-z])/i;function D(e,t,n){let r=t.filter(e=>e!==null);if(r.every(e=>Number.isInteger(e))&&r.length)return re.test(e)||r.every(e=>e>=1800&&e<=2100)?{format:`year`,dec:0}:T.test(e)&&!w.test(e)?{format:`plain`,dec:0}:w.test(e)?{format:`float`,dec:2}:{format:`int`,dec:0};let i=0,a=0,o=1/0,s=0;for(let e of r){if(e===0)continue;let t=Math.abs(e);i++,t>a&&(a=t),t<o&&(o=t),s+=t}if(!i)return{format:`float`,dec:Math.min(n,6)};if(E.test(e)&&a<=2)return{format:`pct`,dec:Math.max(1,Math.min(4,n-2))};if(w.test(e)||n<=2&&a<1e5)return{format:`float`,dec:2};if(a/o>1e6)return{format:`eng`,dec:0};let c=s/i;return{format:`float`,dec:Math.max(0,Math.min(n,3-Math.floor(Math.log10(c)),6))}}var O={"-9":`n`,"-6":`µ`,"-3":`m`,0:``,3:`k`,6:`M`,9:`G`,12:`T`};function k(e){if(e===0)return`0`;let t=Math.abs(e),n=Math.floor(Math.log10(t)/3)*3;n=Math.max(-9,Math.min(12,n));let r=t/10**n;return(e<0?`-`:``)+Number(r.toPrecision(3))+O[n]}function A(e,t){if(e<=t)return Array.from({length:e},(e,t)=>t);let n=Array(t),r=e/t;for(let e=0;e<t;e++)n[e]=Math.floor(e*r);return n}var j=2048,M=/^-?0\d/;function N(e,t){let n=A(t.length,j);return e.map((e,r)=>{let i=!0,a=!0,o=!1,s=!1,c=0;for(let e of n){let n=(t[e][r]??``).trim();if(!(n===``||g(n))&&(c++,i&&(_(n)===null?i=!1:(!o&&M.test(n)&&(o=!0),!s&&y(n)&&(s=!0))),a&&C(n,!1)===null&&(a=!1),o||s||!i&&!a))break}if(c===0||o||s)return s?{name:e,type:`text`,align:`right`,values:null}:{name:e,type:`text`,values:null};if(i){let n=Array(t.length).fill(null),i=0;for(let e=0;e<t.length;e++){let a=(t[e][r]??``).trim();if(a===``||g(a))continue;let o=_(a);o&&(n[e]=o.v,o.dec>i&&(i=o.dec))}let a=D(e,n,i);return{name:e,type:`number`,format:a.format,dec:a.dec,values:n}}if(a){let n=!1,i=!1,a=!1,o=!1,s=Array(t.length).fill(null);for(let e=0;e<t.length;e++){let c=(t[e][r]??``).trim();if(c===``||g(c))continue;let l=C(c,!1);l&&(s[e]=l.t,i||=l.hasTime);let u=ee(c);u===`day`?(n=!0,o=!0):u===`month`?o=!0:u===`ambiguous`&&(a=!0)}if(n){s=Array(t.length).fill(null);for(let e=0;e<t.length;e++){let n=(t[e][r]??``).trim();if(n===``||g(n))continue;let i=C(n,!0);i&&(s[e]=i.t)}}return{name:e,type:`date`,hasTime:i,ambiguousOrder:a&&!o,values:s}}return{name:e,type:`text`,values:null}})}function P(e,t=null){let r,a,o=null,l;if(s(e)){if({headers:r,rows:a,aligns:o}=c(e),l=t===!1,l&&(a=[r,...a],r=r.map((e,t)=>`col${t+1}`)),!a.length)throw Error(`Markdown table has no data rows.`)}else{let o=i(e,n(e));if(o.length<2)throw Error(`Need a header row and at least one data row.`);l=t===null?te(o[0]):!t,r=l?o[0].map((e,t)=>`col${t+1}`):o[0].map((e,t)=>e.trim()||`col${t+1}`),a=(l?o:o.slice(1)).map(e=>{if(e.length===r.length)return e;let t=e.slice(0,r.length);for(;t.length<r.length;)t.push(``);return t})}let u=N(r,a);return l&&ne(u),o&&u.forEach((e,t)=>{o[t]&&(e.align=o[t])}),{headers:u.map(e=>e.name),rows:a,cols:u,headerless:l}}var F=new Map;function I(e){let t=F.get(e);return t||(t=new Intl.NumberFormat(`en-US`,{minimumFractionDigits:e,maximumFractionDigits:e}),F.set(e,t)),t}function L(e){if(e==null||e===``)return null;if(e===`year`||e===`eng`)return{kind:e};let t=/^(,)?(?:\.(\d+))?([fd%es])$/.exec(e);if(!t)throw Error(`CsvGrid: unrecognized format spec '${e}'`);return{kind:t[3],comma:!!t[1],dec:t[2]===void 0?null:+t[2]}}var R=[[0xe8d4a51000,`T`],[1e9,`G`],[1e6,`M`],[1e3,`k`],[1,``],[.001,`m`],[1e-6,`µ`],[1e-9,`n`]];function z(e,t){switch(t.kind){case`year`:return String(e);case`eng`:return k(e);case`d`:{let n=Math.round(e);return t.comma?I(0).format(n):String(n)}case`f`:{let n=t.dec??2;return t.comma?I(n).format(e):e.toFixed(n)}case`%`:{let n=t.dec??0,r=e*100;return(t.comma?I(n).format(r):r.toFixed(n))+`%`}case`e`:return e.toExponential(t.dec??2);case`s`:{if(t.dec===null||t.dec===void 0)return k(e);if(e===0)return 0 .toFixed(t.dec);let n=Math.abs(e);for(let[r,i]of R)if(n>=r)return(e/r).toFixed(t.dec)+i;return(e/1e-9).toFixed(t.dec)+`n`}}}function ie(e){return[...e].map(e=>({l:`left`,r:`right`,c:`center`})[e]??null)}function B(e,t,n,r=`auto`){if(e=(e??``).trim(),e===``)return``;if(r===`raw`)return e;if(t.type===`number`){let r=t.values[n];return r===null?g(e)?``:e:t.fmt?z(r,t.fmt):t.format===`year`||t.format===`plain`?String(r):t.format===`eng`?k(r):t.format===`pct`?I(t.dec).format(r*100)+`%`:I(t.dec).format(r)}if(t.type===`date`){let r=t.values[n];if(r===null)return g(e)?``:e;let i=new Date(r),a=e=>String(e).padStart(2,`0`),o=`${i.getFullYear()}-${a(i.getMonth()+1)}-${a(i.getDate())}`;return t.hasTime&&(o+=` ${a(i.getHours())}:${a(i.getMinutes())}`),o}return e}function V(e,t){let n=e=>(e=(e??``)+``,/[",\r\n]/.test(e)?`"`+e.replace(/"/g,`""`)+`"`:e),r=e=>e.map(n).join(`,`),i=[r(e)];for(let e of t)i.push(r(e));return i.join(`\r
4
- `)}function H(e,t,n=[]){let r=e=>((e??``)+``).replace(/\|/g,`\\|`).replace(/\s*\r?\n\s*/g,` `),i=e=>e===`right`?`---:`:e===`center`?`:--:`:e===`left`?`:---`:`---`,a=e=>`| `+e.map(r).join(` | `)+` |`,o=`|`+e.map((e,t)=>i(n[t])).join(`|`)+`|`,s=[a(e),o];for(let e of t)s.push(a(e));return s.join(`
5
- `)}function U(e,t){if(!Array.isArray(e))throw Error(`CsvGrid: records must be an array.`);let n=e=>e==null||typeof e==`number`&&Number.isNaN(e)?``:String(e),r,i;if(e.length&&Array.isArray(e[0])){if(!t)throw Error(`CsvGrid: columns are required with array-of-arrays records.`);r=t.map(String),i=e.map(e=>r.map((t,r)=>n(e[r])))}else r=(t??Object.keys(e[0]??{})).map(String),i=e.map(e=>r.map(t=>n(e[t])));let a=N(r,i);return{headers:r,rows:i,cols:a,headerless:!1}}function W(e){let t=[];for(let n of e.trim().split(/\s+/)){if(!n)continue;let e={kind:`fuzzy`,negate:!1};n.startsWith(`!`)&&(e.negate=!0,e.kind=`exact`,n=n.slice(1)),n.startsWith(`'`)&&(e.kind=`exact`,n=n.slice(1)),n.startsWith(`^`)&&(e.kind=`prefix`,n=n.slice(1)),n.endsWith(`$`)&&(e.kind=e.kind===`prefix`?`exact`:`suffix`,n=n.slice(0,-1)),n&&(e.cs=/[A-Z]/.test(n),e.str=e.cs?n:n.toLowerCase(),t.push(e))}return t}var G=/[\s_\-\/\\.,:;()[\]{}"']/;function K(e,t){let n=t.length,r=e.length;if(r===0)return 0;if(r>n)return-1;let i=0,a=-1;for(let o=0;o<n;o++)if(t[o]===e[i]&&(i++,i===r)){a=o;break}if(a<0)return-1;i=r-1;let o=a;for(let n=a;n>=0&&!(t[n]===e[i]&&(o=n,i--,i<0));n--);let s=100-3*(a-o+1-r)-Math.min(o,20);i=0;let c=!1;for(let n=o;n<=a&&i<r;n++)t[n]===e[i]?((n===0||G.test(t[n-1]))&&(s+=8),c&&(s+=4),c=!0,i++):c=!1;return s}function q(e,t,n){let r=e.cs?n:t,i,a=0;switch(e.kind){case`exact`:i=r.includes(e.str);break;case`prefix`:i=r.startsWith(e.str);break;case`suffix`:i=r.endsWith(e.str);break;default:{let t=K(e.str,r);i=t>=0,a=t}}return e.negate&&(i=!i),i?a:-1}function J(e,t,n,r=`equal-risk`){return r===`coverage`?ae(e,t,n):Y(e,t,n)}function Y(e,t,n){let r=(e,t)=>e.length?e[Math.floor(t*(e.length-1))]:0,i=n=>e.map((e,i)=>Math.max(t[i],r(e,n))),a=e=>e.reduce((e,t)=>e+t,0),o=i(1);if(a(o)<=n)return o;if(a(i(0))>=n)return i(0);let s=0,c=1;for(let e=0;e<32;e++){let e=(s+c)/2;a(i(e))<=n?s=e:c=e}return i(s)}function ae(e,t,n){let r=e.map((e,n)=>Math.max(t[n],e.length?e[e.length-1]:0)),i=e=>e.reduce((e,t)=>e+t,0);if(i(r)<=n)return r;if(i(t)>=n)return t.slice();let a=t.slice(),o=n-i(t),s=[];for(let n=0;n<e.length;n++){let r=oe(e[n],t[n]);for(let e=1;e<r.length;e++){let t=r[e].w-r[e-1].w,i=r[e].cells-r[e-1].cells;t>0&&i>0&&s.push({j:n,dw:t,slope:i/t})}}s.sort((e,t)=>t.slope-e.slope);for(let e of s){if(o<=0)break;let t=Math.min(e.dw,o);a[e.j]+=t,o-=t}return a}function oe(e,t){let n=e.length,r=0;for(;r<n&&e[r]<=t;)r++;let i=[{w:t,cells:r}];for(;r<n;){let t=e[r];for(;r<n&&e[r]===t;)r++;i.push({w:t,cells:r})}let a=[];for(let e of i){for(;a.length>=2;){let t=a[a.length-2],n=a[a.length-1];if((n.w-t.w)*(e.cells-t.cells)-(n.cells-t.cells)*(e.w-t.w)>=0)a.pop();else break}a.push(e)}return a}function se(e,t){let n=e.trim();if(!n)return null;if(t.type===`number`||t.type===`date`){let e=t.type===`number`?e=>{let t=_(e);return t?t.v:NaN}:e=>{let t=C(e);return t?t.t:NaN},r=/^(>=|<=|>|<|=)\s*(.+)$/.exec(n);if(r){let n=e(r[2]);if(!isNaN(n)){let e=r[1];return(r,i)=>{let a=t.values[i];if(a===null)return!1;switch(e){case`>`:return a>n;case`>=`:return a>=n;case`<`:return a<n;case`<=`:return a<=n;default:return a===n}}}}if(r=/^(.+?)\.\.(.+)$/.exec(n),r){let n=e(r[1]),i=e(r[2]);if(!isNaN(n)&&!isNaN(i))return(e,r)=>{let a=t.values[r];return a!==null&&a>=n&&a<=i}}}let r=n.toLowerCase();return(e,t)=>e.toLowerCase().includes(r)}function X(e){return e.align?`col-${e.type} align-${e.align}`:`col-${e.type}`}function Z(e){return e.replace(/&/g,`&amp;`).replace(/</g,`&lt;`).replace(/>/g,`&gt;`).replace(/"/g,`&quot;`)}var Q=1e6,ce=2048,le=1e4;function $(e,t){let n=document.createElement(e);return t&&(n.className=t),n}return class n{constructor(e,t,n={}){let r=typeof e==`string`?document.querySelector(e):e;if(!r)throw Error(`CsvGrid: target element not found.`);this.root=r,this.opts={globalSearch:!0,columnFilters:!0,sortable:!0,statusBar:!0,expandButtons:!0,align:null,formats:null,renderCap:2048,eagerCells:262144,worker:!0,headerMode:`auto`,widthMode:`equal-risk`,maxRows:null,height:null,displayMode:`auto`,...n},this.displayMode=this.opts.displayMode===`raw`?`raw`:`auto`,this.fileName=``,this.headers=[],this.rows=[],this.cols=[],this.formatted=[],this.searchRaw=null,this.searchLow=null,this.searchReady=!1,this.indexing=null,this.loadGen=0,this.scores=[],this.layout=null,this.expandAll=!1,this.manualWidths=new Map,this.guessedHeaders=!1,this.ambiguousDateCols=[],this.view=[],this.sortCol=null,this.sortDir=1,this.globalFilter=``,this.colFilters=[],this.showAll=!1,this._worker=void 0,this._pending=new Map,this._buildScaffold(),t&&this.setData(t)}_buildScaffold(){let e=this.opts,t=this.root;if(t.classList.add(`csvgrid`),t.replaceChildren(),this.els={},e.globalSearch||e.expandButtons){let n=$(`div`,`csvgrid-toolbar`);if(e.globalSearch){let e=$(`input`,`csvgrid-search`);e.type=`text`,e.placeholder=`fzf search: term 'exact !not ^pre fix$`,e.title=`Space-separated terms AND together. Fuzzy by default; 'exact, !exclude, ^prefix, suffix$. Uppercase = case-sensitive.`,e.addEventListener(`input`,()=>this.setGlobalFilter(e.value)),e.addEventListener(`keydown`,t=>{t.key===`Escape`&&(t.preventDefault(),e.value=``,e.blur(),this.setGlobalFilter(``))}),n.appendChild(e),this.els.search=e}if(e.expandButtons){let e=$(`button`,`csvgrid-btn`);e.type=`button`,e.textContent=`Expand`,e.title=`Expand all columns to their full natural width (table scrolls horizontally)`,e.addEventListener(`click`,()=>this.expand());let t=$(`button`,`csvgrid-btn`);t.type=`button`,t.textContent=`Contract`,t.title=`Back to fitted widths (equal-risk squeeze); also clears any dragged widths`,t.addEventListener(`click`,()=>this.contract()),n.append(e,t)}t.appendChild(n)}let n=$(`div`,`csvgrid-scroll`),r=$(`table`,`csvgrid-table`),i=$(`thead`),a=$(`tbody`);r.append(i,a),n.appendChild(r),t.appendChild(n);let o=$(`div`,`csvgrid-capnote csvgrid-hidden`),s=$(`button`,`csvgrid-btn`);s.type=`button`,s.addEventListener(`click`,()=>{this.showAll=!0,this.renderBody(),this.renderStatus()}),o.appendChild(s),t.appendChild(o);let c=$(`div`,`csvgrid-error csvgrid-hidden`);t.appendChild(c);let l=null;e.statusBar===!0?(l=$(`div`,`csvgrid-status`),t.appendChild(l)):e.statusBar&&(l=e.statusBar),Object.assign(this.els,{table:r,head:i,body:a,scroll:n,capNote:o,showAllBtn:s,error:c,status:l}),r.addEventListener(`mouseover`,e=>{let t=e.target.closest(`td, th`);t&&!t.title&&t.scrollWidth>t.clientWidth&&(t.title=t.textContent)})}setData(e){let t=++this.loadGen,n=new Promise((n,r)=>{this._resolveData(e,t).then(({d:e,name:r})=>{t===this.loadGen&&(this._install(e,r),n())},e=>{t===this.loadGen&&(this._showError(e.message||String(e)),r(e))})});return n.catch(()=>{}),n}async _resolveData(e,t){if(!e||typeof e!=`object`)throw Error(`CsvGrid: data must be {csv}, {records[, columns]}, or {url}.`);if(this._headerMode=e.headerMode??this.opts.headerMode,e.url!==void 0){let n=String(e.url),r=e.name??decodeURIComponent(n.split(`/`).pop()||n),i=await fetch(n);if(!i.ok)throw Error(`HTTP ${i.status}`);return{d:await this._parse(await i.text(),t,r),name:r}}if(e.csv!==void 0){let n=e.name??``;return{d:await this._parse(e.csv,t,n),name:n}}if(e.records!==void 0)return{d:U(e.records,e.columns),name:e.name??``};throw Error(`CsvGrid: data must be {csv}, {records[, columns]}, or {url}.`)}_parse(e,n,r){if(e=t(e),!e.trim())throw Error(`No data found.`);let i=this._headerMode===`first-row`?!0:this._headerMode===`headerless`?!1:null,a=this.opts.worker!==!1&&e.length>=Q?this._getWorker():null;return a?(this._setStatus(`parsing ${r||`data`} (${(e.length/1e6).toFixed(1)} MB)…`),new Promise((t,r)=>{this._pending.set(n,{resolve:t,reject:r}),a.postMessage({gen:n,text:e,headerOverride:i})})):P(e,i)}_getWorker(){if(this._worker===void 0){this._worker=null;try{let t=typeof this.opts.worker==`string`?new Worker(this.opts.worker):new Worker(new URL(``+new URL(`csv-grid.worker.js`,e).href,``+e),{type:`module`});t.onmessage=e=>{let{gen:t,result:n,error:r}=e.data,i=this._pending.get(t);i&&(this._pending.delete(t),r?i.reject(Error(r)):i.resolve(n))},t.onerror=()=>{let e=[...this._pending.values()];this._pending.clear();for(let t of e)t.reject(Error(`Background parse failed.`))},this._worker=t}catch{}}return this._worker}_install(e,t){let{rows:n,cols:r}=e;if(this.opts.align){let e=ie(this.opts.align);r.forEach((t,n)=>{e[n]&&(t.align=e[n])})}if(this.opts.formats&&r.forEach((e,t)=>{e.fmt=L(this.opts.formats[t])}),this.fileName=t||``,this.guessedHeaders=e.headerless,this.ambiguousDateCols=r.filter(e=>e.ambiguousOrder).map(e=>e.name),this.headers=e.headers,this.rows=n,this.cols=r,this.formatted=Array(n.length),this.searchRaw=null,this.searchLow=null,this.searchReady=!1,this.indexing=null,n.length*r.length<=this.opts.eagerCells){for(let e=0;e<n.length;e++)this.getFormattedRow(e);this.searchRaw=this.formatted.map((e,t)=>e.join(` `)+` `+n[t].join(` `)),this.searchLow=this.searchRaw.map(e=>e.toLowerCase()),this.searchReady=!0}this.sortCol=null,this.sortDir=1,this.globalFilter=``,this.colFilters=Array(r.length).fill(``),this.manualWidths=new Map,this.showAll=!1,this.els.search&&(this.els.search.value=``),this.els.error.classList.add(`csvgrid-hidden`),this.renderHead(),this.layout=this.measureLayout(),this.applyLayout(),this.refresh(),this._applyHeight()}_applyHeight(){let e=this.opts;if(e.height){this.els.scroll.style.maxHeight=e.height;return}if(e.maxRows&&this.els.body.rows.length){let t=this.els.head.offsetHeight,n=this.els.body.rows[0].offsetHeight;this.els.scroll.style.maxHeight=Math.ceil(t+n*e.maxRows+2)+`px`}}_showError(e){this.els.error.textContent=e,this.els.error.classList.remove(`csvgrid-hidden`)}_setStatus(e){this.els.status&&(this.els.status.textContent=e)}destroy(){this.loadGen++,this._pending.clear(),this._worker&&=(this._worker.terminate(),null),this.root.classList.remove(`csvgrid`),this.root.replaceChildren()}setGlobalFilter(e){this.globalFilter=e,this.refresh()}clearFilters(){this.globalFilter=``,this.colFilters=this.colFilters.map(()=>``),this.els.search&&(this.els.search.value=``),this.renderHead(),this.refresh()}expand(){this.expandAll=!0,this.applyLayout()}contract(){this.expandAll=!1,this.manualWidths.clear(),this.applyLayout()}export({scope:e=`view`,format:t=`csv`,values:n=`raw`}={}){let r=e===`all`?this.rows.map((e,t)=>t):this.view,i=n===`formatted`&&r.length<=this.opts.renderCap,a=r.map(e=>i?this.getFormattedRow(e):this.cols.map((t,n)=>this.rows[e][n]??``));if(t===`md`){let e=this.cols.map(e=>e.align||(e.type===`number`?`right`:e.type===`date`?`center`:`left`));return H(this.headers,a,e)}return V(this.headers,a)}setWidthMode(e){this.opts.widthMode=e===`coverage`?`coverage`:`equal-risk`,this.applyLayout()}setDisplayMode(e){if(e=e===`raw`?`raw`:`auto`,e===this.displayMode||!this.cols.length){this.displayMode=e;return}if(this.displayMode=e,this.formatted=Array(this.rows.length),this.searchRaw=null,this.searchLow=null,this.searchReady=!1,this.indexing=null,this.rows.length*this.cols.length<=this.opts.eagerCells){for(let e=0;e<this.rows.length;e++)this.getFormattedRow(e);this.searchRaw=this.formatted.map((e,t)=>e.join(` `)+` `+this.rows[t].join(` `)),this.searchLow=this.searchRaw.map(e=>e.toLowerCase()),this.searchReady=!0}this.layout=this.measureLayout(),this.applyLayout(),this.refresh()}measureLayout(){let e=(n._canvas||=document.createElement(`canvas`)).getContext(`2d`),t=getComputedStyle(this.els.table),r=`${t.fontSize} ${t.fontFamily}`,i=A(this.rows.length,ce),a=[],o=[];for(let t=0;t<this.cols.length;t++){e.font=`bold ${r}`,o.push(Math.max(50,Math.ceil(e.measureText(this.cols[t].name).width)+14+18)),e.font=r;let n=[];for(let r of i){let i=this.getFormattedRow(r)[t];i!==``&&n.push(Math.ceil(e.measureText(i).width)+18)}n.sort((e,t)=>e-t),a.push(n)}return{arrays:a,floors:o}}startColResize(e,t){e.preventDefault(),e.stopPropagation();let n=this.els.table,r=n.querySelectorAll(`colgroup col`)[t];if(!r)return;let i=e.clientX,a=parseFloat(r.style.width);document.body.classList.add(`csvgrid-resizing`);let o=()=>{let e=0;n.querySelectorAll(`colgroup col`).forEach(t=>{e+=parseFloat(t.style.width)}),n.style.width=e+`px`},s=e=>{let n=Math.max(24,Math.round(a+e.clientX-i));this.manualWidths.set(t,n),r.style.width=n+`px`,o()},c=()=>{document.body.classList.remove(`csvgrid-resizing`),document.removeEventListener(`mousemove`,s),document.removeEventListener(`mouseup`,c)};document.addEventListener(`mousemove`,s),document.addEventListener(`mouseup`,c)}fitColumn(e){let{arrays:t,floors:n}=this.layout,r=Math.max(n[e],t[e].length?t[e][t[e].length-1]:0);this.manualWidths.set(e,r),this.applyLayout()}applyLayout(){if(!this.layout)return;let e=this.els.table,t=this.expandAll?1/0:e.parentElement.clientWidth;if(!t)return;let n=J(this.layout.arrays,this.layout.floors,t,this.opts.widthMode);for(let[e,t]of this.manualWidths)e<n.length&&(n[e]=t);let r=e.querySelector(`colgroup`);r&&r.remove(),r=document.createElement(`colgroup`);for(let e of n){let t=document.createElement(`col`);t.style.width=e+`px`,r.appendChild(t)}e.prepend(r),e.style.tableLayout=`fixed`,e.style.width=n.reduce((e,t)=>e+t,0)+`px`}getFormattedRow(e){let t=this.formatted[e];return t||(t=this.cols.map((t,n)=>B(this.rows[e][n],t,e,this.displayMode)),this.formatted[e]=t),t}buildSearchIndexChunked(){let e=this.loadGen,t=this.rows.length,n=Array(t),r=Array(t),i=0;this.indexing=0;let a=()=>{if(e!==this.loadGen)return;let o=Math.min(t,i+le);for(;i<o;i++){let e=this.getFormattedRow(i).join(` `)+` `+this.rows[i].join(` `);n[i]=e,r[i]=e.toLowerCase()}i<t?(this.indexing=i/t,this.renderStatus(),setTimeout(a,0)):(this.searchRaw=n,this.searchLow=r,this.searchReady=!0,this.indexing=null,this.refresh())};a()}rebuildView(){let{rows:e,cols:t}=this,n=W(this.globalFilter);n.length&&!this.searchReady&&(this.indexing===null&&this.buildSearchIndexChunked(),n=[]);let r=n.some(e=>e.kind===`fuzzy`&&!e.negate),i=this.colFilters.map((e,n)=>se(e||``,t[n])),a=i.some(e=>e)||n.length,o=[];this.scores=[];for(let t=0;t<e.length;t++){let r=0;if(a){let a=!0;for(let e of n){let n=q(e,this.searchLow[t],this.searchRaw[t]);if(n<0){a=!1;break}r+=n}if(a){for(let n=0;n<i.length;n++)if(i[n]&&!i[n](e[t][n]??``,t)){a=!1;break}}if(!a)continue}this.scores[t]=r,o.push(t)}let s=this.sortCol;if(s===null&&r)o.sort((e,t)=>this.scores[t]-this.scores[e]||e-t);else if(s!==null){let e=this.cols[s],t=this.sortDir;if(e.type===`text`){let e=new Intl.Collator(`en`,{sensitivity:`base`,numeric:!0});o.sort((n,r)=>{let i=(this.rows[n][s]??``).trim(),a=(this.rows[r][s]??``).trim();return i===``||a===``?i===a?0:i===``?1:-1:t*e.compare(i,a)})}else o.sort((n,r)=>{let i=e.values[n],a=e.values[r];return i===null||a===null?i===a?0:i===null?1:-1:t*(i-a)})}this.view=o}renderHead(){let{cols:e}=this,t=this.els.head;t.innerHTML=``;let n=document.createElement(`tr`);if(e.forEach((e,t)=>{let r=document.createElement(`th`);r.className=X(e),this.opts.sortable?(r.innerHTML=`<span class="sort-arrow">${this.sortCol===t?this.sortDir===1?`▲`:`▼`:``}</span>${Z(e.name)}`,r.title=`${e.name} (${e.type}) — click to sort`,r.addEventListener(`click`,()=>this.onSort(t))):(r.innerHTML=`<span class="sort-arrow"></span>${Z(e.name)}`,r.title=`${e.name} (${e.type})`,r.classList.add(`csvgrid-nosort`));let i=document.createElement(`span`);i.className=`col-resizer`,i.title=`Drag to resize — double-click to fit content`,i.addEventListener(`mousedown`,e=>this.startColResize(e,t)),i.addEventListener(`dblclick`,e=>{e.stopPropagation(),this.fitColumn(t)}),i.addEventListener(`click`,e=>e.stopPropagation()),r.appendChild(i),n.appendChild(r)}),t.appendChild(n),!this.opts.columnFilters)return;let r=document.createElement(`tr`);r.className=`filter-row`,e.forEach((e,t)=>{let n=document.createElement(`th`),i=document.createElement(`input`);i.type=`text`,i.className=`csvgrid-filter`,i.placeholder=e.type===`text`?`filter`:`filter, >, .. `,i.value=this.colFilters[t]||``,i.addEventListener(`input`,()=>{this.colFilters[t]=i.value,i.classList.toggle(`active-filter`,i.value.trim()!==``),this.refresh()}),i.addEventListener(`keydown`,e=>{e.key===`Escape`&&(e.preventDefault(),i.value=``,this.colFilters[t]=``,i.classList.remove(`active-filter`),i.blur(),this.refresh())}),n.appendChild(i),r.appendChild(n)}),t.appendChild(r)}renderBody(){let{cols:e,view:t}=this,n=this.showAll?t.length:Math.min(t.length,this.opts.renderCap),r=[];for(let i=0;i<n;i++){let n=t[i],a=this.getFormattedRow(n),o=e.map((e,t)=>{let n=a[t];return n===``?`<td class="${X(e)} blank">·</td>`:`<td class="${X(e)}">${Z(n)}</td>`});r.push(`<tr>${o.join(``)}</tr>`)}this.els.body.innerHTML=r.join(``);let i=this.els.capNote;t.length>n?(i.classList.remove(`csvgrid-hidden`),this.els.showAllBtn.textContent=`Showing first ${n.toLocaleString()} of ${t.length.toLocaleString()} rows — show all`):i.classList.add(`csvgrid-hidden`)}renderStatus(){if(!this.els.status)return;let e=e=>e.toLocaleString(),t=this.rows.length,n=this.view.length,r=this.showAll?n:Math.min(n,this.opts.renderCap),i=this.fileName?this.fileName+` — `:``;i+=n===t?`${e(t)} rows`:`${e(n)} of ${e(t)} rows`,i+=` × ${this.cols.length} cols`,r<n&&(i+=` — showing rows 1–${e(r)}`),this.guessedHeaders&&(i+=` (headers guessed)`),this.indexing!==null&&(i+=` — indexing search ${Math.round(this.indexing*100)}%`),this.els.status.textContent=i}refresh(){this.rebuildView(),this.renderBody(),this.renderStatus()}onSort(e){this.sortCol===e?this.sortDir===1?this.sortDir=-1:(this.sortCol=null,this.sortDir=1):(this.sortCol=e,this.sortDir=1),this.renderHead(),this.refresh()}}})();
6
- //# sourceMappingURL=csv-grid.iife.js.map
File without changes