@allxsmith/bestax-bulma 5.54.1 → 5.56.0

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.
Files changed (87) hide show
  1. package/dist/bestax.css +1 -1
  2. package/dist/bestax.css.map +1 -1
  3. package/dist/esm/components/Command.js +22 -22
  4. package/dist/esm/components/Command.js.map +1 -1
  5. package/dist/esm/components/DataTable.js +215 -0
  6. package/dist/esm/components/DataTable.js.map +1 -0
  7. package/dist/esm/components/useDataTable.js +509 -0
  8. package/dist/esm/components/useDataTable.js.map +1 -0
  9. package/dist/esm/elements/ColorSwatch.js +49 -0
  10. package/dist/esm/elements/ColorSwatch.js.map +1 -0
  11. package/dist/esm/elements/RingProgress.js +3 -3
  12. package/dist/esm/elements/Td.js +4 -2
  13. package/dist/esm/elements/Td.js.map +1 -1
  14. package/dist/esm/elements/Th.js +13 -5
  15. package/dist/esm/elements/Th.js.map +1 -1
  16. package/dist/esm/elements/Tr.js.map +1 -1
  17. package/dist/esm/form/ColorInput.js +68 -0
  18. package/dist/esm/form/ColorInput.js.map +1 -0
  19. package/dist/esm/form/ColorInputBase.js +198 -0
  20. package/dist/esm/form/ColorInputBase.js.map +1 -0
  21. package/dist/esm/form/ColorPicker.js +524 -0
  22. package/dist/esm/form/ColorPicker.js.map +1 -0
  23. package/dist/esm/form/Combobox.js +18 -18
  24. package/dist/esm/form/Combobox.js.map +1 -1
  25. package/dist/esm/form/Dropzone.js +524 -0
  26. package/dist/esm/form/Dropzone.js.map +1 -0
  27. package/dist/esm/form/_colorInternals/EyeDropperButton.js +40 -0
  28. package/dist/esm/form/_colorInternals/EyeDropperButton.js.map +1 -0
  29. package/dist/esm/form/_colorInternals/colorMath.js +292 -0
  30. package/dist/esm/form/_colorInternals/colorMath.js.map +1 -0
  31. package/dist/esm/form/_colorInternals/pickerState.js +160 -0
  32. package/dist/esm/form/_colorInternals/pickerState.js.map +1 -0
  33. package/dist/esm/helpers/statusRegion.js +3 -3
  34. package/dist/esm/helpers/statusRegion.js.map +1 -1
  35. package/dist/esm/helpers/useFocusTrap.js +2 -2
  36. package/dist/extras.css +1 -1
  37. package/dist/extras.css.map +1 -1
  38. package/dist/index.cjs +3054 -586
  39. package/dist/index.cjs.map +1 -1
  40. package/dist/index.esm.js +7 -0
  41. package/dist/index.esm.js.map +1 -1
  42. package/dist/types/components/DataTable.d.ts +120 -0
  43. package/dist/types/components/useDataTable.d.ts +481 -0
  44. package/dist/types/elements/ColorSwatch.d.ts +54 -0
  45. package/dist/types/elements/Td.d.ts +9 -1
  46. package/dist/types/elements/Th.d.ts +14 -2
  47. package/dist/types/elements/Tr.d.ts +10 -1
  48. package/dist/types/form/ColorInput.d.ts +76 -0
  49. package/dist/types/form/ColorInputBase.d.ts +108 -0
  50. package/dist/types/form/ColorPicker.d.ts +271 -0
  51. package/dist/types/form/Dropzone.d.ts +138 -0
  52. package/dist/types/form/_colorInternals/EyeDropperButton.d.ts +8 -0
  53. package/dist/types/form/_colorInternals/colorMath.d.ts +63 -0
  54. package/dist/types/form/_colorInternals/pickerState.d.ts +68 -0
  55. package/dist/types/index.d.ts +8 -0
  56. package/dist/types-cjs/components/DataTable.d.ts +120 -0
  57. package/dist/types-cjs/components/useDataTable.d.ts +481 -0
  58. package/dist/types-cjs/elements/ColorSwatch.d.ts +54 -0
  59. package/dist/types-cjs/elements/Td.d.ts +9 -1
  60. package/dist/types-cjs/elements/Th.d.ts +14 -2
  61. package/dist/types-cjs/elements/Tr.d.ts +10 -1
  62. package/dist/types-cjs/form/ColorInput.d.ts +76 -0
  63. package/dist/types-cjs/form/ColorInputBase.d.ts +108 -0
  64. package/dist/types-cjs/form/ColorPicker.d.ts +271 -0
  65. package/dist/types-cjs/form/Dropzone.d.ts +138 -0
  66. package/dist/types-cjs/form/_colorInternals/EyeDropperButton.d.ts +8 -0
  67. package/dist/types-cjs/form/_colorInternals/colorMath.d.ts +63 -0
  68. package/dist/types-cjs/form/_colorInternals/pickerState.d.ts +68 -0
  69. package/dist/types-cjs/index.d.ts +8 -0
  70. package/dist/versions/bestax-no-dark-mode.css +1 -1
  71. package/dist/versions/bestax-no-dark-mode.css.map +1 -1
  72. package/dist/versions/bestax-no-helpers-prefixed.css +1 -1
  73. package/dist/versions/bestax-no-helpers-prefixed.css.map +1 -1
  74. package/dist/versions/bestax-no-helpers.css +1 -1
  75. package/dist/versions/bestax-no-helpers.css.map +1 -1
  76. package/dist/versions/bestax-prefixed.css +1 -1
  77. package/dist/versions/bestax-prefixed.css.map +1 -1
  78. package/package.json +1 -1
  79. package/src/scss/components/_datatable.scss +152 -0
  80. package/src/scss/components/_index.scss +1 -0
  81. package/src/scss/elements/_colorswatch.scss +100 -0
  82. package/src/scss/elements/_index.scss +1 -0
  83. package/src/scss/form/_checkbox.scss +53 -0
  84. package/src/scss/form/_colorinput.scss +109 -0
  85. package/src/scss/form/_colorpicker.scss +354 -0
  86. package/src/scss/form/_dropzone.scss +233 -0
  87. package/src/scss/form/_index.scss +3 -0
@@ -0,0 +1,509 @@
1
+ /* @allxsmith/bestax-bulma — AI agents: see AGENTS.md in the package root, or https://bestax.io/llms.txt */
2
+ import { useMemo, useCallback, useState, useRef } from 'react';
3
+ import { prefixedClassNames } from '../helpers/classNames.js';
4
+ import { useClassPrefix } from '../helpers/Config.js';
5
+ import { warnOnce, isDev } from '../helpers/devWarnings.js';
6
+ import { useLocale } from '../helpers/LocaleProvider.js';
7
+ import { useLocaleMatcher, useNumberFormat } from '../helpers/localeFormat.js';
8
+ import { useClientLayoutEffect } from '../helpers/useClientLayoutEffect.js';
9
+ import { useLatestRef } from '../helpers/useLatestRef.js';
10
+
11
+ /** A column's raw value for a row. */
12
+ function readValue(column, row) {
13
+ const { accessor } = column;
14
+ if (typeof accessor === 'function')
15
+ return accessor(row);
16
+ if (row === null || typeof row !== 'object')
17
+ return undefined;
18
+ return row[(accessor ?? column.id)];
19
+ }
20
+ /** A column's text for a row. */
21
+ function readText(column, row) {
22
+ const value = readValue(column, row);
23
+ if (column.format)
24
+ return column.format(value, row);
25
+ return value === null || value === undefined ? '' : String(value);
26
+ }
27
+ /** Whether a value sorts as empty: nothing, no text, or no number or date. */
28
+ function isEmptyValue(value) {
29
+ return (value === null ||
30
+ value === undefined ||
31
+ value === '' ||
32
+ (typeof value === 'number' && Number.isNaN(value)) ||
33
+ (value instanceof Date && Number.isNaN(value.getTime())));
34
+ }
35
+ /** Compares two values that aren't empty, for an ascending sort. */
36
+ function compareValues(a, b, collator) {
37
+ if (typeof a === 'number' && typeof b === 'number')
38
+ return a - b;
39
+ if (a instanceof Date && b instanceof Date)
40
+ return a.getTime() - b.getTime();
41
+ if (typeof a === 'boolean' && typeof b === 'boolean') {
42
+ return Number(a) - Number(b);
43
+ }
44
+ return collator.compare(String(a), String(b));
45
+ }
46
+ /** Whether a filter value filters anything. */
47
+ function isActiveFilter(value) {
48
+ return (value !== undefined &&
49
+ value !== null &&
50
+ value !== '' &&
51
+ !(Array.isArray(value) && value.length === 0));
52
+ }
53
+ /** A field a spreadsheet would read as the start of a formula. */
54
+ const formulaStart = /^[=+\-@\t\r]/;
55
+ /** A plain number, signed, with any grouping, which no spreadsheet runs. */
56
+ const plainNumber = /^[+-]?\d[\d.,]*$/;
57
+ /**
58
+ * One CSV field: a `'` in front of what would start a formula, then quoted
59
+ * when it holds the delimiter, a quote or a line break, its quotes doubled.
60
+ */
61
+ function csvField(text, delimiter) {
62
+ const safe = formulaStart.test(text) && !plainNumber.test(text) ? `'${text}` : text;
63
+ return safe.includes(delimiter) || /["\r\n]/.test(safe)
64
+ ? `"${safe.replace(/"/g, '""')}"`
65
+ : safe;
66
+ }
67
+ /**
68
+ * Whether a search or a filter value is narrowing the rows. Used by
69
+ * DataTable to tell an empty table from one with no matches.
70
+ */
71
+ function isFiltering(search, filters) {
72
+ return search.trim() !== '' || Object.values(filters).some(isActiveFilter);
73
+ }
74
+ /** A row's id from its `id` property, or nothing when it has none. */
75
+ function idOf(row) {
76
+ if (row === null || typeof row !== 'object')
77
+ return undefined;
78
+ const id = row.id;
79
+ return id === undefined || id === null || id === '' ? undefined : String(id);
80
+ }
81
+ /**
82
+ * A piece of state that's the caller's when they pass its value, and the
83
+ * table's own otherwise. Setting it calls the change handler either way.
84
+ *
85
+ * It also returns `latest`, what a change should build on. While the table
86
+ * holds the state, that's the value last set, even before React renders it,
87
+ * so two changes in one handler build on each other. While the caller holds
88
+ * it, it's the value as rendered, since only the caller knows what it made
89
+ * of a change.
90
+ */
91
+ function useTableState(value, initial, onChange) {
92
+ const [own, setOwn] = useState(initial);
93
+ const held = value !== undefined;
94
+ const current = held ? value : own;
95
+ const rendered = useLatestRef(current);
96
+ // A value set since the last commit, cleared once a commit shows it.
97
+ const pendingRef = useRef(null);
98
+ useClientLayoutEffect(() => {
99
+ pendingRef.current = null;
100
+ });
101
+ const set = useCallback((next) => {
102
+ if (!held) {
103
+ pendingRef.current = { value: next };
104
+ setOwn(next);
105
+ }
106
+ onChange?.(next);
107
+ }, [held, onChange]);
108
+ const latest = useCallback(() => (pendingRef.current ? pendingRef.current.value : rendered.current), [rendered]);
109
+ return [current, set, latest];
110
+ }
111
+ const noSort = [];
112
+ const noIds = [];
113
+ const noFilters = {};
114
+ /**
115
+ * `useDataTable` holds a table's sort, selection, page, search and filters,
116
+ * works out its rows, and hands out props for bestax's own table parts, so
117
+ * custom markup behaves as `DataTable` does. Pass its result to
118
+ * `<DataTable table={table} />` to render it with DataTable's own markup,
119
+ * with a toolbar or an export button elsewhere on the page.
120
+ *
121
+ * @example
122
+ * const table = useDataTable({ columns, data: users, pageSize: 10 });
123
+ *
124
+ * <DataTable table={table} caption="Users" hasSearch />
125
+ */
126
+ function useDataTable(options) {
127
+ const { columns, data, getRowId: rowIdOf, sort: sortProp, defaultSort = noSort, onSortChange, selectionMode = 'none', selected: selectedProp, defaultSelected = noIds, onSelectedChange, pageSize: pageSizeProp, page: pageProp, defaultPage = 1, onPageChange, search: searchProp, defaultSearch = '', onSearchChange, filters: filtersProp, defaultFilters = noFilters, onFiltersChange, manual = false, rowCount: rowCountProp, labels, } = options;
128
+ const [sort, setSort] = useTableState(sortProp, defaultSort, onSortChange);
129
+ const [selected, setSelected, latestSelected] = useTableState(selectedProp, defaultSelected, onSelectedChange);
130
+ const [pageState, setPageState, latestPage] = useTableState(pageProp, defaultPage, onPageChange);
131
+ const [search, setSearchState] = useTableState(searchProp, defaultSearch, onSearchChange);
132
+ const [filters, setFiltersState, latestFilters] = useTableState(filtersProp, defaultFilters, onFiltersChange);
133
+ const prefix = useClassPrefix();
134
+ const { locale } = useLocale();
135
+ const matchText = useLocaleMatcher();
136
+ const formatNumber = useNumberFormat();
137
+ const collator = useMemo(() => new Intl.Collator(locale, { numeric: true }), [locale]);
138
+ const pageSize = pageSizeProp !== undefined &&
139
+ Number.isFinite(pageSizeProp) &&
140
+ pageSizeProp >= 1
141
+ ? Math.floor(pageSizeProp)
142
+ : undefined;
143
+ const columnsById = useMemo(() => {
144
+ const byId = new Map();
145
+ for (const column of columns) {
146
+ if (byId.has(column.id)) {
147
+ warnOnce('DataTable:duplicate-column', `[bestax-bulma] DataTable has two columns with the id "${column.id}". ` +
148
+ 'Give each column its own id: the sort, the filters and an export ' +
149
+ 'find a column by it.');
150
+ }
151
+ else {
152
+ byId.set(column.id, column);
153
+ }
154
+ }
155
+ return byId;
156
+ }, [columns]);
157
+ // Each row's id, by its index in `data`.
158
+ const ids = useMemo(() => {
159
+ const out = data.map((row, index) => {
160
+ const id = rowIdOf ? rowIdOf(row, index) : idOf(row);
161
+ if (id === undefined || id === '') {
162
+ warnOnce('DataTable:missing-row-id', '[bestax-bulma] A DataTable row has no id, so it falls back to its ' +
163
+ "index, which doesn't survive the data changing. Give each row " +
164
+ 'an `id`, or pass `getRowId`.');
165
+ return String(index);
166
+ }
167
+ return id;
168
+ });
169
+ if (isDev() && new Set(out).size < out.length) {
170
+ warnOnce('DataTable:duplicate-row-id', '[bestax-bulma] Two DataTable rows have the same id, so selecting ' +
171
+ 'one selects both. Make the ids unique, or pass a `getRowId` ' +
172
+ 'that does.');
173
+ }
174
+ return out;
175
+ }, [data, rowIdOf]);
176
+ const indexOf = useMemo(() => {
177
+ const map = new Map();
178
+ data.forEach((row, index) => {
179
+ if (!map.has(row))
180
+ map.set(row, index);
181
+ });
182
+ return map;
183
+ }, [data]);
184
+ /** A row's id, from its index when the row is one of `data`. */
185
+ const getRowId = useCallback((row) => {
186
+ const index = indexOf.get(row);
187
+ if (index !== undefined)
188
+ return ids[index];
189
+ const id = rowIdOf ? rowIdOf(row, -1) : idOf(row);
190
+ return id ?? '';
191
+ }, [indexOf, ids, rowIdOf]);
192
+ // Every column's text for every row, worked out once per data and
193
+ // columns, since the search reads them on every keystroke.
194
+ const texts = useMemo(() => data.map(row => columns.map(column => readText(column, row))), [data, columns]);
195
+ const sortedIndexes = useMemo(() => {
196
+ const all = data.map((_, index) => index);
197
+ if (manual)
198
+ return all;
199
+ const keys = sort
200
+ .map(entry => ({
201
+ column: columnsById.get(entry.id),
202
+ descending: entry.direction === 'descending',
203
+ }))
204
+ .filter((key) => key.column !== undefined);
205
+ if (keys.length === 0)
206
+ return all;
207
+ const values = keys.map(({ column }) => column.sortFn ? null : data.map(row => readValue(column, row)));
208
+ return all.sort((x, y) => {
209
+ for (let k = 0; k < keys.length; k++) {
210
+ const { column, descending } = keys[k];
211
+ let result;
212
+ if (column.sortFn) {
213
+ result = column.sortFn(data[x], data[y]);
214
+ if (descending)
215
+ result = -result;
216
+ }
217
+ else {
218
+ const a = values[k][x];
219
+ const b = values[k][y];
220
+ const aEmpty = isEmptyValue(a);
221
+ const bEmpty = isEmptyValue(b);
222
+ if (aEmpty || bEmpty) {
223
+ // Empty values go last whichever way the column sorts.
224
+ result = Number(aEmpty) - Number(bEmpty);
225
+ }
226
+ else {
227
+ result = compareValues(a, b, collator);
228
+ if (descending)
229
+ result = -result;
230
+ }
231
+ }
232
+ if (result)
233
+ return result;
234
+ }
235
+ // Ties keep the order of `data`.
236
+ return x - y;
237
+ });
238
+ }, [data, sort, columnsById, collator, manual]);
239
+ const filteredIndexes = useMemo(() => {
240
+ if (manual)
241
+ return sortedIndexes;
242
+ const query = search.trim();
243
+ const holds = matchText
244
+ ? (text, needle) => matchText(text, needle)
245
+ : (text, needle) => text.toLowerCase().includes(needle.toLowerCase());
246
+ const searched = columns
247
+ .map((column, index) => ({ column, index }))
248
+ .filter(({ column }) => column.filterable !== false);
249
+ const filtered = Object.entries(filters)
250
+ .filter(([, value]) => isActiveFilter(value))
251
+ .map(([id, value]) => ({
252
+ column: columnsById.get(id),
253
+ index: columns.findIndex(column => column.id === id),
254
+ value,
255
+ }))
256
+ .filter(({ column }) => column !== undefined && column.filterable !== false);
257
+ if (query === '' && filtered.length === 0)
258
+ return sortedIndexes;
259
+ return sortedIndexes.filter(rowIndex => {
260
+ const row = data[rowIndex];
261
+ const rowTexts = texts[rowIndex];
262
+ for (const { column, index, value } of filtered) {
263
+ // An array is any of its entries, as a multiple-choice filter gives.
264
+ const passes = column.filterFn
265
+ ? column.filterFn(row, value)
266
+ : Array.isArray(value)
267
+ ? value.some(entry => holds(rowTexts[index], String(entry)))
268
+ : holds(rowTexts[index], String(value));
269
+ if (!passes)
270
+ return false;
271
+ }
272
+ return (query === '' ||
273
+ searched.some(({ index }) => holds(rowTexts[index], query)));
274
+ });
275
+ }, [
276
+ manual,
277
+ sortedIndexes,
278
+ search,
279
+ filters,
280
+ matchText,
281
+ columns,
282
+ columnsById,
283
+ data,
284
+ texts,
285
+ ]);
286
+ const knowsCount = rowCountProp !== undefined && Number.isFinite(rowCountProp);
287
+ if (manual && pageSize !== undefined && !knowsCount) {
288
+ warnOnce('DataTable:manual-row-count', '[bestax-bulma] A DataTable with `manual` and a `pageSize` has no ' +
289
+ '`rowCount`, so it counts only the rows in `data`, makes one page ' +
290
+ 'of them and shows no pager. Pass `rowCount`, how many rows match ' +
291
+ 'on the server.');
292
+ }
293
+ const rowCount = manual
294
+ ? Math.max(Math.floor(knowsCount ? rowCountProp : data.length), 0)
295
+ : filteredIndexes.length;
296
+ const pageCount = pageSize ? Math.max(Math.ceil(rowCount / pageSize), 1) : 1;
297
+ const page = Math.min(Math.max(Number.isFinite(pageState) ? Math.floor(pageState) : 1, 1), pageCount);
298
+ const pageIndexes = useMemo(() => {
299
+ if (manual || !pageSize)
300
+ return filteredIndexes;
301
+ return filteredIndexes.slice((page - 1) * pageSize, page * pageSize);
302
+ }, [manual, pageSize, filteredIndexes, page]);
303
+ const selectedSet = useMemo(() => new Set(selected), [selected]);
304
+ const selectable = selectionMode === 'multiple';
305
+ const rowsOf = useCallback((indexes) => indexes.map(index => data[index]), [data]);
306
+ const getRows = useCallback((scope = 'filtered') => {
307
+ switch (scope) {
308
+ case 'all':
309
+ return rowsOf(sortedIndexes);
310
+ case 'page':
311
+ return rowsOf(pageIndexes);
312
+ case 'selected':
313
+ return rowsOf(filteredIndexes.filter(index => selectedSet.has(ids[index])));
314
+ default:
315
+ return rowsOf(filteredIndexes);
316
+ }
317
+ }, [rowsOf, sortedIndexes, pageIndexes, filteredIndexes, selectedSet, ids]);
318
+ const getValue = useCallback((row, columnId) => {
319
+ const column = columnsById.get(columnId);
320
+ return column ? readValue(column, row) : undefined;
321
+ }, [columnsById]);
322
+ const getText = useCallback((row, columnId) => {
323
+ const column = columnsById.get(columnId);
324
+ if (!column)
325
+ return '';
326
+ const index = indexOf.get(row);
327
+ return index !== undefined
328
+ ? texts[index][columns.indexOf(column)]
329
+ : readText(column, row);
330
+ }, [columnsById, indexOf, columns, texts]);
331
+ const labelColumn = columns.find(column => column.isRowHeader) ?? columns[0];
332
+ const getRowLabel = useCallback((row) => (labelColumn && getText(row, labelColumn.id)) || getRowId(row), [labelColumn, getText, getRowId]);
333
+ const isSelected = useCallback((row) => selectable && selectedSet.has(getRowId(row)), [selectable, selectedSet, getRowId]);
334
+ const setPage = useCallback((next) => {
335
+ if (next !== page)
336
+ setPageState(next);
337
+ }, [page, setPageState]);
338
+ // A new search or filter starts from the first page. It's measured against
339
+ // the page as stored, not as shown: a page past the end shows the last,
340
+ // and left stored it would come back once the rows grew again.
341
+ const resetPage = useCallback(() => {
342
+ if (latestPage() !== 1)
343
+ setPageState(1);
344
+ }, [latestPage, setPageState]);
345
+ const setSearch = useCallback((next) => {
346
+ setSearchState(next);
347
+ resetPage();
348
+ }, [setSearchState, resetPage]);
349
+ const setFilters = useCallback((next) => {
350
+ setFiltersState(next);
351
+ resetPage();
352
+ }, [setFiltersState, resetPage]);
353
+ const setFilter = useCallback((columnId, value) => {
354
+ const next = { ...latestFilters() };
355
+ if (isActiveFilter(value))
356
+ next[columnId] = value;
357
+ else
358
+ delete next[columnId];
359
+ setFilters(next);
360
+ }, [latestFilters, setFilters]);
361
+ const toggleSort = useCallback((columnId) => {
362
+ const column = columnsById.get(columnId);
363
+ if (!column)
364
+ return;
365
+ const first = column.sortDescFirst
366
+ ? 'descending'
367
+ : 'ascending';
368
+ const current = sort[0]?.id === columnId ? sort[0].direction : undefined;
369
+ if (current === undefined) {
370
+ setSort([{ id: columnId, direction: first }]);
371
+ }
372
+ else if (current === first) {
373
+ setSort([
374
+ {
375
+ id: columnId,
376
+ direction: first === 'ascending' ? 'descending' : 'ascending',
377
+ },
378
+ ]);
379
+ }
380
+ else {
381
+ setSort([]);
382
+ }
383
+ }, [columnsById, sort, setSort]);
384
+ const toggleRowSelected = useCallback((row, value) => {
385
+ const id = getRowId(row);
386
+ const current = latestSelected();
387
+ const has = current.includes(id);
388
+ const on = value ?? !has;
389
+ if (on === has)
390
+ return;
391
+ setSelected(on ? [...current, id] : current.filter(s => s !== id));
392
+ }, [getRowId, latestSelected, setSelected]);
393
+ const pageIds = useMemo(() => pageIndexes.map(index => ids[index]), [pageIndexes, ids]);
394
+ const pageSelectedCount = pageIds.filter(id => selectedSet.has(id)).length;
395
+ const allPageSelected = pageIds.length > 0 && pageSelectedCount === pageIds.length;
396
+ const togglePageSelected = useCallback((value) => {
397
+ const current = latestSelected();
398
+ const has = new Set(current);
399
+ const on = value ?? !(pageIds.length > 0 && pageIds.every(id => has.has(id)));
400
+ if (on) {
401
+ const adding = pageIds.filter(id => !has.has(id));
402
+ if (adding.length > 0)
403
+ setSelected([...current, ...adding]);
404
+ }
405
+ else {
406
+ const onPage = new Set(pageIds);
407
+ const kept = current.filter(id => !onPage.has(id));
408
+ if (kept.length !== current.length)
409
+ setSelected(kept);
410
+ }
411
+ }, [latestSelected, pageIds, setSelected]);
412
+ const count = useCallback((value) => (formatNumber ? formatNumber(value) : String(value)), [formatNumber]);
413
+ const resolvedLabels = {
414
+ selectAll: labels?.selectAll ||
415
+ (pageCount > 1 ? 'Select all rows on this page' : 'Select all rows'),
416
+ selectRow: labels?.selectRow ?? (label => `Select ${label}`),
417
+ sortHint: labels?.sortHint || 'column headers with buttons are sortable',
418
+ search: labels?.search || 'Search',
419
+ results: labels?.results ??
420
+ (total => total === 0
421
+ ? 'No rows match'
422
+ : `${count(total)} ${total === 1 ? 'row matches' : 'rows match'}`),
423
+ pageRange: labels?.pageRange ??
424
+ ((first, last, total) => `Showing ${count(first)} to ${count(last)} of ${count(total)}`),
425
+ loading: labels?.loading || 'Loading',
426
+ pagination: labels?.pagination || undefined,
427
+ empty: labels?.empty || 'No rows to show.',
428
+ noResults: labels?.noResults || 'No rows match.',
429
+ };
430
+ const toCSV = useCallback(({ rows = 'filtered', columns: ids, header = true, delimiter = ',', } = {}) => {
431
+ const written = ids
432
+ ? ids
433
+ .map(id => columnsById.get(id))
434
+ .filter((column) => column !== undefined)
435
+ : columns;
436
+ const line = (fields) => fields.map(field => csvField(field, delimiter)).join(delimiter);
437
+ const lines = getRows(rows).map(row => line(written.map(column => getText(row, column.id))));
438
+ if (header)
439
+ lines.unshift(line(written.map(column => column.header)));
440
+ return lines.join('\r\n');
441
+ }, [columnsById, columns, getRows, getText]);
442
+ const sortButtonClass = prefixedClassNames(prefix, 'data-table-sort');
443
+ return {
444
+ columns,
445
+ state: { sort, selected, page, pageSize, search, filters },
446
+ selectionMode,
447
+ manual,
448
+ rowCount,
449
+ pageCount,
450
+ labels: resolvedLabels,
451
+ getRows,
452
+ getRowId,
453
+ getValue,
454
+ getText,
455
+ getRowLabel,
456
+ toCSV,
457
+ isSelected,
458
+ setSort,
459
+ toggleSort,
460
+ setSelected,
461
+ toggleRowSelected,
462
+ togglePageSelected,
463
+ setPage,
464
+ setSearch,
465
+ setFilter,
466
+ setFilters,
467
+ getHeaderCellProps: column => ({
468
+ scope: 'col',
469
+ 'aria-sort': sort[0]?.id === column.id ? sort[0].direction : undefined,
470
+ isAligned: column.align,
471
+ width: column.width,
472
+ }),
473
+ getSortButtonProps: column => ({
474
+ type: 'button',
475
+ className: sortButtonClass,
476
+ onClick: () => toggleSort(column.id),
477
+ }),
478
+ getRowProps: row => ({ isSelected: isSelected(row) }),
479
+ getCellProps: (_row, column) => ({
480
+ scope: column.isRowHeader ? 'row' : undefined,
481
+ isAligned: column.align,
482
+ }),
483
+ getSelectAllProps: () => ({
484
+ 'aria-label': resolvedLabels.selectAll,
485
+ checked: allPageSelected,
486
+ indeterminate: pageSelectedCount > 0 && !allPageSelected,
487
+ disabled: pageIds.length === 0,
488
+ onChange: () => togglePageSelected(),
489
+ }),
490
+ getSelectRowProps: row => ({
491
+ 'aria-label': resolvedLabels.selectRow(getRowLabel(row)),
492
+ checked: selectedSet.has(getRowId(row)),
493
+ onChange: () => toggleRowSelected(row),
494
+ }),
495
+ getPaginationProps: () => ({
496
+ total: pageCount,
497
+ current: page,
498
+ onPageChange: setPage,
499
+ }),
500
+ getSearchProps: () => ({
501
+ type: 'search',
502
+ value: search,
503
+ onChange: event => setSearch(event.target.value),
504
+ }),
505
+ };
506
+ }
507
+
508
+ export { isFiltering, useDataTable };
509
+ //# sourceMappingURL=useDataTable.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useDataTable.js","sources":["../../../src/components/useDataTable.ts"],"sourcesContent":["import React, { useCallback, useMemo, useRef, useState } from 'react';\nimport { prefixedClassNames } from '../helpers/classNames';\nimport { useClassPrefix } from '../helpers/Config';\nimport { isDev, warnOnce } from '../helpers/devWarnings';\nimport { useLocale } from '../helpers/LocaleProvider';\nimport { useLocaleMatcher, useNumberFormat } from '../helpers/localeFormat';\nimport { useClientLayoutEffect } from '../helpers/useClientLayoutEffect';\nimport { useLatestRef } from '../helpers/useLatestRef';\nimport type { TableAlignment } from '../elements/tableAlignment';\n\n/**\n * Carries a row type and adds nothing, so `DataTableColumnMeta` can take the\n * row type for the fields an add-on merges in while it has none of its own.\n */\ntype CarriesRow<TRow> = { [K in never]?: TRow };\n\n/**\n * Options of its own an add-on gives a column, read from the column's\n * `meta`. Empty in bestax: an add-on, such as a spreadsheet exporter, adds\n * its fields by declaration merging, and every column then takes them. Every\n * declaration of it names the row type the same way, `TRow`.\n *\n * @example\n * declare module '@allxsmith/bestax-bulma' {\n * interface DataTableColumnMeta<TRow> {\n * exportValue?: (row: TRow) => string | number;\n * }\n * }\n */\n// eslint-disable-next-line @typescript-eslint/no-empty-object-type -- empty so an add-on can merge into it\nexport interface DataTableColumnMeta<TRow = unknown> extends CarriesRow<TRow> {}\n\n/** What a column's `cell` is given beside the row. */\nexport interface DataTableCellContext {\n /** The column's raw value for the row, from its `accessor`. */\n value: unknown;\n /** The column's text for the row, from its `format`. */\n text: string;\n /** The row's id, from `getRowId`. */\n rowId: string;\n}\n\n/**\n * One column of a DataTable. A column keeps three things apart: its raw\n * value (`accessor`), which sorting and `filterFn` read; its text\n * (`format`), which the cell shows, the search matches and an export\n * writes; and its rich content (`cell`), which only the screen sees.\n */\nexport interface DataTableColumn<TRow> {\n /**\n * Names the column for good: the sort, the filters and an export refer to\n * it by this id. Unique within the table, and stable across renders.\n */\n id: string;\n /**\n * The column's name, as text: the header, the sort button's name, the\n * row checkboxes' names when it's the row header, and the header an\n * export writes.\n */\n header: string;\n /**\n * The raw value, for sorting and filtering: a key of the row, or a\n * function of it. Left out, it's the row's property named `id`.\n */\n accessor?: keyof TRow | ((row: TRow) => unknown);\n /**\n * The text for the value: what the cell shows when there's no `cell`, what\n * the search matches, and what an export writes. Left out, it's the value\n * as a string, and nothing for `null` or `undefined`. Give one for\n * numbers and dates you want written a certain way.\n */\n format?: (value: unknown, row: TRow) => string;\n /**\n * Rich content for the cell, such as a tag or a link. Only the screen\n * reads it: sorting, the search and an export use the value and its text.\n */\n cell?: (row: TRow, context: DataTableCellContext) => React.ReactNode;\n /**\n * Makes the header a button that sorts by this column: ascending, then\n * descending, then unsorted.\n */\n sortable?: boolean;\n /** Sorts descending on the first press, for a column read from the top, such as a score. */\n sortDescFirst?: boolean;\n /**\n * Compares two rows for an ascending sort, returning a negative number,\n * zero or a positive one. Descending reverses it. Without it, numbers,\n * dates and booleans compare by value, anything else by its text in the\n * `LocaleProvider`'s locale with numbers inside it read as numbers (\"Item\n * 9\" before \"Item 10\"), and an empty value goes last either way.\n */\n sortFn?: (a: TRow, b: TRow) => number;\n /**\n * Whether the column takes part in filtering: the search matches its\n * text, and `filters` can hold a value for it. `false` leaves it out of\n * both, as for a column of actions.\n */\n filterable?: boolean;\n /**\n * Decides whether a row passes this column's value in `filters`. Without\n * it, the column's text has to contain the value's text, compared as the\n * search compares.\n */\n filterFn?: (row: TRow, filterValue: unknown) => boolean;\n /** Aligns the header and the cells (`isAligned` on `Th` and `Td`). */\n align?: TableAlignment;\n /** The column's width, on its header cell: a number is pixels, a string any CSS length. */\n width?: string | number;\n /**\n * Renders this column's cells as row headers (`th scope=\"row\"`), which a\n * screen reader reads out with the other cells of the row. The row's\n * checkbox is named from it. Mark one column, usually the first.\n */\n isRowHeader?: boolean;\n /** Options of an add-on's own, as `DataTableColumnMeta` declares them. */\n meta?: DataTableColumnMeta<TRow>;\n}\n\n/** The direction of a sort, in `aria-sort`'s words. */\nexport type DataTableSortDirection = 'ascending' | 'descending';\n\n/** One column a DataTable sorts by. */\nexport interface DataTableSort {\n /** The column's `id`. */\n id: string;\n /** Which way it sorts. */\n direction: DataTableSortDirection;\n}\n\n/** The values per column `filters` holds, keyed by column `id`. */\nexport type DataTableFilters = Record<string, unknown>;\n\n/**\n * Which of a table's rows to read: `all` of `data`, `filtered` (the ones the\n * search and the filters let through, from every page), the `page` shown,\n * or the `selected` ones the filters let through. Each comes in the order\n * the table shows them.\n */\nexport type DataTableRowScope = 'all' | 'filtered' | 'page' | 'selected';\n\n/** Whether a DataTable has row checkboxes. */\nexport type DataTableSelectionMode = 'none' | 'multiple';\n\n/**\n * The words a DataTable writes. Each is English unless you give your own,\n * and the numbers in the default messages are written in the\n * `LocaleProvider`'s locale.\n */\nexport interface DataTableLabels {\n /**\n * The header checkbox's name. \"Select all rows\", or \"Select all rows on\n * this page\" when there's more than one page, since it then covers the\n * page shown.\n */\n selectAll?: string;\n /** A row checkbox's name, from the row's label (`label => 'Select ' + label`). */\n selectRow?: (rowLabel: string) => string;\n /**\n * Says that headers with buttons sort: hidden at the end of the caption,\n * after a comma, or as a hidden caption of its own. \"column headers with\n * buttons are sortable\".\n */\n sortHint?: string;\n /** The search field's label. \"Search\". */\n search?: string;\n /** Announced after the search or a filter changes (\"12 rows match\"). */\n results?: (count: number) => string;\n /** Announced after the page changes (\"Showing 11 to 20 of 57\"). */\n pageRange?: (first: number, last: number, total: number) => string;\n /** Announced while `loading`, once the search, a filter or the page has changed. \"Loading\". */\n loading?: string;\n /**\n * The pager's name. \"{the table's name} pages\" when the table is named by\n * `aria-label` or a text `caption`, so two tables' pagers have different\n * names, else `Pagination`'s own.\n */\n pagination?: string;\n /** What the table shows with no rows at all. \"No rows to show.\" */\n empty?: string;\n /** What the table shows when the search and filters let no row through. \"No rows match.\" */\n noResults?: string;\n}\n\n/** The words a DataTable writes, with every default filled in. */\nexport interface DataTableResolvedLabels extends Required<\n Omit<DataTableLabels, 'pagination'>\n> {\n /** The pager's name, when one was given. */\n pagination?: string;\n}\n\n/**\n * The options `useDataTable` and `DataTable` share, beside the columns and\n * the data. Each piece of state is yours when you pass its value (and its\n * `on…Change`), or the table's own, starting from its `default…`.\n */\nexport interface DataTableStateOptions<TRow> {\n /**\n * A row's id, unique and stable, which the selection is a list of. Left\n * out, it's the row's `id` property as a string. A development build\n * warns about a missing or repeated id, and a row with none falls back to\n * its index, which doesn't survive the data changing.\n */\n getRowId?: (row: TRow, index: number) => string;\n /**\n * The sort when you hold it: an array of `{ id, direction }`, the first\n * deciding and each next one breaking ties. The headers set one at a time.\n */\n sort?: DataTableSort[];\n /**\n * The sort to start with when the table holds it. Text sorts in the\n * `LocaleProvider`'s locale, or the runtime's own outside one, which can\n * differ between a server and the browser, so put a table rendered on the\n * server sorted inside a `LocaleProvider`.\n */\n defaultSort?: DataTableSort[];\n /** Called with the new sort when a header is pressed. */\n onSortChange?: (sort: DataTableSort[]) => void;\n /**\n * `multiple` adds a checkbox to each row and a \"select all\" checkbox to the header.\n *\n * @defaultValue 'none'\n */\n selectionMode?: DataTableSelectionMode;\n /**\n * The selected rows' ids when you hold them. They stay selected while the\n * search, a filter or the page hides them.\n */\n selected?: string[];\n /** The rows selected to begin with, by id, when the table holds them. */\n defaultSelected?: string[];\n /** Called with every selected id after a checkbox changes. */\n onSelectedChange?: (selected: string[]) => void;\n /** Rows per page. Set, the table pages through `Pagination`; left out, it shows every row. */\n pageSize?: number;\n /**\n * The page shown when you hold it, counting from 1. A page past the end\n * shows the last.\n */\n page?: number;\n /**\n * The page to start on when the table holds it.\n *\n * @defaultValue 1\n */\n defaultPage?: number;\n /**\n * Called with the page chosen in the pager, and with 1 when the search or\n * a filter changes through the table while the page held isn't 1, even\n * when a page past the end shows as the last.\n */\n onPageChange?: (page: number) => void;\n /**\n * The search when you hold it, matched against every filterable column's\n * text: in the `LocaleProvider`'s locale, ignoring case and the accents\n * the language ignores, or a case-insensitive substring outside one.\n */\n search?: string;\n /** The search to start with when the table holds it. */\n defaultSearch?: string;\n /** Called with the search as it changes through the table. */\n onSearchChange?: (search: string) => void;\n /**\n * A value per column, by `id`, when you hold them. A row passes when every\n * column with a value passes it: the column's `filterFn` if it has one,\n * given the value as it is, or else the column's text has to contain the\n * value's text, compared as the search compares. An array is a choice of\n * values, as a multiple-choice filter gives, and passes a row whose text\n * contains any of them. A value of `undefined`, `null`, `''` or an empty\n * array is no filter.\n */\n filters?: DataTableFilters;\n /** The filters to start with when the table holds them. */\n defaultFilters?: DataTableFilters;\n /** Called with every filter value after one changes through the table. */\n onFiltersChange?: (filters: DataTableFilters) => void;\n /**\n * Hands sorting, filtering and paging to a server: the table shows `data`\n * as given, as the current page, and only reports the state as it\n * changes.\n */\n manual?: boolean;\n /**\n * With `manual`, how many rows match in all, which sets the page count and\n * the announced count. Without it, the table counts the rows in `data`,\n * which with a `pageSize` is one page and no pager, and a development\n * build warns.\n */\n rowCount?: number;\n /** The words the table writes, in your app's language. */\n labels?: DataTableLabels;\n}\n\n/** What `useDataTable` takes. */\nexport interface UseDataTableOptions<TRow> extends DataTableStateOptions<TRow> {\n /**\n * The columns, in the order they're shown. Keep the array the same from\n * one render to the next, defined outside the component or in `useMemo`:\n * a new one has every cell's text worked out again.\n */\n columns: DataTableColumn<TRow>[];\n /** The rows, as records of your own. */\n data: TRow[];\n}\n\n/** The table's state, as it stands. */\nexport interface DataTableState {\n /** The sort, the first entry deciding. */\n sort: DataTableSort[];\n /** The selected rows' ids. */\n selected: string[];\n /** The page shown, counting from 1. */\n page: number;\n /** Rows per page, or `undefined` when it doesn't page. */\n pageSize: number | undefined;\n /** The search. */\n search: string;\n /** The filter values, by column id. */\n filters: DataTableFilters;\n}\n\n/** The props `getSortButtonProps` gives a header's `<button>`. */\nexport interface DataTableSortButtonProps {\n type: 'button';\n className: string;\n onClick: () => void;\n}\n\n/** The props `getSearchProps` gives a search `<input>` or bestax `Input`. */\nexport interface DataTableSearchProps {\n type: 'search';\n value: string;\n onChange: (event: React.ChangeEvent<HTMLInputElement>) => void;\n}\n\n/** The props `getHeaderCellProps` gives a column's `Th`. */\nexport interface DataTableHeaderCellProps {\n scope: 'col';\n 'aria-sort'?: DataTableSortDirection;\n isAligned?: TableAlignment;\n width?: string | number;\n}\n\n/** The props `getCellProps` gives a row's `Td`, or its `Th` for the row header. */\nexport interface DataTableCellProps {\n scope?: 'row';\n isAligned?: TableAlignment;\n}\n\n/** The props `getSelectAllProps` and `getSelectRowProps` give a `Checkbox`. */\nexport interface DataTableCheckboxProps {\n 'aria-label': string;\n checked: boolean;\n indeterminate?: boolean;\n disabled?: boolean;\n onChange: () => void;\n}\n\n/** The props `getPaginationProps` gives `Pagination`. */\nexport interface DataTablePaginationProps {\n total: number;\n current: number;\n onPageChange: (page: number) => void;\n}\n\n/** What `toCSV` writes. */\nexport interface DataTableCSVOptions {\n /**\n * Which rows, in the order the table shows them: the ones the search and\n * filters let through, from every page, by default, or `all`, `page` or\n * `selected`.\n *\n * @defaultValue 'filtered'\n */\n rows?: DataTableRowScope;\n /** The ids of the columns to write, in that order. Every column, in the order shown, by default. */\n columns?: string[];\n /**\n * Writes the columns' headers as the first line.\n *\n * @defaultValue true\n */\n header?: boolean;\n /**\n * What separates the fields. A semicolon suits a spreadsheet that reads\n * a comma as the decimal point, as Excel does in much of Europe.\n *\n * @defaultValue ','\n */\n delimiter?: string;\n}\n\n/**\n * A table: what `useDataTable` returns, what `DataTable`'s `toolbar` is\n * given, and what its `table` takes. It reads the rows and the state, changes\n * the state, and hands out props for bestax's own `Th`, `Tr`, `Td`,\n * `Checkbox` and `Pagination`, so markup of your own behaves as DataTable's\n * does.\n */\nexport interface DataTableModel<TRow> {\n /** The columns, in the order they're shown. */\n columns: DataTableColumn<TRow>[];\n /** The state as it stands. */\n state: DataTableState;\n /** Whether rows have checkboxes. */\n selectionMode: DataTableSelectionMode;\n /** Whether a server sorts, filters and pages (`manual`). */\n manual: boolean;\n /** How many rows the search and filters let through, or `rowCount` with `manual`. */\n rowCount: number;\n /** How many pages there are, at least 1. */\n pageCount: number;\n /** The words the table writes, with the defaults filled in. */\n labels: DataTableResolvedLabels;\n /** The rows in `scope` (`filtered` by default), in the order the table shows them. */\n getRows: (scope?: DataTableRowScope) => TRow[];\n /** A row's id. */\n getRowId: (row: TRow) => string;\n /** A column's raw value for a row, or `undefined` for a column it doesn't have. */\n getValue: (row: TRow, columnId: string) => unknown;\n /** A column's text for a row, or `''` for a column it doesn't have. */\n getText: (row: TRow, columnId: string) => string;\n /** What names a row: its row header's text, or its first column's. */\n getRowLabel: (row: TRow) => string;\n /**\n * The rows as CSV, from the columns' text (`format`, not `cell`), with a\n * line break of `\\r\\n` between rows and fields quoted as RFC 4180 asks.\n * A field that starts with `=`, `+`, `-`, `@`, a tab or a carriage return\n * gets a `'` in front, so a spreadsheet shows it as text rather than\n * running it as a formula, unless it's a plain number such as `-12.5`.\n * Excel takes a file as UTF-8 only when it starts with a byte order mark,\n * so put `\\uFEFF` in front of the text when you save it for Excel.\n */\n toCSV: (options?: DataTableCSVOptions) => string;\n /** Whether a row is selected. */\n isSelected: (row: TRow) => boolean;\n /** Sets the sort. */\n setSort: (sort: DataTableSort[]) => void;\n /** Moves a column through its sort, as its header button does. */\n toggleSort: (columnId: string) => void;\n /** Sets the selected ids. */\n setSelected: (selected: string[]) => void;\n /**\n * Selects a row, or clears it, or with no `selected` flips it. Called\n * twice in one handler, the second call builds on the first while the\n * table holds the selection. While you hold it, each call builds on the\n * selection as rendered, so make several changes at once with\n * `setSelected`.\n */\n toggleRowSelected: (row: TRow, selected?: boolean) => void;\n /**\n * Selects every row on the page, or clears them, or with no `selected`\n * does what the header checkbox does. It builds on earlier calls as\n * `toggleRowSelected` does.\n */\n togglePageSelected: (selected?: boolean) => void;\n /** Goes to a page, counting from 1. */\n setPage: (page: number) => void;\n /**\n * Sets the search, and goes back to page 1, calling `onPageChange` with 1\n * unless the page held is 1 already.\n */\n setSearch: (search: string) => void;\n /**\n * Sets one column's filter value, and goes back to page 1. Called twice in\n * one handler, the second call builds on the first while the table holds\n * the filters. While you hold them, each call builds on the filters as\n * rendered, so set several at once with `setFilters`.\n */\n setFilter: (columnId: string, value: unknown) => void;\n /** Sets every filter value, and goes back to page 1, as `setSearch` does. */\n setFilters: (filters: DataTableFilters) => void;\n /** Props for a column's `Th`: its scope, its `aria-sort` while sorted, its alignment and width. */\n getHeaderCellProps: (\n column: DataTableColumn<TRow>\n ) => DataTableHeaderCellProps;\n /** Props for the `<button>` in a sortable column's header. */\n getSortButtonProps: (\n column: DataTableColumn<TRow>\n ) => DataTableSortButtonProps;\n /** Props for a row's `Tr`: Bulma's selected look while it's selected. */\n getRowProps: (row: TRow) => { isSelected: boolean };\n /** Props for a row's cell in a column: its alignment, and `scope=\"row\"` for the row header. */\n getCellProps: (\n row: TRow,\n column: DataTableColumn<TRow>\n ) => DataTableCellProps;\n /** Props for the header's \"select all\" `Checkbox`, which covers the page shown. */\n getSelectAllProps: () => DataTableCheckboxProps;\n /** Props for a row's `Checkbox`, named for the row. */\n getSelectRowProps: (row: TRow) => DataTableCheckboxProps;\n /** Props for `Pagination`: the page count, the page and the handler. */\n getPaginationProps: () => DataTablePaginationProps;\n /** Props for a search field, bound to the search. */\n getSearchProps: () => DataTableSearchProps;\n}\n\n/** A column's raw value for a row. */\nfunction readValue<TRow>(column: DataTableColumn<TRow>, row: TRow): unknown {\n const { accessor } = column;\n if (typeof accessor === 'function') return accessor(row);\n if (row === null || typeof row !== 'object') return undefined;\n return (row as Record<PropertyKey, unknown>)[\n (accessor ?? column.id) as PropertyKey\n ];\n}\n\n/** A column's text for a row. */\nfunction readText<TRow>(column: DataTableColumn<TRow>, row: TRow): string {\n const value = readValue(column, row);\n if (column.format) return column.format(value, row);\n return value === null || value === undefined ? '' : String(value);\n}\n\n/** Whether a value sorts as empty: nothing, no text, or no number or date. */\nfunction isEmptyValue(value: unknown): boolean {\n return (\n value === null ||\n value === undefined ||\n value === '' ||\n (typeof value === 'number' && Number.isNaN(value)) ||\n (value instanceof Date && Number.isNaN(value.getTime()))\n );\n}\n\n/** Compares two values that aren't empty, for an ascending sort. */\nfunction compareValues(a: unknown, b: unknown, collator: Intl.Collator) {\n if (typeof a === 'number' && typeof b === 'number') return a - b;\n if (a instanceof Date && b instanceof Date) return a.getTime() - b.getTime();\n if (typeof a === 'boolean' && typeof b === 'boolean') {\n return Number(a) - Number(b);\n }\n return collator.compare(String(a), String(b));\n}\n\n/** Whether a filter value filters anything. */\nfunction isActiveFilter(value: unknown): boolean {\n return (\n value !== undefined &&\n value !== null &&\n value !== '' &&\n !(Array.isArray(value) && value.length === 0)\n );\n}\n\n/** A field a spreadsheet would read as the start of a formula. */\nconst formulaStart = /^[=+\\-@\\t\\r]/;\n/** A plain number, signed, with any grouping, which no spreadsheet runs. */\nconst plainNumber = /^[+-]?\\d[\\d.,]*$/;\n\n/**\n * One CSV field: a `'` in front of what would start a formula, then quoted\n * when it holds the delimiter, a quote or a line break, its quotes doubled.\n */\nfunction csvField(text: string, delimiter: string): string {\n const safe =\n formulaStart.test(text) && !plainNumber.test(text) ? `'${text}` : text;\n return safe.includes(delimiter) || /[\"\\r\\n]/.test(safe)\n ? `\"${safe.replace(/\"/g, '\"\"')}\"`\n : safe;\n}\n\n/**\n * Whether a search or a filter value is narrowing the rows. Used by\n * DataTable to tell an empty table from one with no matches.\n */\nexport function isFiltering(search: string, filters: DataTableFilters) {\n return search.trim() !== '' || Object.values(filters).some(isActiveFilter);\n}\n\n/** A row's id from its `id` property, or nothing when it has none. */\nfunction idOf(row: unknown): string | undefined {\n if (row === null || typeof row !== 'object') return undefined;\n const id = (row as { id?: unknown }).id;\n return id === undefined || id === null || id === '' ? undefined : String(id);\n}\n\n/**\n * A piece of state that's the caller's when they pass its value, and the\n * table's own otherwise. Setting it calls the change handler either way.\n *\n * It also returns `latest`, what a change should build on. While the table\n * holds the state, that's the value last set, even before React renders it,\n * so two changes in one handler build on each other. While the caller holds\n * it, it's the value as rendered, since only the caller knows what it made\n * of a change.\n */\nfunction useTableState<T>(\n value: T | undefined,\n initial: T,\n onChange: ((next: T) => void) | undefined\n): [T, (next: T) => void, () => T] {\n const [own, setOwn] = useState(initial);\n const held = value !== undefined;\n const current = held ? value : own;\n const rendered = useLatestRef(current);\n // A value set since the last commit, cleared once a commit shows it.\n const pendingRef = useRef<{ value: T } | null>(null);\n useClientLayoutEffect(() => {\n pendingRef.current = null;\n });\n const set = useCallback(\n (next: T) => {\n if (!held) {\n pendingRef.current = { value: next };\n setOwn(next);\n }\n onChange?.(next);\n },\n [held, onChange]\n );\n const latest = useCallback(\n () => (pendingRef.current ? pendingRef.current.value : rendered.current),\n [rendered]\n );\n return [current, set, latest];\n}\n\nconst noSort: DataTableSort[] = [];\nconst noIds: string[] = [];\nconst noFilters: DataTableFilters = {};\n\n/**\n * `useDataTable` holds a table's sort, selection, page, search and filters,\n * works out its rows, and hands out props for bestax's own table parts, so\n * custom markup behaves as `DataTable` does. Pass its result to\n * `<DataTable table={table} />` to render it with DataTable's own markup,\n * with a toolbar or an export button elsewhere on the page.\n *\n * @example\n * const table = useDataTable({ columns, data: users, pageSize: 10 });\n *\n * <DataTable table={table} caption=\"Users\" hasSearch />\n */\nexport function useDataTable<TRow>(\n options: UseDataTableOptions<TRow>\n): DataTableModel<TRow> {\n const {\n columns,\n data,\n getRowId: rowIdOf,\n sort: sortProp,\n defaultSort = noSort,\n onSortChange,\n selectionMode = 'none',\n selected: selectedProp,\n defaultSelected = noIds,\n onSelectedChange,\n pageSize: pageSizeProp,\n page: pageProp,\n defaultPage = 1,\n onPageChange,\n search: searchProp,\n defaultSearch = '',\n onSearchChange,\n filters: filtersProp,\n defaultFilters = noFilters,\n onFiltersChange,\n manual = false,\n rowCount: rowCountProp,\n labels,\n } = options;\n\n const [sort, setSort] = useTableState(sortProp, defaultSort, onSortChange);\n const [selected, setSelected, latestSelected] = useTableState(\n selectedProp,\n defaultSelected,\n onSelectedChange\n );\n const [pageState, setPageState, latestPage] = useTableState(\n pageProp,\n defaultPage,\n onPageChange\n );\n const [search, setSearchState] = useTableState(\n searchProp,\n defaultSearch,\n onSearchChange\n );\n const [filters, setFiltersState, latestFilters] = useTableState(\n filtersProp,\n defaultFilters,\n onFiltersChange\n );\n\n const prefix = useClassPrefix();\n const { locale } = useLocale();\n const matchText = useLocaleMatcher();\n const formatNumber = useNumberFormat();\n const collator = useMemo(\n () => new Intl.Collator(locale, { numeric: true }),\n [locale]\n );\n\n const pageSize =\n pageSizeProp !== undefined &&\n Number.isFinite(pageSizeProp) &&\n pageSizeProp >= 1\n ? Math.floor(pageSizeProp)\n : undefined;\n\n const columnsById = useMemo(() => {\n const byId = new Map<string, DataTableColumn<TRow>>();\n for (const column of columns) {\n if (byId.has(column.id)) {\n warnOnce(\n 'DataTable:duplicate-column',\n `[bestax-bulma] DataTable has two columns with the id \"${column.id}\". ` +\n 'Give each column its own id: the sort, the filters and an export ' +\n 'find a column by it.'\n );\n } else {\n byId.set(column.id, column);\n }\n }\n return byId;\n }, [columns]);\n\n // Each row's id, by its index in `data`.\n const ids = useMemo(() => {\n const out = data.map((row, index) => {\n const id = rowIdOf ? rowIdOf(row, index) : idOf(row);\n if (id === undefined || id === '') {\n warnOnce(\n 'DataTable:missing-row-id',\n '[bestax-bulma] A DataTable row has no id, so it falls back to its ' +\n \"index, which doesn't survive the data changing. Give each row \" +\n 'an `id`, or pass `getRowId`.'\n );\n return String(index);\n }\n return id;\n });\n if (isDev() && new Set(out).size < out.length) {\n warnOnce(\n 'DataTable:duplicate-row-id',\n '[bestax-bulma] Two DataTable rows have the same id, so selecting ' +\n 'one selects both. Make the ids unique, or pass a `getRowId` ' +\n 'that does.'\n );\n }\n return out;\n }, [data, rowIdOf]);\n\n const indexOf = useMemo(() => {\n const map = new Map<TRow, number>();\n data.forEach((row, index) => {\n if (!map.has(row)) map.set(row, index);\n });\n return map;\n }, [data]);\n\n /** A row's id, from its index when the row is one of `data`. */\n const getRowId = useCallback(\n (row: TRow) => {\n const index = indexOf.get(row);\n if (index !== undefined) return ids[index];\n const id = rowIdOf ? rowIdOf(row, -1) : idOf(row);\n return id ?? '';\n },\n [indexOf, ids, rowIdOf]\n );\n\n // Every column's text for every row, worked out once per data and\n // columns, since the search reads them on every keystroke.\n const texts = useMemo(\n () => data.map(row => columns.map(column => readText(column, row))),\n [data, columns]\n );\n\n const sortedIndexes = useMemo(() => {\n const all = data.map((_, index) => index);\n if (manual) return all;\n const keys = sort\n .map(entry => ({\n column: columnsById.get(entry.id),\n descending: entry.direction === 'descending',\n }))\n .filter(\n (key): key is { column: DataTableColumn<TRow>; descending: boolean } =>\n key.column !== undefined\n );\n if (keys.length === 0) return all;\n const values = keys.map(({ column }) =>\n column.sortFn ? null : data.map(row => readValue(column, row))\n );\n return all.sort((x, y) => {\n for (let k = 0; k < keys.length; k++) {\n const { column, descending } = keys[k];\n let result: number;\n if (column.sortFn) {\n result = column.sortFn(data[x], data[y]);\n if (descending) result = -result;\n } else {\n const a = values[k]![x];\n const b = values[k]![y];\n const aEmpty = isEmptyValue(a);\n const bEmpty = isEmptyValue(b);\n if (aEmpty || bEmpty) {\n // Empty values go last whichever way the column sorts.\n result = Number(aEmpty) - Number(bEmpty);\n } else {\n result = compareValues(a, b, collator);\n if (descending) result = -result;\n }\n }\n if (result) return result;\n }\n // Ties keep the order of `data`.\n return x - y;\n });\n }, [data, sort, columnsById, collator, manual]);\n\n const filteredIndexes = useMemo(() => {\n if (manual) return sortedIndexes;\n const query = search.trim();\n const holds = matchText\n ? (text: string, needle: string) => matchText(text, needle)\n : (text: string, needle: string) =>\n text.toLowerCase().includes(needle.toLowerCase());\n const searched = columns\n .map((column, index) => ({ column, index }))\n .filter(({ column }) => column.filterable !== false);\n const filtered = Object.entries(filters)\n .filter(([, value]) => isActiveFilter(value))\n .map(([id, value]) => ({\n column: columnsById.get(id),\n index: columns.findIndex(column => column.id === id),\n value,\n }))\n .filter(\n ({ column }) => column !== undefined && column.filterable !== false\n );\n if (query === '' && filtered.length === 0) return sortedIndexes;\n return sortedIndexes.filter(rowIndex => {\n const row = data[rowIndex];\n const rowTexts = texts[rowIndex];\n for (const { column, index, value } of filtered) {\n // An array is any of its entries, as a multiple-choice filter gives.\n const passes = column!.filterFn\n ? column!.filterFn(row, value)\n : Array.isArray(value)\n ? value.some(entry => holds(rowTexts[index], String(entry)))\n : holds(rowTexts[index], String(value));\n if (!passes) return false;\n }\n return (\n query === '' ||\n searched.some(({ index }) => holds(rowTexts[index], query))\n );\n });\n }, [\n manual,\n sortedIndexes,\n search,\n filters,\n matchText,\n columns,\n columnsById,\n data,\n texts,\n ]);\n\n const knowsCount =\n rowCountProp !== undefined && Number.isFinite(rowCountProp);\n if (manual && pageSize !== undefined && !knowsCount) {\n warnOnce(\n 'DataTable:manual-row-count',\n '[bestax-bulma] A DataTable with `manual` and a `pageSize` has no ' +\n '`rowCount`, so it counts only the rows in `data`, makes one page ' +\n 'of them and shows no pager. Pass `rowCount`, how many rows match ' +\n 'on the server.'\n );\n }\n const rowCount = manual\n ? Math.max(\n Math.floor(knowsCount ? (rowCountProp as number) : data.length),\n 0\n )\n : filteredIndexes.length;\n const pageCount = pageSize ? Math.max(Math.ceil(rowCount / pageSize), 1) : 1;\n const page = Math.min(\n Math.max(Number.isFinite(pageState) ? Math.floor(pageState) : 1, 1),\n pageCount\n );\n\n const pageIndexes = useMemo(() => {\n if (manual || !pageSize) return filteredIndexes;\n return filteredIndexes.slice((page - 1) * pageSize, page * pageSize);\n }, [manual, pageSize, filteredIndexes, page]);\n\n const selectedSet = useMemo(() => new Set(selected), [selected]);\n const selectable = selectionMode === 'multiple';\n\n const rowsOf = useCallback(\n (indexes: number[]) => indexes.map(index => data[index]),\n [data]\n );\n\n const getRows = useCallback(\n (scope: DataTableRowScope = 'filtered') => {\n switch (scope) {\n case 'all':\n return rowsOf(sortedIndexes);\n case 'page':\n return rowsOf(pageIndexes);\n case 'selected':\n return rowsOf(\n filteredIndexes.filter(index => selectedSet.has(ids[index]))\n );\n default:\n return rowsOf(filteredIndexes);\n }\n },\n [rowsOf, sortedIndexes, pageIndexes, filteredIndexes, selectedSet, ids]\n );\n\n const getValue = useCallback(\n (row: TRow, columnId: string) => {\n const column = columnsById.get(columnId);\n return column ? readValue(column, row) : undefined;\n },\n [columnsById]\n );\n\n const getText = useCallback(\n (row: TRow, columnId: string) => {\n const column = columnsById.get(columnId);\n if (!column) return '';\n const index = indexOf.get(row);\n return index !== undefined\n ? texts[index][columns.indexOf(column)]\n : readText(column, row);\n },\n [columnsById, indexOf, columns, texts]\n );\n\n const labelColumn = columns.find(column => column.isRowHeader) ?? columns[0];\n const getRowLabel = useCallback(\n (row: TRow) =>\n (labelColumn && getText(row, labelColumn.id)) || getRowId(row),\n [labelColumn, getText, getRowId]\n );\n\n const isSelected = useCallback(\n (row: TRow) => selectable && selectedSet.has(getRowId(row)),\n [selectable, selectedSet, getRowId]\n );\n\n const setPage = useCallback(\n (next: number) => {\n if (next !== page) setPageState(next);\n },\n [page, setPageState]\n );\n\n // A new search or filter starts from the first page. It's measured against\n // the page as stored, not as shown: a page past the end shows the last,\n // and left stored it would come back once the rows grew again.\n const resetPage = useCallback(() => {\n if (latestPage() !== 1) setPageState(1);\n }, [latestPage, setPageState]);\n\n const setSearch = useCallback(\n (next: string) => {\n setSearchState(next);\n resetPage();\n },\n [setSearchState, resetPage]\n );\n\n const setFilters = useCallback(\n (next: DataTableFilters) => {\n setFiltersState(next);\n resetPage();\n },\n [setFiltersState, resetPage]\n );\n\n const setFilter = useCallback(\n (columnId: string, value: unknown) => {\n const next = { ...latestFilters() };\n if (isActiveFilter(value)) next[columnId] = value;\n else delete next[columnId];\n setFilters(next);\n },\n [latestFilters, setFilters]\n );\n\n const toggleSort = useCallback(\n (columnId: string) => {\n const column = columnsById.get(columnId);\n if (!column) return;\n const first: DataTableSortDirection = column.sortDescFirst\n ? 'descending'\n : 'ascending';\n const current = sort[0]?.id === columnId ? sort[0].direction : undefined;\n if (current === undefined) {\n setSort([{ id: columnId, direction: first }]);\n } else if (current === first) {\n setSort([\n {\n id: columnId,\n direction: first === 'ascending' ? 'descending' : 'ascending',\n },\n ]);\n } else {\n setSort([]);\n }\n },\n [columnsById, sort, setSort]\n );\n\n const toggleRowSelected = useCallback(\n (row: TRow, value?: boolean) => {\n const id = getRowId(row);\n const current = latestSelected();\n const has = current.includes(id);\n const on = value ?? !has;\n if (on === has) return;\n setSelected(on ? [...current, id] : current.filter(s => s !== id));\n },\n [getRowId, latestSelected, setSelected]\n );\n\n const pageIds = useMemo(\n () => pageIndexes.map(index => ids[index]),\n [pageIndexes, ids]\n );\n const pageSelectedCount = pageIds.filter(id => selectedSet.has(id)).length;\n const allPageSelected =\n pageIds.length > 0 && pageSelectedCount === pageIds.length;\n\n const togglePageSelected = useCallback(\n (value?: boolean) => {\n const current = latestSelected();\n const has = new Set(current);\n const on =\n value ?? !(pageIds.length > 0 && pageIds.every(id => has.has(id)));\n if (on) {\n const adding = pageIds.filter(id => !has.has(id));\n if (adding.length > 0) setSelected([...current, ...adding]);\n } else {\n const onPage = new Set(pageIds);\n const kept = current.filter(id => !onPage.has(id));\n if (kept.length !== current.length) setSelected(kept);\n }\n },\n [latestSelected, pageIds, setSelected]\n );\n\n const count = useCallback(\n (value: number) => (formatNumber ? formatNumber(value) : String(value)),\n [formatNumber]\n );\n\n const resolvedLabels: DataTableResolvedLabels = {\n selectAll:\n labels?.selectAll ||\n (pageCount > 1 ? 'Select all rows on this page' : 'Select all rows'),\n selectRow: labels?.selectRow ?? (label => `Select ${label}`),\n sortHint: labels?.sortHint || 'column headers with buttons are sortable',\n search: labels?.search || 'Search',\n results:\n labels?.results ??\n (total =>\n total === 0\n ? 'No rows match'\n : `${count(total)} ${total === 1 ? 'row matches' : 'rows match'}`),\n pageRange:\n labels?.pageRange ??\n ((first, last, total) =>\n `Showing ${count(first)} to ${count(last)} of ${count(total)}`),\n loading: labels?.loading || 'Loading',\n pagination: labels?.pagination || undefined,\n empty: labels?.empty || 'No rows to show.',\n noResults: labels?.noResults || 'No rows match.',\n };\n\n const toCSV = useCallback(\n ({\n rows = 'filtered',\n columns: ids,\n header = true,\n delimiter = ',',\n }: DataTableCSVOptions = {}) => {\n const written = ids\n ? ids\n .map(id => columnsById.get(id))\n .filter(\n (column): column is DataTableColumn<TRow> => column !== undefined\n )\n : columns;\n const line = (fields: string[]) =>\n fields.map(field => csvField(field, delimiter)).join(delimiter);\n const lines = getRows(rows).map(row =>\n line(written.map(column => getText(row, column.id)))\n );\n if (header) lines.unshift(line(written.map(column => column.header)));\n return lines.join('\\r\\n');\n },\n [columnsById, columns, getRows, getText]\n );\n\n const sortButtonClass = prefixedClassNames(prefix, 'data-table-sort');\n\n return {\n columns,\n state: { sort, selected, page, pageSize, search, filters },\n selectionMode,\n manual,\n rowCount,\n pageCount,\n labels: resolvedLabels,\n getRows,\n getRowId,\n getValue,\n getText,\n getRowLabel,\n toCSV,\n isSelected,\n setSort,\n toggleSort,\n setSelected,\n toggleRowSelected,\n togglePageSelected,\n setPage,\n setSearch,\n setFilter,\n setFilters,\n getHeaderCellProps: column => ({\n scope: 'col',\n 'aria-sort': sort[0]?.id === column.id ? sort[0].direction : undefined,\n isAligned: column.align,\n width: column.width,\n }),\n getSortButtonProps: column => ({\n type: 'button',\n className: sortButtonClass,\n onClick: () => toggleSort(column.id),\n }),\n getRowProps: row => ({ isSelected: isSelected(row) }),\n getCellProps: (_row, column) => ({\n scope: column.isRowHeader ? 'row' : undefined,\n isAligned: column.align,\n }),\n getSelectAllProps: () => ({\n 'aria-label': resolvedLabels.selectAll,\n checked: allPageSelected,\n indeterminate: pageSelectedCount > 0 && !allPageSelected,\n disabled: pageIds.length === 0,\n onChange: () => togglePageSelected(),\n }),\n getSelectRowProps: row => ({\n 'aria-label': resolvedLabels.selectRow(getRowLabel(row)),\n checked: selectedSet.has(getRowId(row)),\n onChange: () => toggleRowSelected(row),\n }),\n getPaginationProps: () => ({\n total: pageCount,\n current: page,\n onPageChange: setPage,\n }),\n getSearchProps: () => ({\n type: 'search',\n value: search,\n onChange: event => setSearch(event.target.value),\n }),\n };\n}\n"],"names":[],"mappings":"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"}