csv-grid 3.3.1__tar.gz → 3.9.0__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.1
3
+ Version: 3.9.0
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/
@@ -74,8 +74,15 @@ html = to_html(df, name="results.df", assets="inline") # fragment string
74
74
  if you want to ship data yourself.
75
75
  - Options mirror the JS API in snake_case: `global_search`,
76
76
  `column_filters`, `sortable`, `status_bar`, `expand_buttons`, `align`
77
- (`'llrcr…'`), `formats`/`fmt` (per-column `[,][.N](f|d|%|e|s)`,
78
- `'year'`, `'eng'`, None = auto), `width_mode` (`'equal-risk'` default,
77
+ (`'llrcr…'`), `formats`/`fmt` (per-column: a **number** spec
78
+ `[,][.N](f|d|%|e|s)` / `'year'` / `'eng'`, or on a **date** column a
79
+ strftime pattern `%Y %y %m %d %H %M %S %f` — `%f` is 3-digit
80
+ **milliseconds** here, not Python's 6-digit microseconds — and `%%` is a
81
+ literal `%`; None = auto). Date columns auto-show their finest present
82
+ resolution: date-only when no times are present, `HH:MM` when minutes
83
+ are, `:SS[.fff]` down to milliseconds otherwise, with a uniform
84
+ fractional width per column. An explicit date pattern overrides the auto
85
+ rule. `width_mode` (`'equal-risk'` default,
79
86
  or `'coverage'` to maximize the count of fully-shown cells),
80
87
  `display_mode` (`'auto'` formatted / `'raw'` verbatim), `rows`
81
88
  (cap the viewport to ~N rows, vertical scroll for the rest) /
@@ -84,6 +91,18 @@ html = to_html(df, name="results.df", assets="inline") # fragment string
84
91
  and `index` (include the DataFrame index as leading columns). Dark mode
85
92
  follows the host page (`prefers-color-scheme`; JupyterLab dark themes
86
93
  included) unless `theme="light"`/`"dark"` forces it.
94
+ - **Clickable rows/cells** (`selectable=True`): a body click fires a
95
+ bubbling `csvgrid:cellclick` DOM event whose `detail` carries the clicked
96
+ cell and the whole row keyed by column name (raw + formatted) with the
97
+ original row index — wire it to HTMX/JS for drill-down. `select_mode`
98
+ (`'row'`/`'cell'`/`'none'`) controls the highlight; `hidden_columns=[…]`
99
+ ships a key column in the payload without displaying it. No Python
100
+ callback — `to_html` stays a pure string emitter.
101
+
102
+ ```python
103
+ to_html(df, name="transactions", selectable=True,
104
+ select_mode="row", hidden_columns=["trans_id"])
105
+ ```
87
106
 
88
107
  Dates are emitted ISO (`yyyy-mm-dd`, with `hh:mm` only when a column has
89
108
  non-midnight times); integral float columns are emitted as integers so
@@ -48,8 +48,15 @@ html = to_html(df, name="results.df", assets="inline") # fragment string
48
48
  if you want to ship data yourself.
49
49
  - Options mirror the JS API in snake_case: `global_search`,
50
50
  `column_filters`, `sortable`, `status_bar`, `expand_buttons`, `align`
51
- (`'llrcr…'`), `formats`/`fmt` (per-column `[,][.N](f|d|%|e|s)`,
52
- `'year'`, `'eng'`, None = auto), `width_mode` (`'equal-risk'` default,
51
+ (`'llrcr…'`), `formats`/`fmt` (per-column: a **number** spec
52
+ `[,][.N](f|d|%|e|s)` / `'year'` / `'eng'`, or on a **date** column a
53
+ strftime pattern `%Y %y %m %d %H %M %S %f` — `%f` is 3-digit
54
+ **milliseconds** here, not Python's 6-digit microseconds — and `%%` is a
55
+ literal `%`; None = auto). Date columns auto-show their finest present
56
+ resolution: date-only when no times are present, `HH:MM` when minutes
57
+ are, `:SS[.fff]` down to milliseconds otherwise, with a uniform
58
+ fractional width per column. An explicit date pattern overrides the auto
59
+ rule. `width_mode` (`'equal-risk'` default,
53
60
  or `'coverage'` to maximize the count of fully-shown cells),
54
61
  `display_mode` (`'auto'` formatted / `'raw'` verbatim), `rows`
55
62
  (cap the viewport to ~N rows, vertical scroll for the rest) /
@@ -58,6 +65,18 @@ html = to_html(df, name="results.df", assets="inline") # fragment string
58
65
  and `index` (include the DataFrame index as leading columns). Dark mode
59
66
  follows the host page (`prefers-color-scheme`; JupyterLab dark themes
60
67
  included) unless `theme="light"`/`"dark"` forces it.
68
+ - **Clickable rows/cells** (`selectable=True`): a body click fires a
69
+ bubbling `csvgrid:cellclick` DOM event whose `detail` carries the clicked
70
+ cell and the whole row keyed by column name (raw + formatted) with the
71
+ original row index — wire it to HTMX/JS for drill-down. `select_mode`
72
+ (`'row'`/`'cell'`/`'none'`) controls the highlight; `hidden_columns=[…]`
73
+ ships a key column in the payload without displaying it. No Python
74
+ callback — `to_html` stays a pure string emitter.
75
+
76
+ ```python
77
+ to_html(df, name="transactions", selectable=True,
78
+ select_mode="row", hidden_columns=["trans_id"])
79
+ ```
61
80
 
62
81
  Dates are emitted ISO (`yyyy-mm-dd`, with `hh:mm` only when a column has
63
82
  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.1"
3
+ version = "3.9.0"
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.1"
21
+ __version__ = "3.9.0"
22
22
  __all__ = ["show", "to_html", "payload"]
23
23
 
24
24
  # python snake_case -> CsvGrid option names (see src/grid/grid.js)
@@ -28,6 +28,7 @@ _OPTION_MAP = {
28
28
  "sortable": "sortable",
29
29
  "status_bar": "statusBar",
30
30
  "expand_buttons": "expandButtons",
31
+ "export_buttons": "exportButtons",
31
32
  "align": "align",
32
33
  "formats": "formats",
33
34
  "width_mode": "widthMode",
@@ -37,6 +38,9 @@ _OPTION_MAP = {
37
38
  "render_cap": "renderCap",
38
39
  "eager_cells": "eagerCells",
39
40
  "worker": "worker",
41
+ "selectable": "selectable",
42
+ "select_mode": "selectMode",
43
+ "hidden_columns": "hiddenColumns",
40
44
  }
41
45
  _CAMEL = set(_OPTION_MAP.values())
42
46
 
@@ -73,10 +77,14 @@ def _jsonable(o):
73
77
 
74
78
  def payload(df, name: str | None = None, index: bool = False) -> dict:
75
79
  """The {records, columns[, name]} dict CsvGrid consumes (records as
76
- arrays in column order). Dates become ISO strings (hh:mm only when a
77
- column has non-midnight times); NaN/None/NaT become None (blank cells
78
- in the grid); integral float columns become ints so the grid's
79
- integer/year formatting rules apply. Types are re-inferred grid-side.
80
+ arrays in column order). Dates become ISO strings at FULL precision
81
+ (``YYYY-MM-DD HH:MM:SS``, plus ``.fff`` milliseconds when the column
82
+ carries any sub-second component); the grid owns the finest-present
83
+ collapse (an all-midnight column reduces to date-only, whole-second
84
+ data to ``:SS``, etc.) so this side no longer special-cases midnight.
85
+ NaN/None/NaT become None (blank cells in the grid); integral float
86
+ columns become ints so the grid's integer/year formatting rules apply.
87
+ Types are re-inferred grid-side.
80
88
  """
81
89
  import pandas as pd # deferred so importing csv_grid stays cheap
82
90
 
@@ -88,10 +96,14 @@ def payload(df, name: str | None = None, index: bool = False) -> dict:
88
96
  for c in df.columns:
89
97
  s = df[c]
90
98
  if isinstance(s.dtype, pd.DatetimeTZDtype) or str(s.dtype).startswith("datetime64"):
91
- midnight = (s.dt.hour.fillna(0).eq(0) & s.dt.minute.fillna(0).eq(0)
92
- & s.dt.second.fillna(0).eq(0)).all()
93
- fmt = "%Y-%m-%d" if midnight else "%Y-%m-%d %H:%M"
94
- vals = [None if pd.isna(v) else v.strftime(fmt) for v in s]
99
+ # any sub-second present in the column -> emit 3-digit ms for all
100
+ # rows (we cap at ms; sub-ms rounds away). The grid decides the
101
+ # uniform displayed width from the values it actually sees.
102
+ subsec = bool(s.dt.microsecond.fillna(0).ne(0).any())
103
+ vals = [None if pd.isna(v)
104
+ else v.strftime("%Y-%m-%d %H:%M:%S")
105
+ + (".%03d" % (v.microsecond // 1000) if subsec else "")
106
+ for v in s]
95
107
  elif str(s.dtype).startswith("float"):
96
108
  nonnull = s.dropna()
97
109
  integral = len(nonnull) > 0 and nonnull.mod(1).eq(0).all()
@@ -222,6 +234,10 @@ def show(df, *, name: str | None = None, assets="inline",
222
234
  sortable : bool, default True click headers to sort.
223
235
  status_bar : bool, default True row-counts line.
224
236
  expand_buttons : bool, default True Expand / Contract pair.
237
+ export_buttons : bool, default True Copy / Save split-buttons (one-click
238
+ current view as CSV, plus a menu for
239
+ Markdown / whole-table / raw). Output
240
+ reflects visible columns only.
225
241
  align : str, optional 'llrcr…', one of l/r/c per column,
226
242
  overriding the type-based default.
227
243
  formats / fmt : list, optional per-column format spec, None entry
@@ -249,6 +265,23 @@ def show(df, *, name: str | None = None, assets="inline",
249
265
  front (else lazy).
250
266
  worker : bool, default False parse worker (off by default here
251
267
  — the data is inlined, not fetched).
268
+ selectable : bool, default False emit a bubbling, cancelable
269
+ ``csvgrid:cellclick`` DOM event on a
270
+ body click (off = no event, no cost).
271
+ ``event.detail`` carries the clicked
272
+ cell and the whole row keyed by column
273
+ name (raw + formatted) with the
274
+ original row index, so an embedder
275
+ (HTMX, JS) can drill down. The grid
276
+ takes no action beyond an optional
277
+ highlight; no Python callback.
278
+ select_mode : {'row', 'cell', 'none'}, default 'row'
279
+ the visual highlight on click ('none'
280
+ still emits the event).
281
+ hidden_columns : list[str], optional header names carried in the event
282
+ payload (and export) but not shown as
283
+ columns — e.g. ship a key column
284
+ without displaying it.
252
285
 
253
286
  Dark mode follows the host page automatically unless ``theme`` forces
254
287
  it (prefers-color-scheme; JupyterLab dark themes included).
@@ -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;
@@ -105,6 +108,77 @@
105
108
  background: var(--csvgrid-muted);
106
109
  color: var(--csvgrid-bg);
107
110
  }
111
+ /* Brief post-action confirmation on a Copy/Save button */
112
+ .csvgrid-btn.csvgrid-flash {
113
+ background: var(--csvgrid-accent);
114
+ border-color: var(--csvgrid-accent);
115
+ color: var(--csvgrid-bg);
116
+ }
117
+
118
+ /* Copy / Save split-control: a flat primary + a ▾ disclosure menu, joined
119
+ * so they read as one button. Native <details> drives open/close (no JS,
120
+ * no document listener — multi-instance safe). */
121
+ .csvgrid-export {
122
+ display: inline-flex;
123
+ position: relative;
124
+ }
125
+ .csvgrid-export .csvgrid-btn {
126
+ border-radius: 0; /* squared inner edges; ends re-rounded below */
127
+ }
128
+ .csvgrid-export > .csvgrid-btn:first-child {
129
+ border-top-left-radius: 0.25rem;
130
+ border-bottom-left-radius: 0.25rem;
131
+ }
132
+ .csvgrid-export .csvgrid-menu-toggle { /* match the reset's specificity so the right corners re-round */
133
+ border-top-right-radius: 0.25rem;
134
+ border-bottom-right-radius: 0.25rem;
135
+ border-left: 0;
136
+ list-style: none; /* kill the native disclosure triangle */
137
+ }
138
+ .csvgrid-menu-toggle::-webkit-details-marker { display: none; }
139
+ .csvgrid-menu-toggle::marker { content: ''; }
140
+ .csvgrid-menu-panel {
141
+ position: absolute;
142
+ top: calc(100% + 2px);
143
+ left: 0;
144
+ z-index: 5;
145
+ min-width: max-content;
146
+ display: flex;
147
+ flex-direction: column;
148
+ padding: 0.25rem 0;
149
+ border: 1px solid var(--csvgrid-border);
150
+ border-radius: 0.25rem;
151
+ background: var(--csvgrid-bg);
152
+ box-shadow: 0 0.25rem 0.75rem rgba(0, 0, 0, 0.15);
153
+ }
154
+ .csvgrid-menu-item {
155
+ text-align: left;
156
+ white-space: nowrap;
157
+ font-size: 0.875rem;
158
+ padding: 0.25rem 0.75rem;
159
+ border: 0;
160
+ background: transparent;
161
+ color: var(--csvgrid-fg);
162
+ cursor: pointer;
163
+ }
164
+ .csvgrid-menu-item:hover {
165
+ background: var(--csvgrid-row-hover);
166
+ }
167
+ .csvgrid-menu-sep {
168
+ height: 1px;
169
+ margin: 0.25rem 0;
170
+ background: var(--csvgrid-border);
171
+ }
172
+ .csvgrid-menu-check {
173
+ display: flex;
174
+ align-items: center;
175
+ gap: 0.4rem;
176
+ white-space: nowrap;
177
+ font-size: 0.875rem;
178
+ padding: 0.25rem 0.75rem;
179
+ color: var(--csvgrid-fg);
180
+ cursor: pointer;
181
+ }
108
182
 
109
183
  /* Scrollable table region; hosts cap its height / add card chrome */
110
184
  .csvgrid-scroll { overflow: auto; }
@@ -135,6 +209,15 @@
135
209
  }
136
210
  .csvgrid .csvgrid-table tbody tr:hover td { background: var(--csvgrid-row-hover); }
137
211
 
212
+ /* Windowed-render spacer rows: reserve off-screen height only — no padding,
213
+ * border, hover or selection chrome (they're not real rows). */
214
+ .csvgrid .csvgrid-table tbody tr.csvgrid-spacer td,
215
+ .csvgrid .csvgrid-table tbody tr.csvgrid-spacer:hover td {
216
+ padding: 0;
217
+ border: 0;
218
+ background: none;
219
+ }
220
+
138
221
  .csvgrid .csvgrid-table thead th {
139
222
  position: sticky;
140
223
  top: 0;
@@ -208,6 +291,17 @@ body.csvgrid-resizing { cursor: col-resize; user-select: none; }
208
291
  .csvgrid .csvgrid-table .align-right { text-align: right; }
209
292
  .csvgrid .csvgrid-table td.blank { color: var(--csvgrid-blank); }
210
293
 
294
+ /* Clickable rows/cells (opt-in selectable option). The cursor affordance
295
+ * shows only when on; selection rules sit after the hover rule so a selected
296
+ * row stays visibly selected even while hovered. Reads in light and dark. */
297
+ .csvgrid[data-selectable] .csvgrid-table tbody tr { cursor: pointer; }
298
+ .csvgrid .csvgrid-table tbody tr.csvgrid-selected td,
299
+ .csvgrid .csvgrid-table tbody tr.csvgrid-selected-row td { background: var(--csvgrid-selected-bg); }
300
+ .csvgrid .csvgrid-table tbody td.csvgrid-selected {
301
+ outline: 2px solid var(--csvgrid-accent);
302
+ outline-offset: -2px;
303
+ }
304
+
211
305
  /* "Showing first N — show all" note below the table */
212
306
  .csvgrid-capnote {
213
307
  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]+)?%?\)?$/,d=/^\(?[+-]?(?:inf(?:inity)?|∞)\)?$/i,f=/^(\d{4})-(\d{1,2})-(\d{1,2})(?:[T ](\d{1,2}):(\d{2})(?::(\d{2})(?:\.(\d+))?)?Z?)?$/,p=/^(\d{1,4})([\/\-.])(\d{1,2})\2(\d{1,4})$/,ee=/^(\d{1,2})[ \-]([A-Za-z]{3,9})\.?,?[ \-](\d{2,4})$/,m=/^([A-Za-z]{3,9})\.?,?[ \-](\d{1,2}),?[ \-](\d{2,4})$/,te=[`january`,`february`,`march`,`april`,`may`,`june`,`july`,`august`,`september`,`october`,`november`,`december`],ne=new Set([`nan`,`na`,`n/a`,`#n/a`,`null`,`none`,`-`,`--`,`.`]);function h(e){return ne.has((e??``).trim().toLowerCase())}function g(e){if(e=e.trim(),d.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,f=s.indexOf(`.`),p=Math.max(0,(f<0?0:s.length-f-1)-c);return i&&(p+=2),{v:a,dec:p,sym:n}}var _=`9007199254740991`;function v(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>_)}function y(e){let t=e.toLowerCase(),n=te.findIndex(e=>e.startsWith(t)||t===`sept`&&e===`september`);return n<0||t.length<3?null:n+1}function b(e){return e=+e,e<100?e<50?2e3+e:1900+e:e}function x(e,t,n,r=0,i=0,a=0,o=0,s=!1){let c=new Date(e,t-1,n,r,i,a,o);return c.getFullYear()!==e||c.getMonth()!==t-1||c.getDate()!==+n?null:{t:c.getTime(),hasTime:s}}function S(e,t=!1){e=e.trim();let n=f.exec(e);if(n){let[,e,t,r,i,a,o,s]=n,c=s?Math.round((`0.`+s)*1e3):0;return x(+e,+t,+r,+(i||0),+(a||0),+(o||0),c,i!==void 0)}if(n=p.exec(e),n){let[,e,,r,i]=n;if(e.length===4&&i.length<=2)return x(+e,+r,+i);if(e.length<=2&&(i.length===4||i.length===2)){let n=b(i);return+e>12&&+r<=12?x(n,+r,+e):+r>12&&+e<=12?x(n,+e,+r):t?x(n,+r,+e):x(n,+e,+r)}return null}if(n=ee.exec(e),n){let e=y(n[2]);return e?x(b(n[3]),e,+n[1]):null}if(n=m.exec(e),n){let e=y(n[1]);return e?x(b(n[3]),e,+n[2]):null}return null}function re(e){let t=p.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 ie(e){return e.some(e=>{let t=(e??``).trim();return t!==``&&(g(t)!==null||S(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===``||h(n))&&(c++,i&&(g(n)===null?i=!1:(!o&&N.test(n)&&(o=!0),!s&&v(n)&&(s=!0))),a&&S(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===``||h(o))continue;let s=g(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===``||h(c))continue;let l=S(c,!1);l&&(s[e]=l.t,i||=l.hasTime);let u=re(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===``||h(n))continue;let i=S(n,!0);i&&(s[e]=i.t)}}let c=!1,l=!1,u=0;for(let e=0;e<s.length;e++){let t=s[e];if(t===null)continue;let n=new Date(t),r=n.getMilliseconds();if((n.getHours()||n.getMinutes()||n.getSeconds()||r)&&(c=!0),(n.getSeconds()||r)&&(l=!0),r){let e=r%100==0?1:r%10==0?2:3;e>u&&(u=e)}}let d=c?l?`second`:`minute`:`day`;return{name:e,type:`date`,hasTime:i,timePrec:{level:d,frac:d===`second`?u:0},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?ie(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,t){if(e==null||e===``)return null;if(/%[YymdHMSf%]/.test(e)){if(t===`number`)throw Error(`CsvGrid: date format '${e}' on a number column`);return{kind:`datefmt`,pattern:e}}if(e===`year`||e===`eng`){if(t===`date`)throw Error(`CsvGrid: number format '${e}' on a date column`);return{kind:e}}let n=/^(,)?(?:\.(\d+))?([fd%es])$/.exec(e);if(!n)throw Error(`CsvGrid: unrecognized format spec '${e}'`);if(t===`date`)throw Error(`CsvGrid: number format '${e}' on a date column`);return{kind:n[3],comma:!!n[1],dec:n[2]===void 0?null:+n[2]}}function z(e,t){let n=e=>String(e).padStart(2,`0`);return t.replace(/%([YymdHMSf%])/g,(t,r)=>{switch(r){case`Y`:return String(e.getFullYear());case`y`:return n(e.getFullYear()%100);case`m`:return n(e.getMonth()+1);case`d`:return n(e.getDate());case`H`:return n(e.getHours());case`M`:return n(e.getMinutes());case`S`:return n(e.getSeconds());case`f`:return String(e.getMilliseconds()).padStart(3,`0`);case`%`:return`%`}})}var B=[[0xe8d4a51000,`T`],[1e9,`G`],[1e6,`M`],[1e3,`k`],[1,``],[.001,`m`],[1e-6,`µ`],[1e-9,`n`]];function V(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 B)if(n>=r)return(e/r).toFixed(t.dec)+i;return(e/1e-9).toFixed(t.dec)+`n`}}}function H(e){return[...e].map(e=>({l:`left`,r:`right`,c:`center`})[e]??null)}function U(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 h(e)?``:e;if(!Number.isFinite(r))return r>0?`inf`:`-inf`;if(t.fmt)return V(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 h(e)?``:e;let i=new Date(r);if(t.fmt?.kind===`datefmt`)return z(i,t.fmt.pattern);let a=e=>String(e).padStart(2,`0`),o=`${i.getFullYear()}-${a(i.getMonth()+1)}-${a(i.getDate())}`,s=t.timePrec??{level:t.hasTime?`minute`:`day`,frac:0};if(s.level!==`day`&&(o+=` ${a(i.getHours())}:${a(i.getMinutes())}`,s.level===`second`&&(o+=`:${a(i.getSeconds())}`,s.frac>0))){let e=String(i.getMilliseconds()).padStart(3,`0`);o+=`.`+e.slice(0,s.frac)}return o}return e}function W(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 G(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 K(e,t=`file`){return(e||``).replace(/\.[^.\\/]+$/,``).replace(/[<>:"/\\|?*\x00-\x1f]/g,``).replace(/[. ]+$/,``).trim()||t}function q(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 J(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 Y=/[\s_\-\/\\.,:;()[\]{}"']/;function ae(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||Y.test(t[n-1]))&&(s+=8),c&&(s+=4),c=!0,i++):c=!1;return s}function oe(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=ae(e.str,r);i=t>=0,a=t}}return e.negate&&(i=!i),i?a:-1}function se(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 ce(e,t,n,r=`equal-risk`){return r===`coverage`?ue(e,t,n):le(e,t,n)}function le(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 ue(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=de(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 de(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 fe(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=g(e);return t?t.v:NaN}:e=>{let t=S(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 pe=1e6,me=2048,he=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,exportButtons:!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||e.exportButtons){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)}e.exportButtons&&n.append(this._buildExportControl(`copy`),this._buildExportControl(`save`)),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)))}_buildExportControl(e){let t=e===`copy`?`Copy`:`Save`,n=$(`span`,`csvgrid-export`),r=$(`button`,`csvgrid-btn`);r.type=`button`,r.textContent=t,r.title=`${t} the current view as CSV`,r.addEventListener(`click`,()=>this._runExport(e,`view`,`csv`,n,r));let i=$(`details`,`csvgrid-menu`),a=$(`summary`,`csvgrid-btn csvgrid-menu-toggle`);a.textContent=`▾`,a.title=`More ${t.toLowerCase()} options`;let o=$(`div`,`csvgrid-menu-panel`);for(let[t,a,s]of[[`view`,`csv`,`Current view → CSV`],[`view`,`md`,`Current view → Markdown`],[`all`,`csv`,`Whole table → CSV`],[`all`,`md`,`Whole table → Markdown`]]){let c=$(`button`,`csvgrid-menu-item`);c.type=`button`,c.textContent=s,c.addEventListener(`click`,()=>{i.open=!1,this._runExport(e,t,a,n,r)}),o.appendChild(c)}o.appendChild($(`div`,`csvgrid-menu-sep`));let s=$(`label`,`csvgrid-menu-check`),c=$(`input`,`csvgrid-export-formatted`);return c.type=`checkbox`,c.checked=!0,s.append(c,document.createTextNode(` Formatted values`)),o.appendChild(s),i.addEventListener(`focusout`,e=>{i.contains(e.relatedTarget)||(i.open=!1)}),i.addEventListener(`keydown`,e=>{e.key===`Escape`&&i.open&&(e.preventDefault(),i.open=!1,a.focus())}),i.append(a,o),n.append(r,i),n}_runExport(e,t,n,r,i){let a=r.querySelector(`.csvgrid-export-formatted`),o=a&&a.checked?`formatted`:`raw`,s=this.export({scope:t,format:n,values:o,visibleOnly:!0});e===`copy`?this._copyText(s,i):this._saveText(s,n,i)}_copyText(e,t){let n=()=>this._flash(t,`Copied`),r=()=>this._flash(t,`Copy failed`);if(navigator.clipboard&&navigator.clipboard.writeText)navigator.clipboard.writeText(e).then(n,r);else{let t=document.createElement(`textarea`);t.value=e,t.style.cssText=`position:fixed;opacity:0`,document.body.appendChild(t),t.select();try{document.execCommand(`copy`),n()}catch{r()}t.remove()}}_saveText(e,t,n){let r=t===`md`,i=r?e:``+e,a=(r?`text/markdown`:`text/csv`)+`;charset=utf-8`,o=URL.createObjectURL(new Blob([i],{type:a})),s=document.createElement(`a`);s.href=o,s.download=this._exportBaseName()+(r?`.md`:`.csv`),document.body.appendChild(s),s.click(),s.remove(),setTimeout(()=>URL.revokeObjectURL(o),1e3),this._flash(n,`Saved`)}_exportBaseName(){return K(this.fileName,`grid`)}_flash(e,t){clearTimeout(e._flashTimer),e._flashLabel===void 0&&(e._flashLabel=e.textContent),e.textContent=t,e.classList.add(`csvgrid-flash`),e._flashTimer=setTimeout(()=>{e.textContent=e._flashLabel,e._flashLabel=void 0,e.classList.remove(`csvgrid-flash`)},1200)}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:q(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>=pe?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=H(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],e.type)}),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`,visibleOnly:r=!1}={}){let i=e===`all`?this.rows.map((e,t)=>t):this.view,a=r?this.visibleCols:this.cols.map((e,t)=>t),o=n===`formatted`&&i.length<=this.opts.renderCap,s=i.map(e=>{let t=o?this.getFormattedRow(e):this.rows[e];return a.map(e=>t[e]??``)}),c=a.map(e=>this.headers[e]);return t===`md`?G(c,s,a.map(e=>this.cols[e].align||(this.cols[e].type===`number`?`right`:this.cols[e].type===`date`?`center`:`left`))):W(c,s)}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,me),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=ce(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)=>U(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+he);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]=se(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=J(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)=>fe(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=oe(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.3.1"
15
+ version = "3.8.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