schummar-table 1.0.0-beta.0 → 1.0.0-beta.3

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.
package/LICENSE ADDED
@@ -0,0 +1,15 @@
1
+ ISC License
2
+
3
+ Copyright (c) 2021-2026 Marco Schumacher
4
+
5
+ Permission to use, copy, modify, and/or distribute this software for any
6
+ purpose with or without fee is hereby granted, provided that the above
7
+ copyright notice and this permission notice appear in all copies.
8
+
9
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10
+ WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11
+ MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12
+ ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13
+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14
+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15
+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
package/README.md CHANGED
@@ -1,4 +1,225 @@
1
1
  # schummar-table
2
2
 
3
3
  [![](https://badgen.net/npm/v/schummar-table)](https://www.npmjs.com/package/schummar-table)
4
+ [![](https://badgen.net/npm/v/schummar-table/next)](https://www.npmjs.com/package/schummar-table/v/next)
4
5
  [![](https://badgen.net/bundlephobia/minzip/schummar-table)](https://bundlephobia.com/package/schummar-table)
6
+
7
+ A fast, fully typed table for React. Sorting, filtering, selection, trees, column resizing,
8
+ virtualization, persistence and exports work out of the box. Every piece of state can be left to
9
+ the table or controlled from outside.
10
+
11
+ - **Typed end to end.** Column values flow into `renderCell`, `sortBy` and `filterBy`, and filters
12
+ are type checked against the column they sit on.
13
+ - **Fast.** Rows and cells are memoized, virtualization uses
14
+ [TanStack Virtual](https://tanstack.com/virtual), and expensive cells can render progressively.
15
+ - **Unopinionated styling.** Plain class names or emotion styles for every part, with built-in
16
+ styles that your overrides always win against. Themes for MUI 4 and 5 are included.
17
+
18
+ **[Live examples](https://schummar.github.io/schummar-table/)**
19
+
20
+ ## Installation
21
+
22
+ ```bash
23
+ npm install schummar-table @emotion/react
24
+ ```
25
+
26
+ React 19 or newer is required. `write-excel-file` is only needed for the Excel exporter, `@mui/material` or
27
+ `@material-ui/core` only for the matching theme.
28
+
29
+ ## Quick start
30
+
31
+ ```tsx
32
+ import { Table, selectFilter, textFilter } from 'schummar-table';
33
+
34
+ interface Person {
35
+ id: number;
36
+ name: string;
37
+ job: string;
38
+ birthday: Date;
39
+ }
40
+
41
+ export function People({ people }: { people: Person[] }) {
42
+ return (
43
+ <Table
44
+ items={people}
45
+ id="id"
46
+ columns={(col) => [
47
+ col((person) => person.name, { header: 'Name', filter: textFilter() }),
48
+ col((person) => person.job, { header: 'Job', filter: selectFilter() }),
49
+ col((person) => person.birthday, {
50
+ header: 'Birthday',
51
+ renderCell: (birthday) => birthday.toLocaleDateString(),
52
+ }),
53
+ ]}
54
+ />
55
+ );
56
+ }
57
+ ```
58
+
59
+ `col(value, options)` infers the column value from its first argument, so `birthday` above is a
60
+ `Date` everywhere.
61
+
62
+ ## Columns
63
+
64
+ ```tsx
65
+ col((person) => person.birthday, {
66
+ id: 'birthday', // stable id for persistence and controlled state; defaults to the index
67
+ header: 'Birthday',
68
+ renderCell: (birthday, person) => birthday.toLocaleDateString(),
69
+ sortBy: [(birthday) => birthday.getTime()],
70
+ exportCell: (birthday) => birthday.toISOString(),
71
+ width: '12ch', // any CSS grid width; defaults to max-content
72
+ displaySize: 'desktop', // only show on some screen sizes
73
+ });
74
+ ```
75
+
76
+ Columns can be hidden by the user (`enableColumnSelection`, on by default) and resized by dragging
77
+ the header separators (`enableColumnResize`).
78
+
79
+ ## Filters
80
+
81
+ A filter is created with a factory and put on a column. Its UI opens from the column header.
82
+
83
+ ```tsx
84
+ col((person) => person.name, { filter: textFilter({ compare: 'prefix' }) });
85
+ col((person) => person.tags, { filter: selectFilter() }); // string[] works too
86
+ col((person) => person.age, { filter: rangeFilter({ min: 0 }) });
87
+ col((person) => person.birthday, { filter: dateFilter({ maxDate: new Date() }) });
88
+ ```
89
+
90
+ | Filter | Accepts |
91
+ | -------------- | -------------------------------------------- |
92
+ | `textFilter` | `string`, `number`, `bigint` |
93
+ | `selectFilter` | anything; `options`, `render` etc. narrow it |
94
+ | `rangeFilter` | `number`, `bigint` |
95
+ | `dateFilter` | `Date`, `DateRange`, ISO date strings |
96
+
97
+ Each also accepts `null`/`undefined`, arrays and Sets (an item matches if one of the values
98
+ does). A filter that doesn't fit the column value is a type error. Use `filterBy` to filter by
99
+ something else:
100
+
101
+ ```tsx
102
+ col((person) => person.birthday, {
103
+ filterBy: (birthday) => birthday.getFullYear(),
104
+ filter: rangeFilter(),
105
+ });
106
+ ```
107
+
108
+ Every filter takes `defaultValue`, `value` and `onChange` (typed by the filter's own value), and
109
+ `external` to leave the actual filtering to you, e.g. on the server. All filter values can also be
110
+ controlled at once with `filterValues` / `onFilterValuesChange` on the table.
111
+
112
+ Custom filters are made with `defineFilter`:
113
+
114
+ ```tsx
115
+ const flagFilter = defineFilter<boolean, boolean>({
116
+ isActive: (value) => value,
117
+ test: (value, input) => input === value,
118
+ Component: ({ value, onChange }) => (
119
+ <label>
120
+ <input type="checkbox" checked={!!value} onChange={(e) => onChange(e.target.checked)} />
121
+ Only flagged
122
+ </label>
123
+ ),
124
+ });
125
+ ```
126
+
127
+ ## State
128
+
129
+ The table manages its state on its own. Every part can be initialized or controlled instead, the
130
+ same way as React inputs:
131
+
132
+ | State | Initial | Controlled | Change |
133
+ | -------------- | ---------------------- | --------------- | ----------------------- |
134
+ | Sort | `defaultSort` | `sort` | `onSortChange` |
135
+ | Selection | `defaultSelection` | `selection` | `onSelectionChange` |
136
+ | Expanded rows | `defaultExpanded` | `expanded` | `onExpandedChange` |
137
+ | Hidden columns | `defaultHiddenColumns` | `hiddenColumns` | `onHiddenColumnsChange` |
138
+ | Filter values | `defaultFilterValues` | `filterValues` | `onFilterValuesChange` |
139
+
140
+ Use `externalSort` when the items arrive sorted already. A `ref` gives imperative access, and
141
+ `useTableActions()` / `useTableContext()` do the same from components inside the table.
142
+
143
+ ## Trees and row details
144
+
145
+ ```tsx
146
+ <Table items={items} id="id" parentId="parentId" columns={columns} />
147
+ ```
148
+
149
+ Items with a `parentId` become collapsible children of their parent. `hasDeferredChildren` marks
150
+ items whose children load on expand, and `revealFiltered` expands parents of matching children.
151
+ `rowDetails` renders an expandable area below each row instead.
152
+
153
+ ## Large tables
154
+
155
+ ```tsx
156
+ <Table virtual items={items} ... />
157
+ <Table virtual={{ rowHeight: 40, overscan: 10, deferCells: true }} items={items} ... />
158
+ ```
159
+
160
+ `virtual` only renders the rows in view. It works inside any scroll container or with the window.
161
+ `deferCells` renders expensive cells progressively: rows that don't fit the frame budget show a
162
+ placeholder first, and visible rows are revealed first. Use `deferred` on single columns instead.
163
+
164
+ ## Persistence
165
+
166
+ ```tsx
167
+ <Table persist={{ storage: localStorage, id: 'people' }} ... />
168
+ ```
169
+
170
+ Sort, selection, expanded rows, hidden columns, column widths and filter values are saved and
171
+ restored. `include` and `exclude` narrow this down, including single filters with
172
+ `{ filterValues: ['name'] }`. Any storage with `getItem`/`setItem`/`removeItem` works, including
173
+ async ones like localForage.
174
+
175
+ ## Export
176
+
177
+ `enableExport` adds copy and download buttons for the visible (or selected) rows as CSV. More
178
+ exporters are registered through a provider:
179
+
180
+ ```tsx
181
+ import ExcelExporter from 'schummar-table/excelExporter';
182
+
183
+ <TableSettingsProvider
184
+ additionalExporters={[{ action: 'download', exporter: new ExcelExporter() }]}
185
+ >
186
+ <App />
187
+ </TableSettingsProvider>;
188
+ ```
189
+
190
+ ## Styling and themes
191
+
192
+ Every part accepts class names and emotion styles, per table or per column:
193
+
194
+ ```tsx
195
+ <Table
196
+ classes={{ table: 'people', headerCell: 'people-header', evenCell: 'even' }}
197
+ styles={{ cell: { padding: '0.5em 1em' } }}
198
+ ...
199
+ />
200
+ ```
201
+
202
+ The built-in styles are inserted before all other styles, so an override of equal specificity
203
+ always wins. `classes.row/cell` and `styles.row/cell` also take a function of the item. Prefer
204
+ class names or constant styles there: function styles run for every cell render.
205
+
206
+ Components, icons, texts and colors are replaced through a theme, per table or for all tables via
207
+ `TableSettingsProvider`. MUI themes ship as separate entry points:
208
+
209
+ ```tsx
210
+ import { Mui5TableThemeProvider } from 'schummar-table/mui5Theme';
211
+
212
+ <Mui5TableThemeProvider>
213
+ <App />
214
+ </Mui5TableThemeProvider>;
215
+ ```
216
+
217
+ ## Upgrading from 0.x
218
+
219
+ 1.0 changes the filter API, the `virtual` options and a few others. The package ships an agent
220
+ skill that walks through the migration: point your coding agent at
221
+ `node_modules/schummar-table/skills/schummar-table-upgrade/SKILL.md`.
222
+
223
+ ## License
224
+
225
+ ISC
@@ -1,4 +1,4 @@
1
- import { i as StringExporter, t as BlobExporter } from "./exporter-BT2ehIIU.cjs";
1
+ import { i as StringExporter, t as BlobExporter } from "./exporter-Dv2Vqqth.cjs";
2
2
  //#region src/exporters/csvExporter.d.ts
3
3
  export interface CsvExporterOptions {
4
4
  sepPrefix?: boolean;
@@ -1,4 +1,4 @@
1
- import { i as StringExporter, t as BlobExporter } from "./exporter-BT2ehIIU.js";
1
+ import { i as StringExporter, t as BlobExporter } from "./exporter-Dv2Vqqth.js";
2
2
  //#region src/exporters/csvExporter.d.ts
3
3
  export interface CsvExporterOptions {
4
4
  sepPrefix?: boolean;
@@ -1,16 +1,19 @@
1
- let xlsx = require("xlsx");
1
+ const require_rolldown_runtime = require("./rolldown-runtime-C0BPl7ul.cjs");
2
+ let write_excel_file_browser = require("write-excel-file/browser");
3
+ write_excel_file_browser = require_rolldown_runtime.__toESM(write_excel_file_browser, 1);
2
4
  //#region src/exporters/excelExporter.ts
3
5
  var ExcelExporter = class {
4
- constructor() {
6
+ constructor(options = {}) {
7
+ this.options = options;
5
8
  this.type = "xlsx";
6
9
  this.fileEnding = "xlsx";
7
10
  }
8
11
  exportToBlob(columns, rows) {
9
- const worksheet = xlsx.utils.aoa_to_sheet([columns, ...rows]);
10
- const workbook = xlsx.utils.book_new();
11
- xlsx.utils.book_append_sheet(workbook, worksheet, "Sheet1");
12
- const data = (0, xlsx.write)(workbook, { type: "buffer" });
13
- return new Blob([data], { type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" });
12
+ const { dateFormat = "yyyy-mm-dd", sheet = "Sheet1" } = this.options;
13
+ return (0, write_excel_file_browser.default)([columns, ...rows], {
14
+ sheet,
15
+ dateFormat
16
+ }).toBlob();
14
17
  }
15
18
  };
16
19
  //#endregion
@@ -1 +1 @@
1
- {"version":3,"file":"excelExporter.cjs","names":["utils","write"],"sources":["../src/exporters/excelExporter.ts"],"sourcesContent":["import { utils, write } from 'xlsx';\nimport { BlobExporter } from './exporter';\n\nexport default class ExcelExporter implements BlobExporter {\n readonly type = 'xlsx';\n readonly fileEnding = 'xlsx';\n\n exportToBlob(columns: (string | number | Date)[], rows: (string | number | Date)[][]): Blob {\n const worksheet = utils.aoa_to_sheet([columns, ...rows]);\n const workbook = utils.book_new();\n utils.book_append_sheet(workbook, worksheet, 'Sheet1');\n\n const data = write(workbook, { type: 'buffer' });\n return new Blob([data], {\n type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',\n });\n }\n}\n"],"mappings":";;AAGA,IAAqB,gBAArB,MAA2D;;EACzC,KAAA,OAAA;EACM,KAAA,aAAA;;CAEtB,aAAa,SAAqC,MAA0C;EAC1F,MAAM,YAAYA,KAAAA,MAAM,aAAa,CAAC,SAAS,GAAG,IAAI,CAAC;EACvD,MAAM,WAAWA,KAAAA,MAAM,SAAS;EAChC,KAAA,MAAM,kBAAkB,UAAU,WAAW,QAAQ;EAErD,MAAM,QAAA,GAAOC,KAAAA,MAAAA,CAAM,UAAU,EAAE,MAAM,SAAS,CAAC;EAC/C,OAAO,IAAI,KAAK,CAAC,IAAI,GAAG,EACtB,MAAM,oEACR,CAAC;CACH;AACF"}
1
+ {"version":3,"file":"excelExporter.cjs","names":["writeXlsxFile"],"sources":["../src/exporters/excelExporter.ts"],"sourcesContent":["import writeXlsxFile from 'write-excel-file/browser';\nimport type { BlobExporter } from './exporter';\n\nexport interface ExcelExporterOptions {\n /** Excel number format for date cells.\n * @default 'yyyy-mm-dd'\n */\n dateFormat?: string;\n /** @default 'Sheet1' */\n sheet?: string;\n}\n\nexport default class ExcelExporter implements BlobExporter {\n readonly type = 'xlsx';\n readonly fileEnding = 'xlsx';\n\n constructor(private readonly options: ExcelExporterOptions = {}) {}\n\n exportToBlob(\n columns: (string | number | Date)[],\n rows: (string | number | Date)[][],\n ): Promise<Blob> {\n const { dateFormat = 'yyyy-mm-dd', sheet = 'Sheet1' } = this.options;\n return writeXlsxFile([columns, ...rows], { sheet, dateFormat }).toBlob();\n }\n}\n"],"mappings":";;;;AAYA,IAAqB,gBAArB,MAA2D;CAIzD,YAAY,UAAiD,CAAC,GAAG;EAApC,KAAA,UAAA;EAHb,KAAA,OAAA;EACM,KAAA,aAAA;CAE4C;CAElE,aACE,SACA,MACe;EACf,MAAM,EAAE,aAAa,cAAc,QAAQ,aAAa,KAAK;EAC7D,QAAA,GAAOA,yBAAAA,QAAAA,CAAc,CAAC,SAAS,GAAG,IAAI,GAAG;GAAE;GAAO;EAAW,CAAC,CAAC,CAAC,OAAO;CACzE;AACF"}
@@ -1,9 +1,19 @@
1
- import { t as BlobExporter } from "./exporter-BT2ehIIU.cjs";
1
+ import { t as BlobExporter } from "./exporter-Dv2Vqqth.cjs";
2
2
  //#region src/exporters/excelExporter.d.ts
3
- declare class ExcelExporter implements BlobExporter {
3
+ export interface ExcelExporterOptions {
4
+ /** Excel number format for date cells.
5
+ * @default 'yyyy-mm-dd'
6
+ */
7
+ dateFormat?: string;
8
+ /** @default 'Sheet1' */
9
+ sheet?: string;
10
+ }
11
+ export default class ExcelExporter implements BlobExporter {
12
+ private readonly options;
4
13
  readonly type = "xlsx";
5
14
  readonly fileEnding = "xlsx";
6
- exportToBlob(columns: (string | number | Date)[], rows: (string | number | Date)[][]): Blob;
15
+ constructor(options?: ExcelExporterOptions);
16
+ exportToBlob(columns: (string | number | Date)[], rows: (string | number | Date)[][]): Promise<Blob>;
7
17
  }
8
- export = ExcelExporter;
18
+ //#endregion
9
19
  //# sourceMappingURL=excelExporter.d.cts.map
@@ -1,9 +1,19 @@
1
- import { t as BlobExporter } from "./exporter-BT2ehIIU.js";
1
+ import { t as BlobExporter } from "./exporter-Dv2Vqqth.js";
2
2
  //#region src/exporters/excelExporter.d.ts
3
+ export interface ExcelExporterOptions {
4
+ /** Excel number format for date cells.
5
+ * @default 'yyyy-mm-dd'
6
+ */
7
+ dateFormat?: string;
8
+ /** @default 'Sheet1' */
9
+ sheet?: string;
10
+ }
3
11
  export default class ExcelExporter implements BlobExporter {
12
+ private readonly options;
4
13
  readonly type = "xlsx";
5
14
  readonly fileEnding = "xlsx";
6
- exportToBlob(columns: (string | number | Date)[], rows: (string | number | Date)[][]): Blob;
15
+ constructor(options?: ExcelExporterOptions);
16
+ exportToBlob(columns: (string | number | Date)[], rows: (string | number | Date)[][]): Promise<Blob>;
7
17
  }
8
18
  //#endregion
9
19
  //# sourceMappingURL=excelExporter.d.ts.map
@@ -1,16 +1,17 @@
1
- import { utils, write } from "xlsx";
1
+ import writeXlsxFile from "write-excel-file/browser";
2
2
  //#region src/exporters/excelExporter.ts
3
3
  var ExcelExporter = class {
4
- constructor() {
4
+ constructor(options = {}) {
5
+ this.options = options;
5
6
  this.type = "xlsx";
6
7
  this.fileEnding = "xlsx";
7
8
  }
8
9
  exportToBlob(columns, rows) {
9
- const worksheet = utils.aoa_to_sheet([columns, ...rows]);
10
- const workbook = utils.book_new();
11
- utils.book_append_sheet(workbook, worksheet, "Sheet1");
12
- const data = write(workbook, { type: "buffer" });
13
- return new Blob([data], { type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" });
10
+ const { dateFormat = "yyyy-mm-dd", sheet = "Sheet1" } = this.options;
11
+ return writeXlsxFile([columns, ...rows], {
12
+ sheet,
13
+ dateFormat
14
+ }).toBlob();
14
15
  }
15
16
  };
16
17
  //#endregion
@@ -1 +1 @@
1
- {"version":3,"file":"excelExporter.js","names":[],"sources":["../src/exporters/excelExporter.ts"],"sourcesContent":["import { utils, write } from 'xlsx';\nimport { BlobExporter } from './exporter';\n\nexport default class ExcelExporter implements BlobExporter {\n readonly type = 'xlsx';\n readonly fileEnding = 'xlsx';\n\n exportToBlob(columns: (string | number | Date)[], rows: (string | number | Date)[][]): Blob {\n const worksheet = utils.aoa_to_sheet([columns, ...rows]);\n const workbook = utils.book_new();\n utils.book_append_sheet(workbook, worksheet, 'Sheet1');\n\n const data = write(workbook, { type: 'buffer' });\n return new Blob([data], {\n type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',\n });\n }\n}\n"],"mappings":";;AAGA,IAAqB,gBAArB,MAA2D;;EACzC,KAAA,OAAA;EACM,KAAA,aAAA;;CAEtB,aAAa,SAAqC,MAA0C;EAC1F,MAAM,YAAY,MAAM,aAAa,CAAC,SAAS,GAAG,IAAI,CAAC;EACvD,MAAM,WAAW,MAAM,SAAS;EAChC,MAAM,kBAAkB,UAAU,WAAW,QAAQ;EAErD,MAAM,OAAO,MAAM,UAAU,EAAE,MAAM,SAAS,CAAC;EAC/C,OAAO,IAAI,KAAK,CAAC,IAAI,GAAG,EACtB,MAAM,oEACR,CAAC;CACH;AACF"}
1
+ {"version":3,"file":"excelExporter.js","names":[],"sources":["../src/exporters/excelExporter.ts"],"sourcesContent":["import writeXlsxFile from 'write-excel-file/browser';\nimport type { BlobExporter } from './exporter';\n\nexport interface ExcelExporterOptions {\n /** Excel number format for date cells.\n * @default 'yyyy-mm-dd'\n */\n dateFormat?: string;\n /** @default 'Sheet1' */\n sheet?: string;\n}\n\nexport default class ExcelExporter implements BlobExporter {\n readonly type = 'xlsx';\n readonly fileEnding = 'xlsx';\n\n constructor(private readonly options: ExcelExporterOptions = {}) {}\n\n exportToBlob(\n columns: (string | number | Date)[],\n rows: (string | number | Date)[][],\n ): Promise<Blob> {\n const { dateFormat = 'yyyy-mm-dd', sheet = 'Sheet1' } = this.options;\n return writeXlsxFile([columns, ...rows], { sheet, dateFormat }).toBlob();\n }\n}\n"],"mappings":";;AAYA,IAAqB,gBAArB,MAA2D;CAIzD,YAAY,UAAiD,CAAC,GAAG;EAApC,KAAA,UAAA;EAHb,KAAA,OAAA;EACM,KAAA,aAAA;CAE4C;CAElE,aACE,SACA,MACe;EACf,MAAM,EAAE,aAAa,cAAc,QAAQ,aAAa,KAAK;EAC7D,OAAO,cAAc,CAAC,SAAS,GAAG,IAAI,GAAG;GAAE;GAAO;EAAW,CAAC,CAAC,CAAC,OAAO;CACzE;AACF"}
@@ -6,7 +6,7 @@ interface StringExporter {
6
6
  interface BlobExporter {
7
7
  type: string;
8
8
  fileEnding: string;
9
- exportToBlob(columns: (string | number | Date)[], rows: (string | number | Date)[][]): Blob;
9
+ exportToBlob(columns: (string | number | Date)[], rows: (string | number | Date)[][]): Blob | Promise<Blob>;
10
10
  }
11
11
  type ExporterEntry = {
12
12
  action: 'copy';
@@ -21,4 +21,4 @@ interface ExportOptions {
21
21
  }
22
22
  //#endregion
23
23
  export { StringExporter as i, ExportOptions as n, ExporterEntry as r, BlobExporter as t };
24
- //# sourceMappingURL=exporter-BT2ehIIU.d.ts.map
24
+ //# sourceMappingURL=exporter-Dv2Vqqth.d.cts.map
@@ -6,7 +6,7 @@ interface StringExporter {
6
6
  interface BlobExporter {
7
7
  type: string;
8
8
  fileEnding: string;
9
- exportToBlob(columns: (string | number | Date)[], rows: (string | number | Date)[][]): Blob;
9
+ exportToBlob(columns: (string | number | Date)[], rows: (string | number | Date)[][]): Blob | Promise<Blob>;
10
10
  }
11
11
  type ExporterEntry = {
12
12
  action: 'copy';
@@ -21,4 +21,4 @@ interface ExportOptions {
21
21
  }
22
22
  //#endregion
23
23
  export { StringExporter as i, ExportOptions as n, ExporterEntry as r, BlobExporter as t };
24
- //# sourceMappingURL=exporter-BT2ehIIU.d.cts.map
24
+ //# sourceMappingURL=exporter-Dv2Vqqth.d.ts.map
package/dist/index.cjs CHANGED
@@ -1,41 +1,11 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
- //#region \0rolldown/runtime.js
3
- var __create = Object.create;
4
- var __defProp = Object.defineProperty;
5
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
6
- var __getOwnPropNames = Object.getOwnPropertyNames;
7
- var __getProtoOf = Object.getPrototypeOf;
8
- var __hasOwnProp = Object.prototype.hasOwnProperty;
9
- var __exportAll = (all, no_symbols) => {
10
- let target = {};
11
- for (var name in all) __defProp(target, name, {
12
- get: all[name],
13
- enumerable: true
14
- });
15
- if (!no_symbols) __defProp(target, Symbol.toStringTag, { value: "Module" });
16
- return target;
17
- };
18
- var __copyProps = (to, from, except, desc) => {
19
- if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
20
- key = keys[i];
21
- if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
22
- get: ((k) => from[k]).bind(null, key),
23
- enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
24
- });
25
- }
26
- return to;
27
- };
28
- var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule || !__hasOwnProp.call(mod, "default") ? __defProp(target, "default", {
29
- value: mod,
30
- enumerable: true
31
- }) : target, mod));
32
- //#endregion
2
+ const require_rolldown_runtime = require("./rolldown-runtime-C0BPl7ul.cjs");
33
3
  const require_tableTheme = require("./tableTheme-CSqMIpLB.cjs");
34
4
  let react = require("react");
35
5
  let _emotion_react_jsx_runtime = require("@emotion/react/jsx-runtime");
36
6
  let _emotion_react = require("@emotion/react");
37
7
  let _emotion_cache = require("@emotion/cache");
38
- _emotion_cache = __toESM(_emotion_cache, 1);
8
+ _emotion_cache = require_rolldown_runtime.__toESM(_emotion_cache, 1);
39
9
  let _emotion_serialize = require("@emotion/serialize");
40
10
  let _emotion_utils = require("@emotion/utils");
41
11
  let react_dom = require("react-dom");
@@ -191,7 +161,7 @@ const Button = ({ startIcon, children, variant = "text", ...props }) => {
191
161
  };
192
162
  //#endregion
193
163
  //#region src/misc/helpers.ts
194
- var helpers_exports = /* @__PURE__ */ __exportAll({
164
+ var helpers_exports = /* @__PURE__ */ require_rolldown_runtime.__exportAll({
195
165
  asNumber: () => asNumber,
196
166
  asNumberOrArray: () => asNumberOrArray,
197
167
  asString: () => asString,
@@ -269,8 +239,9 @@ const getDescendants = (...items) => {
269
239
  const identity$1 = (x) => x;
270
240
  const asString = (x) => {
271
241
  if (Array.isArray(x)) return x.map(asString).join(", ");
242
+ if (x === null || x === void 0) return "";
272
243
  if (x instanceof Object) return JSON.stringify(x);
273
- return String(x ?? "");
244
+ return String(x);
274
245
  };
275
246
  const asStringOrArray = (x) => {
276
247
  if (Array.isArray(x)) return x.map(asString);
@@ -2109,18 +2080,20 @@ const isActiveFilter = (filter, value) => filter !== void 0 && value !== void 0
2109
2080
  function filteredColumns(props, visibleColumns) {
2110
2081
  return props.enableHiddenColumnFilters ? props.columns : visibleColumns;
2111
2082
  }
2083
+ /** Adds controlled values and defaults. Returns `stored` itself when there are none. */
2084
+ function withFilterDefaults(stored, columns) {
2085
+ let result = stored;
2086
+ for (const { id, filter } of columns) {
2087
+ const value = filter?.value !== void 0 || stored.has(id) ? filter?.value : filter?.defaultValue;
2088
+ if (value === void 0) continue;
2089
+ if (result === stored) result = new Map(stored);
2090
+ result.set(id, value);
2091
+ }
2092
+ return result;
2093
+ }
2112
2094
  function useFilters(props, visibleColumns, items) {
2113
2095
  const [stored, setFilterValues, setFilterValuesInternal] = useControllableState(props.filterValues, () => props.defaultFilterValues ?? /* @__PURE__ */ new Map(), props.onFilterValuesChange);
2114
- const filterValues = (0, react.useMemo)(() => {
2115
- let result = stored;
2116
- for (const { id, filter } of props.columns) {
2117
- const value = filter?.value !== void 0 || stored.has(id) ? filter?.value : filter?.defaultValue;
2118
- if (value === void 0) continue;
2119
- if (result === stored) result = new Map(stored);
2120
- result.set(id, value);
2121
- }
2122
- return result;
2123
- }, [stored, props.columns]);
2096
+ const filterValues = (0, react.useMemo)(() => withFilterDefaults(stored, props.columns), [stored, props.columns]);
2124
2097
  const applied = filteredColumns(props, visibleColumns);
2125
2098
  return {
2126
2099
  stored,
@@ -2388,7 +2361,7 @@ const defaultProps = {
2388
2361
  } }
2389
2362
  };
2390
2363
  const identity = (value) => value;
2391
- const defaultSortBy = (v) => typeof v === "number" || v instanceof Date ? v : v === null || v === void 0 ? "" : String(v);
2364
+ const defaultSortBy = (v) => typeof v === "number" || v instanceof Date ? v : asString(v);
2392
2365
  function normalizeId(id) {
2393
2366
  return id instanceof Function ? id : (item) => item[id];
2394
2367
  }
@@ -3545,9 +3518,10 @@ function Export() {
3545
3518
  const rows = exportedItems.map((item) => activeColumns.map((column) => column.exportCell(column.value(item.value), item.value)));
3546
3519
  if (action === "copy") {
3547
3520
  const data = exporter.exportToString(columns, rows);
3548
- navigator.clipboard.writeText(data);
3549
- } else {
3550
- const blob = exporter.exportToBlob(columns, rows);
3521
+ navigator.clipboard.writeText(data).catch((error) => {
3522
+ console.error("Failed to copy the export to the clipboard:", error);
3523
+ });
3524
+ } else Promise.resolve(exporter.exportToBlob(columns, rows)).then((blob) => {
3551
3525
  const url = URL.createObjectURL(blob);
3552
3526
  const a = document.createElement("a");
3553
3527
  a.href = url;
@@ -3556,7 +3530,9 @@ function Export() {
3556
3530
  a.click();
3557
3531
  a.remove();
3558
3532
  URL.revokeObjectURL(url);
3559
- }
3533
+ }).catch((error) => {
3534
+ console.error("Failed to export:", error);
3535
+ });
3560
3536
  }
3561
3537
  return /* @__PURE__ */ (0, _emotion_react_jsx_runtime.jsxs)(_emotion_react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, _emotion_react_jsx_runtime.jsx)(IconButton, {
3562
3538
  onClick: (event) => setAnchor(anchor ? null : event.currentTarget),
@@ -3746,6 +3722,7 @@ function useScrollRoot(tableRef, probe) {
3746
3722
  return root;
3747
3723
  }
3748
3724
  function VirtualWindow({ virtualizer, renderRow, measure }) {
3725
+ "use no memo";
3749
3726
  const items = virtualizer.getVirtualItems();
3750
3727
  const scheduler = (0, react.useContext)(CellSchedulerContext);
3751
3728
  (0, react.useLayoutEffect)(() => {
@@ -3777,6 +3754,7 @@ function virtualizerOptions({ count, getKey, options, scrollMargin }) {
3777
3754
  };
3778
3755
  }
3779
3756
  function ElementRows(props) {
3757
+ "use no memo";
3780
3758
  const virtualizer = (0, _tanstack_react_virtual.useVirtualizer)({
3781
3759
  ...virtualizerOptions(props),
3782
3760
  getScrollElement: () => props.root
@@ -3788,6 +3766,7 @@ function ElementRows(props) {
3788
3766
  });
3789
3767
  }
3790
3768
  function WindowRows(props) {
3769
+ "use no memo";
3791
3770
  const virtualizer = (0, _tanstack_react_virtual.useWindowVirtualizer)(virtualizerOptions(props));
3792
3771
  return /* @__PURE__ */ (0, _emotion_react_jsx_runtime.jsx)(VirtualWindow, {
3793
3772
  virtualizer,