@dxos/react-ui-table 0.3.8-next.f4e0086 → 0.3.9-main.1d6fb54

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 (54) hide show
  1. package/dist/lib/browser/index.mjs +546 -480
  2. package/dist/lib/browser/index.mjs.map +4 -4
  3. package/dist/lib/browser/meta.json +1 -1
  4. package/dist/types/src/components/Cell/Cell.d.ts +12 -0
  5. package/dist/types/src/components/Cell/Cell.d.ts.map +1 -0
  6. package/dist/types/src/components/{ComboboxCell.d.ts → Cell/CellCombobox.d.ts} +4 -4
  7. package/dist/types/src/components/Cell/CellCombobox.d.ts.map +1 -0
  8. package/dist/types/src/components/Cell/index.d.ts +2 -0
  9. package/dist/types/src/components/Cell/index.d.ts.map +1 -0
  10. package/dist/types/src/components/Table/Table.d.ts +3 -0
  11. package/dist/types/src/components/Table/Table.d.ts.map +1 -0
  12. package/dist/types/src/components/{Table.stories.d.ts → Table/Table.stories.d.ts} +4 -7
  13. package/dist/types/src/components/Table/Table.stories.d.ts.map +1 -0
  14. package/dist/types/src/components/Table/TableBody.d.ts +11 -0
  15. package/dist/types/src/components/Table/TableBody.d.ts.map +1 -0
  16. package/dist/types/src/components/Table/TableContext.d.ts +14 -0
  17. package/dist/types/src/components/Table/TableContext.d.ts.map +1 -0
  18. package/dist/types/src/components/Table/TableFooter.d.ts +7 -0
  19. package/dist/types/src/components/Table/TableFooter.d.ts.map +1 -0
  20. package/dist/types/src/components/Table/TableHead.d.ts +8 -0
  21. package/dist/types/src/components/Table/TableHead.d.ts.map +1 -0
  22. package/dist/types/src/components/Table/index.d.ts +3 -0
  23. package/dist/types/src/components/Table/index.d.ts.map +1 -0
  24. package/dist/types/src/components/Table/props.d.ts +39 -0
  25. package/dist/types/src/components/Table/props.d.ts.map +1 -0
  26. package/dist/types/src/components/index.d.ts +1 -1
  27. package/dist/types/src/components/index.d.ts.map +1 -1
  28. package/dist/types/src/helpers.d.ts +21 -15
  29. package/dist/types/src/helpers.d.ts.map +1 -1
  30. package/dist/types/src/theme.d.ts +30 -33
  31. package/dist/types/src/theme.d.ts.map +1 -1
  32. package/dist/types/src/types.d.ts +13 -10
  33. package/dist/types/src/types.d.ts.map +1 -1
  34. package/package.json +12 -10
  35. package/src/components/Cell/Cell.tsx +43 -0
  36. package/src/components/{ComboboxCell.tsx → Cell/CellCombobox.tsx} +6 -6
  37. package/src/components/Cell/index.ts +5 -0
  38. package/src/components/{Table.stories.tsx → Table/Table.stories.tsx} +51 -51
  39. package/src/components/Table/Table.tsx +184 -0
  40. package/src/components/Table/TableBody.tsx +70 -0
  41. package/src/components/Table/TableContext.tsx +28 -0
  42. package/src/components/Table/TableFooter.tsx +42 -0
  43. package/src/components/Table/TableHead.tsx +79 -0
  44. package/src/components/Table/index.ts +6 -0
  45. package/src/components/Table/props.ts +57 -0
  46. package/src/components/index.ts +1 -1
  47. package/src/helpers.tsx +276 -219
  48. package/src/theme.ts +102 -63
  49. package/src/types.ts +15 -10
  50. package/dist/types/src/components/ComboboxCell.d.ts.map +0 -1
  51. package/dist/types/src/components/Table.d.ts +0 -29
  52. package/dist/types/src/components/Table.d.ts.map +0 -1
  53. package/dist/types/src/components/Table.stories.d.ts.map +0 -1
  54. package/src/components/Table.tsx +0 -551
@@ -184,93 +184,216 @@ var ColumnPanel = ({ context, tableDefs, tableDef, column, onUpdate, onDelete })
184
184
  })))))), /* @__PURE__ */ React.createElement(Popover.Arrow, null))));
185
185
  };
186
186
 
187
- // packages/ui/react-ui-table/src/components/Table.tsx
188
- import { flexRender, getCoreRowModel, getGroupedRowModel, useReactTable } from "@tanstack/react-table";
189
- import React2, { Fragment, useEffect, useRef as useRef2, useState as useState2 } from "react";
187
+ // packages/ui/react-ui-table/src/components/Table/Table.tsx
188
+ import { useControllableState } from "@radix-ui/react-use-controllable-state";
189
+ import { getCoreRowModel, getGroupedRowModel, useReactTable } from "@tanstack/react-table";
190
+ import React6, { Fragment, useCallback, useEffect, useState as useState2 } from "react";
190
191
  import { debounce } from "@dxos/async";
191
- import { groupBorder, inputSurface, mx as mx2 } from "@dxos/react-ui-theme";
192
+
193
+ // packages/ui/react-ui-table/src/components/Table/TableBody.tsx
194
+ import { useArrowNavigationGroup } from "@fluentui/react-tabster";
195
+ import { flexRender } from "@tanstack/react-table";
196
+ import React3 from "react";
197
+
198
+ // packages/ui/react-ui-table/src/components/Table/TableContext.tsx
199
+ import { createContext } from "@radix-ui/react-context";
200
+ var TABLE_NAME = "Table";
201
+ var [TableProvider, useUntypedTableContext] = createContext(TABLE_NAME);
202
+ var useTableContext = (consumerName) => useUntypedTableContext(consumerName);
192
203
 
193
204
  // packages/ui/react-ui-table/src/theme.ts
194
- import { chromeSurface } from "@dxos/react-ui-theme";
195
- var defaultTableSlots = {
196
- // TODO(burdon): head/body/table rows.
197
- header: {
198
- className: [
199
- chromeSurface,
200
- "px-2 font-light select-none"
201
- ]
202
- },
203
- footer: {
204
- className: [
205
- chromeSurface,
206
- "px-2 font-light"
207
- ]
208
- },
209
- cell: {
210
- className: "px-2"
211
- },
212
- group: {
213
- className: "px-2 font-light text-xs text-left"
214
- },
215
- focus: {
216
- className: "ring ring-primary-600 ring-inset"
217
- },
218
- selected: {
219
- className: "!bg-teal-100 dark:!bg-teal-700"
220
- }
205
+ import { chromeSurface, fixedSurface, focusRing, ghostSelected, ghostSelectedCurrent, groupBorder, mx as mx2 } from "@dxos/react-ui-theme";
206
+ var currentRow = "!bg-neutral-75 !dark:bg-neutral-850";
207
+ var selectedRow = "!bg-primary-100 dark:!bg-primary-700";
208
+ var flushPadding = "pli-0 plb-0";
209
+ var textPadding = "pli-2 plb-0.5";
210
+ var headPadding = "pli-2 plb-1.5";
211
+ var gridCellFocusRing = "focus:z-[11] focus:outline outline-2 outline-primary-500 dark:outline-primary-400";
212
+ var tableRoot = ({ fullWidth }, ...etc) => mx2("table-fixed", fullWidth && "is-full", ...etc);
213
+ var groupTh = (_props, ...etc) => mx2("text-start font-medium", flushPadding, ...etc);
214
+ var theadRoot = ({ header }, ...etc) => mx2(header ? "sticky block-start-0 z-10" : "collapse", header && fixedSurface, ...etc);
215
+ var theadTr = (_props, ...etc) => mx2("group", ...etc);
216
+ var theadTh = ({ border }, ...etc) => mx2("relative text-start font-medium select-none truncate", headPadding, border && "border", border && groupBorder, ...etc);
217
+ var theadResizeRoot = (_props, ...etc) => mx2("absolute top-0 pis-1 h-full z-[10] w-[7px] -right-[5px] cursor-col-resize select-none touch-none opacity-20 hover:opacity-100", ...etc);
218
+ var theadResizeThumb = (_props, ...etc) => mx2("flex group-hover:bg-neutral-700 -ml-[2px] w-[1px] h-full", ...etc);
219
+ var tbodyRoot = (_props, ...etc) => mx2(...etc);
220
+ var tbodyTr = ({ canBeCurrent }, ...etc) => mx2("group", canBeCurrent ? ghostSelectedCurrent : ghostSelected, canBeCurrent && focusRing, canBeCurrent && "cursor-pointer rounded", ...etc);
221
+ var tdRoot = ({ border, isGrid }, ...etc) => mx2("relative", flushPadding, border && "border", border && groupBorder, isGrid && gridCellFocusRing, ...etc);
222
+ var tdContent = (_props, ...etc) => mx2(...etc);
223
+ var tfootRoot = (_props, ...etc) => mx2("sticky block-end-0 z-10", chromeSurface, ...etc);
224
+ var tfootTr = (_props, ...etc) => mx2(...etc);
225
+ var tfootTh = ({ border }, ...etc) => mx2(textPadding, chromeSurface, border && groupBorder, ...etc);
226
+
227
+ // packages/ui/react-ui-table/src/components/Cell/Cell.tsx
228
+ import { useFocusableGroup } from "@fluentui/react-tabster";
229
+ import React2 from "react";
230
+ var CELL_NAME = "Cell";
231
+ var FocusableCell = ({ cell, children }) => {
232
+ const tableContext = useTableContext(CELL_NAME);
233
+ const domAttributes = useFocusableGroup({
234
+ tabBehavior: "limited"
235
+ });
236
+ return /* @__PURE__ */ React2.createElement("td", {
237
+ tabIndex: 0,
238
+ ...domAttributes,
239
+ className: tdRoot(tableContext, cell.column.columnDef.meta?.cell?.classNames)
240
+ }, children);
221
241
  };
242
+ var StaticCell = ({ cell, children }) => {
243
+ const tableContext = useTableContext(CELL_NAME);
244
+ return /* @__PURE__ */ React2.createElement("td", {
245
+ className: tdRoot(tableContext, cell.column.columnDef.meta?.cell?.classNames)
246
+ }, children);
247
+ };
248
+ var Cell = ({ cell, children }) => {
249
+ const { isGrid } = useTableContext(CELL_NAME);
250
+ const Root = isGrid ? FocusableCell : StaticCell;
251
+ return /* @__PURE__ */ React2.createElement(Root, {
252
+ cell
253
+ }, children);
254
+ };
255
+ Cell.displayName = CELL_NAME;
222
256
 
223
- // packages/ui/react-ui-table/src/components/Table.tsx
224
- var updateSelection = (selectionState, id, selection) => {
225
- switch (selection) {
226
- case "single": {
227
- return {
228
- [id]: true
229
- };
230
- }
231
- case "single-toggle": {
232
- return selectionState[id] ? {} : {
233
- [id]: true
234
- };
235
- }
236
- case "multiple": {
237
- return {
238
- [id]: true,
239
- ...selectionState
240
- };
241
- }
242
- case "multiple-toggle": {
243
- if (selectionState[id]) {
244
- const newSelectionState = {
245
- ...selectionState
246
- };
247
- delete newSelectionState[id];
248
- return newSelectionState;
249
- } else {
250
- return {
251
- [id]: true,
252
- ...selectionState
253
- };
257
+ // packages/ui/react-ui-table/src/components/Table/TableBody.tsx
258
+ var TABLE_BODY_NAME = "TableBody";
259
+ var TableBody = ({ rows }) => {
260
+ const tableContext = useTableContext(TABLE_BODY_NAME);
261
+ const { table, keyAccessor, debug, expand, isGrid, onDatumClick, currentDatum } = tableContext;
262
+ const rowSelection = table.getState().rowSelection;
263
+ const domAttributes = useArrowNavigationGroup({
264
+ axis: "grid"
265
+ });
266
+ const canBeCurrent = !isGrid && !!onDatumClick;
267
+ return /* @__PURE__ */ React3.createElement("tbody", isGrid && domAttributes, rows.map((row) => {
268
+ const isCurrent = currentDatum === row.original;
269
+ const isSelected = rowSelection?.[row.id];
270
+ return /* @__PURE__ */ React3.createElement("tr", {
271
+ key: keyAccessor ? keyAccessor(row.original) : row.id,
272
+ className: tbodyTr({
273
+ canBeCurrent
274
+ }),
275
+ ...isCurrent && {
276
+ "aria-current": "location"
277
+ },
278
+ ...isSelected && {
279
+ "aria-selected": "true"
280
+ },
281
+ ...canBeCurrent && {
282
+ tabIndex: 0,
283
+ onClick: () => {
284
+ onDatumClick(row.original);
285
+ },
286
+ onKeyUp: ({ key }) => {
287
+ if (key === "Enter" || key === " ") {
288
+ onDatumClick(row.original);
289
+ }
290
+ }
254
291
  }
255
- }
256
- }
257
- return selectionState;
292
+ }, debug && /* @__PURE__ */ React3.createElement("td", null, row.id), row.getVisibleCells().map((cell) => {
293
+ return /* @__PURE__ */ React3.createElement(Cell, {
294
+ key: cell.id,
295
+ cell
296
+ }, flexRender(cell.column.columnDef.cell, {
297
+ className: "pli-2",
298
+ ...cell.getContext()
299
+ }));
300
+ }), expand && /* @__PURE__ */ React3.createElement("td", null));
301
+ }));
258
302
  };
259
- var Table = ({ slots = defaultTableSlots, ...props }) => {
260
- const { data = [], columns = [], onColumnResize, columnVisibility, header = true, footer, select, selected, onSelectedChange, fullWidth, pinToBottom, debug } = props;
261
- const [focus, setFocus] = useState2();
262
- const [rowSelection, setRowSelection] = useState2({});
263
- useEffect(() => {
264
- setRowSelection(selected?.reduce((selectionState, selected2) => {
265
- const row = table.getRowModel().rows.find((row2) => row2.original === selected2);
266
- if (row) {
267
- selectionState[row.id] = true;
268
- }
269
- return selectionState;
270
- }, {}) ?? {});
303
+ TableBody.displayName = TABLE_BODY_NAME;
304
+
305
+ // packages/ui/react-ui-table/src/components/Table/TableFooter.tsx
306
+ import { flexRender as flexRender2 } from "@tanstack/react-table";
307
+ import React4 from "react";
308
+ var TABLE_FOOTER_NAME = "TableFooter";
309
+ var TableFooter = (props) => {
310
+ const tableContext = useTableContext(TABLE_FOOTER_NAME);
311
+ const { table, expand, debug } = tableContext;
312
+ const footers = table.getFooterGroups();
313
+ return /* @__PURE__ */ React4.createElement("tfoot", {
314
+ className: tfootRoot(props)
315
+ }, footers.map((footerGroup) => /* @__PURE__ */ React4.createElement("tr", {
316
+ key: footerGroup.id,
317
+ className: tfootTr(tableContext)
318
+ }, debug && /* @__PURE__ */ React4.createElement("th", null), footerGroup.headers.map((footer) => {
319
+ return /* @__PURE__ */ React4.createElement("th", {
320
+ key: footer.id,
321
+ className: tfootTh(tableContext, footer.column.columnDef.meta?.footer?.classNames)
322
+ }, footer.isPlaceholder ? null : flexRender2(footer.column.columnDef.footer, footer.getContext()));
323
+ }), expand && /* @__PURE__ */ React4.createElement("th", null))));
324
+ };
325
+ TableFooter.displayName = TABLE_FOOTER_NAME;
326
+
327
+ // packages/ui/react-ui-table/src/components/Table/TableHead.tsx
328
+ import { flexRender as flexRender3 } from "@tanstack/react-table";
329
+ import React5 from "react";
330
+ import { mx as mx3 } from "@dxos/react-ui-theme";
331
+ var TABLE_HEAD_NAME = "TableHead";
332
+ var TableHead = (_props) => {
333
+ const tableContext = useTableContext(TABLE_HEAD_NAME);
334
+ const headerGroups = tableContext.table.getHeaderGroups();
335
+ const state = tableContext.table.getState();
336
+ return /* @__PURE__ */ React5.createElement("thead", {
337
+ className: theadRoot(tableContext)
338
+ }, headerGroups.map((headerGroup) => {
339
+ return (
340
+ // Group element to hover resize handles.
341
+ /* @__PURE__ */ React5.createElement("tr", {
342
+ key: headerGroup.id,
343
+ className: theadTr(tableContext)
344
+ }, tableContext.debug && /* @__PURE__ */ React5.createElement("th", {
345
+ className: "font-mono",
346
+ style: {
347
+ width: 32
348
+ }
349
+ }, "#"), headerGroup.headers.map((header) => {
350
+ const isResizing = header.column.getIsResizing();
351
+ return /* @__PURE__ */ React5.createElement("th", {
352
+ key: header.id,
353
+ style: {
354
+ width: header.getSize()
355
+ },
356
+ className: theadTh(tableContext, header.column.columnDef.meta?.header?.classNames)
357
+ }, !header || header.isPlaceholder ? null : flexRender3(header.column.columnDef.header, header.getContext()), header.column.columnDef.meta?.resizable && /* @__PURE__ */ React5.createElement("div", {
358
+ className: theadResizeRoot(tableContext, isResizing && "hidden"),
359
+ style: {
360
+ transform: `translateX(${isResizing ? state.columnSizingInfo.deltaOffset : 0}px)`
361
+ },
362
+ onMouseDown: header.getResizeHandler(),
363
+ onTouchStart: header.getResizeHandler()
364
+ }, /* @__PURE__ */ React5.createElement("div", {
365
+ className: mx3(theadResizeThumb(tableContext))
366
+ })));
367
+ }), tableContext.expand && /* @__PURE__ */ React5.createElement("th", null))
368
+ );
369
+ }));
370
+ };
371
+ TableHead.displayName = TABLE_HEAD_NAME;
372
+
373
+ // packages/ui/react-ui-table/src/components/Table/Table.tsx
374
+ var Table = (props) => {
375
+ const { role, data = [], columns = [], onColumnResize, columnVisibility, header = true, footer, rowsSelectable, fullWidth, debug, onDataSelectionChange, classNames } = props;
376
+ const TableProvider2 = TableProvider;
377
+ const [rowSelection = {}, directlySetRowSelection] = useControllableState({
378
+ prop: props.rowSelection,
379
+ onChange: props.onRowSelectionChange,
380
+ defaultProp: props.defaultRowSelection
381
+ });
382
+ const handleRowSelectionChange = useCallback((updaterOrValue) => {
383
+ const nextRowSelection = typeof updaterOrValue === "function" ? updaterOrValue(rowSelection) : updaterOrValue;
384
+ if (rowsSelectable === "multi") {
385
+ directlySetRowSelection(nextRowSelection);
386
+ } else if (rowsSelectable) {
387
+ const nextRowSelectionKey = Object.keys(nextRowSelection).filter((id) => !rowSelection[id])[0];
388
+ directlySetRowSelection(nextRowSelectionKey ? {
389
+ [nextRowSelectionKey]: true
390
+ } : {});
391
+ } else {
392
+ directlySetRowSelection({});
393
+ }
271
394
  }, [
272
- select,
273
- selected
395
+ rowSelection,
396
+ directlySetRowSelection
274
397
  ]);
275
398
  const [columnSizingInfo, setColumnSizingInfo] = useState2({});
276
399
  const onColumnResizeDebounced = debounce((info) => onColumnResize?.(info), 500);
@@ -286,246 +409,88 @@ var Table = ({ slots = defaultTableSlots, ...props }) => {
286
409
  props.grouping
287
410
  ]);
288
411
  const table = useReactTable({
412
+ // Data
413
+ meta: {},
289
414
  data,
415
+ // Columns
290
416
  columns,
291
417
  defaultColumn: {
292
- size: 400,
293
- maxSize: 800
418
+ size: 256,
419
+ maxSize: 1024
294
420
  },
421
+ // Rows
295
422
  getCoreRowModel: getCoreRowModel(),
296
- meta: {},
297
- // TODO(burdon): Pagination.
298
- // TODO(burdon): Sorting.
299
- // TODO(burdon): Filtering.
423
+ // State
300
424
  state: {
301
425
  columnVisibility,
302
426
  columnSizingInfo,
303
427
  rowSelection,
304
428
  grouping
305
429
  },
306
- // Grouping.
430
+ // Grouping
307
431
  getGroupedRowModel: getGroupedRowModel(),
308
432
  onGroupingChange: setGrouping,
309
- // Selection.
310
- enableRowSelection: select === "single" || select === "single-toggle",
311
- enableMultiRowSelection: select === "multiple" || select === "multiple-toggle",
312
- onRowSelectionChange: (rows) => {
313
- setRowSelection(rows);
314
- },
315
- // Resize columns.
316
- // TODO(burdon): Drag to re-order columns.
433
+ // Selection
434
+ ...rowsSelectable === "multi" ? {
435
+ enableMultiRowSelection: true
436
+ } : rowsSelectable ? {
437
+ enableRowSelection: true
438
+ } : {},
439
+ onRowSelectionChange: handleRowSelectionChange,
440
+ // Resize columns
317
441
  columnResizeMode: "onChange",
318
442
  enableColumnResizing: true,
319
443
  onColumnSizingInfoChange: setColumnSizingInfo,
444
+ // Debug
320
445
  debugTable: debug
321
446
  });
322
- const expand = false;
323
- const containerRef = usePinToBottom(data, pinToBottom);
324
- const handleSelect = (row) => {
325
- if (select) {
326
- setRowSelection((selectionState) => {
327
- const newSelectionState = updateSelection(selectionState, row.id, select);
328
- if (onSelectedChange) {
329
- const rows = Object.keys(newSelectionState).map((id) => table.getRowModel().rowsById[id].original);
330
- onSelectedChange(rows);
331
- }
332
- return newSelectionState;
333
- });
334
- } else {
335
- onSelectedChange?.([
336
- row.original
337
- ]);
338
- }
339
- };
340
- return /* @__PURE__ */ React2.createElement("div", {
341
- ref: containerRef,
342
- className: mx2("grow overflow-auto", slots?.root?.className)
343
- }, /* @__PURE__ */ React2.createElement("table", {
344
- // Styles:
345
- // table-fixed: Prevents fixed sized columns from shrinking.
346
- className: mx2(!fullWidth && "table-fixed", inputSurface, slots?.table?.className),
347
- style: {
348
- width: fullWidth ? "100%" : table.getTotalSize()
447
+ useEffect(() => {
448
+ if (onDataSelectionChange) {
449
+ onDataSelectionChange(Object.keys(rowSelection).map((id) => table.getRowModel().rowsById[id].original));
349
450
  }
350
- }, /* @__PURE__ */ React2.createElement(TableHead, {
451
+ }, [
452
+ onDataSelectionChange,
453
+ rowSelection,
454
+ table
455
+ ]);
456
+ const expand = false;
457
+ return /* @__PURE__ */ React6.createElement(TableProvider2, {
351
458
  ...props,
352
- slots,
353
459
  header,
354
- state: table.getState(),
355
- headers: table.getHeaderGroups()
356
- }), grouping.length === 0 && /* @__PURE__ */ React2.createElement(TableBody, {
357
- ...props,
358
- slots,
359
- rowSelection,
360
460
  expand,
361
- focus,
362
- onFocus: setFocus,
363
- onSelect: handleSelect,
461
+ table,
462
+ isGrid: role === "grid" || role === "treegrid"
463
+ }, /* @__PURE__ */ React6.createElement("table", {
464
+ role,
465
+ className: tableRoot(props, classNames),
466
+ ...!fullWidth && {
467
+ style: {
468
+ width: table.getTotalSize()
469
+ }
470
+ }
471
+ }, /* @__PURE__ */ React6.createElement(TableHead, null), grouping.length === 0 && /* @__PURE__ */ React6.createElement(TableBody, {
364
472
  rows: table.getRowModel().rows
365
473
  }), grouping.length !== 0 && table.getGroupedRowModel().rows.map((row, i) => {
366
- return /* @__PURE__ */ React2.createElement(Fragment, {
474
+ return /* @__PURE__ */ React6.createElement(Fragment, {
367
475
  key: i
368
- }, /* @__PURE__ */ React2.createElement("thead", null, /* @__PURE__ */ React2.createElement("tr", null, slots?.margin && /* @__PURE__ */ React2.createElement("th", {
369
- className: mx2(slots?.margin?.className)
370
- }), debug && /* @__PURE__ */ React2.createElement("th", null), /* @__PURE__ */ React2.createElement("th", {
476
+ }, /* @__PURE__ */ React6.createElement("thead", null, /* @__PURE__ */ React6.createElement("tr", null, debug && /* @__PURE__ */ React6.createElement("th", null), /* @__PURE__ */ React6.createElement("th", {
371
477
  // TODO(burdon): Calculate row span.
372
478
  colSpan: table.getHeaderGroups()[0].headers.length,
373
- className: mx2("text-left", slots?.group?.className)
374
- }, table.getState().grouping[0], "[", String(row.getGroupingValue(table.getState().grouping[0])), "]"))), /* @__PURE__ */ React2.createElement(TableBody, {
375
- ...props,
376
- slots,
377
- rowSelection,
378
- expand,
379
- focus,
380
- onFocus: setFocus,
381
- onSelect: handleSelect,
479
+ className: groupTh(props)
480
+ }, table.getState().grouping[0], "[", String(row.getGroupingValue(table.getState().grouping[0])), "]"))), /* @__PURE__ */ React6.createElement(TableBody, {
382
481
  rows: row.subRows
383
482
  }));
384
- }), footer && /* @__PURE__ */ React2.createElement(TableFoot, {
385
- ...props,
386
- slots,
387
- footers: table.getFooterGroups()
388
- })), debug && /* @__PURE__ */ React2.createElement("pre", {
483
+ }), footer && /* @__PURE__ */ React6.createElement(TableFooter, null)), debug && /* @__PURE__ */ React6.createElement("pre", {
389
484
  className: "font-mono text-xs text-neutral-500 my-4 p-2 ring"
390
- }, /* @__PURE__ */ React2.createElement("code", null, JSON.stringify(table.getState(), void 0, 2))));
391
- };
392
- var usePinToBottom = (data, pinToBottom) => {
393
- const containerRef = useRef2(null);
394
- const [stickyScrolling, setStickyScrolling] = useState2(true);
395
- useEffect(() => {
396
- const container = containerRef.current;
397
- if (!pinToBottom || !container) {
398
- return;
399
- }
400
- const handler = () => {
401
- const bottom = container.scrollHeight - container.scrollTop - container.clientHeight === 0;
402
- setStickyScrolling(bottom);
403
- };
404
- container.addEventListener("scroll", handler);
405
- return () => container.removeEventListener("scroll", handler);
406
- }, []);
407
- useEffect(() => {
408
- if (!pinToBottom || !containerRef.current || !stickyScrolling) {
409
- return;
410
- }
411
- containerRef.current?.scroll({
412
- top: containerRef.current.scrollHeight
413
- });
414
- }, [
415
- data
416
- ]);
417
- return containerRef;
418
- };
419
- var TableHead = ({ state, headers, expand, header, debug, fullWidth, border, slots }) => {
420
- return /* @__PURE__ */ React2.createElement("thead", {
421
- className: mx2(header ? [
422
- "sticky top-0 z-10"
423
- ] : "collapse")
424
- }, headers.map((headerGroup) => {
425
- return (
426
- // Group element to hover resize handles.
427
- /* @__PURE__ */ React2.createElement("tr", {
428
- key: headerGroup.id,
429
- className: "font-light group"
430
- }, slots?.margin && /* @__PURE__ */ React2.createElement("th", {
431
- className: mx2(slots?.margin?.className)
432
- }), debug && /* @__PURE__ */ React2.createElement("th", {
433
- className: "text-left",
434
- style: {
435
- width: 32
436
- }
437
- }, "#"), headerGroup.headers.map((header2) => {
438
- return /* @__PURE__ */ React2.createElement("th", {
439
- key: header2.id,
440
- style: {
441
- // Don't set width if fullWidth and no explicit size.
442
- width: fullWidth && header2.column.columnDef.meta?.expand ? void 0 : header2.getSize()
443
- },
444
- // Relative for resize handle.
445
- // TODO(burdon): Border scrolls with main content.
446
- // https://stackoverflow.com/questions/50361698/border-style-do-not-work-with-sticky-position-element
447
- className: mx2("relative text-left", border && groupBorder, slots?.header?.className, header2.column.columnDef.meta?.slots?.header?.className)
448
- }, !header2 || header2.isPlaceholder ? null : flexRender(header2.column.columnDef.header, header2.getContext()), header2.column.columnDef.meta?.resizable && /* @__PURE__ */ React2.createElement("div", {
449
- className: mx2("absolute top-0 pl-1 h-full z-[10] w-[7px] -right-[5px]", "cursor-col-resize select-none touch-none opacity-20 hover:opacity-100", header2.column.getIsResizing() && "hidden"),
450
- style: {
451
- transform: header2.column.getIsResizing() ? `translateX(${state.columnSizingInfo.deltaOffset}px)` : void 0
452
- },
453
- onMouseDown: header2.getResizeHandler(),
454
- onTouchStart: header2.getResizeHandler()
455
- }, /* @__PURE__ */ React2.createElement("div", {
456
- className: "flex group-hover:bg-neutral-700 -ml-[2px] w-[1px] h-full"
457
- })));
458
- }), expand && /* @__PURE__ */ React2.createElement("th", null), slots?.margin && /* @__PURE__ */ React2.createElement("th", {
459
- className: mx2(slots?.margin?.className)
460
- }))
461
- );
462
- }));
463
- };
464
- var TableBody = ({ keyAccessor, rows, rowSelection, focus, onFocus, onSelect, debug, border, expand, slots }) => {
465
- return /* @__PURE__ */ React2.createElement("tbody", null, rows.map((row) => {
466
- return /* @__PURE__ */ React2.createElement("tr", {
467
- key: keyAccessor ? keyAccessor(row.original) : row.id,
468
- onClick: () => onSelect?.(row),
469
- role: "button",
470
- className: mx2("group", rowSelection[row.id] && slots?.selected?.className, focus === row.id && slots?.focus?.className, slots?.row?.className)
471
- }, slots?.margin && /* @__PURE__ */ React2.createElement("td", {
472
- className: mx2(slots?.margin?.className)
473
- }, /* @__PURE__ */ React2.createElement("button", {
474
- role: "button",
475
- style: {
476
- width: 1,
477
- height: 1
478
- },
479
- className: "focus:outline-none",
480
- onFocus: () => onFocus?.(keyAccessor ? keyAccessor(row.original) : row.id),
481
- onBlur: () => onFocus?.(void 0),
482
- onKeyDown: (event) => {
483
- switch (event.key) {
484
- case "ArrowUp": {
485
- break;
486
- }
487
- case "ArrowDown": {
488
- break;
489
- }
490
- }
491
- }
492
- })), debug && /* @__PURE__ */ React2.createElement("td", null, row.id), row.getVisibleCells().map((cell) => {
493
- return /* @__PURE__ */ React2.createElement("td", {
494
- key: cell.id,
495
- className: mx2(border && groupBorder, slots?.cell?.className, cell.column.columnDef.meta?.slots?.cell?.className)
496
- }, flexRender(cell.column.columnDef.cell, {
497
- className: "px-2",
498
- ...cell.getContext()
499
- }));
500
- }), expand && /* @__PURE__ */ React2.createElement("td", null), slots?.margin && /* @__PURE__ */ React2.createElement("td", {
501
- className: mx2(slots?.margin?.className)
502
- }));
503
- }));
504
- };
505
- var TableFoot = ({ footers, expand, slots, debug, border }) => {
506
- return /* @__PURE__ */ React2.createElement("tfoot", {
507
- className: mx2("sticky bottom-0 z-[10]", slots?.footer?.className)
508
- }, footers.map((footerGroup) => /* @__PURE__ */ React2.createElement("tr", {
509
- key: footerGroup.id,
510
- className: "font-thin"
511
- }, slots?.margin && /* @__PURE__ */ React2.createElement("th", {
512
- className: mx2(slots?.margin?.className)
513
- }), debug && /* @__PURE__ */ React2.createElement("th", null), footerGroup.headers.map((footer) => {
514
- return /* @__PURE__ */ React2.createElement("th", {
515
- key: footer.id,
516
- className: mx2(border && groupBorder, "text-left", slots?.footer?.className, footer.column.columnDef.meta?.slots?.footer?.className)
517
- }, footer.isPlaceholder ? null : flexRender(footer.column.columnDef.footer, footer.getContext()));
518
- }), expand && /* @__PURE__ */ React2.createElement("th", null), slots?.margin && /* @__PURE__ */ React2.createElement("th", {
519
- className: mx2(slots?.margin?.className)
520
- }))));
485
+ }, /* @__PURE__ */ React6.createElement("code", null, JSON.stringify(table.getState(), void 0, 2))));
521
486
  };
522
487
 
523
- // packages/ui/react-ui-table/src/components/ComboboxCell.tsx
488
+ // packages/ui/react-ui-table/src/components/Cell/CellCombobox.tsx
524
489
  import { CaretDown as CaretDown2 } from "@phosphor-icons/react";
525
- import React3, { useCallback, useState as useState3 } from "react";
490
+ import React7, { useCallback as useCallback2, useState as useState3 } from "react";
526
491
  import { Popover as Popover2, useTranslation } from "@dxos/react-ui";
527
492
  import { PopoverCombobox } from "@dxos/react-ui-searchlist";
528
- import { descriptionText, getSize as getSize2, mx as mx3, staticPlaceholderText } from "@dxos/react-ui-theme";
493
+ import { descriptionText, getSize as getSize2, mx as mx4, staticPlaceholderText } from "@dxos/react-ui-theme";
529
494
 
530
495
  // packages/ui/react-ui-table/src/translations.ts
531
496
  var translationKey = "table";
@@ -539,14 +504,14 @@ var translations_default = [
539
504
  }
540
505
  ];
541
506
 
542
- // packages/ui/react-ui-table/src/components/ComboboxCell.tsx
507
+ // packages/ui/react-ui-table/src/components/Cell/CellCombobox.tsx
543
508
  var initialItems = (model, value) => value ? {
544
509
  [model.getId(value)]: {
545
510
  label: model.getText(value),
546
511
  data: value
547
512
  }
548
513
  } : {};
549
- var ComboboxCell = ({ model, value, onValueChange }) => {
514
+ var CellCombobox = ({ model, value, onValueChange }) => {
550
515
  const { t } = useTranslation(translationKey);
551
516
  const [items, setItems] = useState3(initialItems(model, value));
552
517
  const [loading, setLoading] = useState3(false);
@@ -564,284 +529,370 @@ var ComboboxCell = ({ model, value, onValueChange }) => {
564
529
  }, initialItems(model, value)));
565
530
  setLoading(false);
566
531
  };
567
- const handleValueChange = useCallback((id) => {
532
+ const handleValueChange = useCallback2((id) => {
568
533
  onValueChange(items[id]?.data);
569
534
  }, [
570
535
  items,
571
536
  onValueChange
572
537
  ]);
573
- return /* @__PURE__ */ React3.createElement(PopoverCombobox.Root, {
538
+ return /* @__PURE__ */ React7.createElement(PopoverCombobox.Root, {
574
539
  placeholder: t("no selection label")
575
- }, /* @__PURE__ */ React3.createElement(PopoverCombobox.Trigger, {
540
+ }, /* @__PURE__ */ React7.createElement(PopoverCombobox.Trigger, {
576
541
  variant: "ghost",
577
- classNames: "is-full"
578
- }, value ? /* @__PURE__ */ React3.createElement(React3.Fragment, null, /* @__PURE__ */ React3.createElement("span", {
579
- className: mx3("font-normal text-start flex-1 min-is-0 truncate mie-2", !value && staticPlaceholderText)
580
- }, model.getText(value)), /* @__PURE__ */ React3.createElement(CaretDown2, {
542
+ classNames: "is-full rounded-none ring-inset"
543
+ }, value ? /* @__PURE__ */ React7.createElement(React7.Fragment, null, /* @__PURE__ */ React7.createElement("span", {
544
+ className: mx4("font-normal text-start flex-1 min-is-0 truncate mie-2", !value && staticPlaceholderText)
545
+ }, model.getText(value)), /* @__PURE__ */ React7.createElement(CaretDown2, {
581
546
  weight: "bold",
582
547
  className: getSize2(3)
583
- })) : null), /* @__PURE__ */ React3.createElement(PopoverCombobox.Content, {
548
+ })) : null), /* @__PURE__ */ React7.createElement(PopoverCombobox.Content, {
584
549
  shouldFilter: false,
585
550
  classNames: "is-[--radix-popover-trigger-width]"
586
- }, /* @__PURE__ */ React3.createElement(PopoverCombobox.Input, {
551
+ }, /* @__PURE__ */ React7.createElement(PopoverCombobox.Input, {
587
552
  value: searchInputValue,
588
553
  onValueChange: handleSearchInputValueChange
589
- }), /* @__PURE__ */ React3.createElement(PopoverCombobox.List, null, searchInputValue.length < 1 ? /* @__PURE__ */ React3.createElement("p", {
590
- className: mx3("text-center", descriptionText)
591
- }, "Start typing to search") : loading ? /* @__PURE__ */ React3.createElement("p", {
592
- className: mx3("text-center", descriptionText)
593
- }, "Searching\u2026") : /* @__PURE__ */ React3.createElement(React3.Fragment, null, /* @__PURE__ */ React3.createElement(PopoverCombobox.Empty, {
554
+ }), /* @__PURE__ */ React7.createElement(PopoverCombobox.List, null, searchInputValue.length < 1 ? /* @__PURE__ */ React7.createElement("p", {
555
+ className: mx4("text-center", descriptionText)
556
+ }, "Start typing to search") : loading ? /* @__PURE__ */ React7.createElement("p", {
557
+ className: mx4("text-center", descriptionText)
558
+ }, "Searching\u2026") : /* @__PURE__ */ React7.createElement(React7.Fragment, null, /* @__PURE__ */ React7.createElement(PopoverCombobox.Empty, {
594
559
  classNames: [
595
560
  "text-center",
596
561
  descriptionText
597
562
  ]
598
- }, "No results"), Object.entries(items).map(([id, { label }]) => /* @__PURE__ */ React3.createElement(PopoverCombobox.Item, {
563
+ }, "No results"), Object.entries(items).map(([id, { label }]) => /* @__PURE__ */ React7.createElement(PopoverCombobox.Item, {
599
564
  key: id,
600
565
  value: id,
601
566
  onSelect: handleValueChange,
602
567
  classNames: "truncate"
603
- }, label)))), /* @__PURE__ */ React3.createElement(Popover2.Arrow, null)));
568
+ }, label)))), /* @__PURE__ */ React7.createElement(Popover2.Arrow, null)));
604
569
  };
605
570
 
606
571
  // packages/ui/react-ui-table/src/helpers.tsx
607
- import { useFocusFinders } from "@fluentui/react-tabster";
608
572
  import { Check as Check2, ClipboardText, X as X2 } from "@phosphor-icons/react";
609
573
  import { createColumnHelper } from "@tanstack/react-table";
610
574
  import format from "date-fns/format";
611
575
  import formatDistanceToNow from "date-fns/formatDistanceToNow";
612
- import defaultsDeep from "lodash.defaultsdeep";
613
- import React4, { useRef as useRef3, useState as useState4 } from "react";
576
+ import React8, { useRef as useRef2, useState as useState4 } from "react";
614
577
  import { Input as Input2, Tooltip } from "@dxos/react-ui";
615
- import { getSize as getSize3, mx as mx4 } from "@dxos/react-ui-theme";
616
- import { stripUndefinedValues } from "@dxos/util";
617
- var findNextFocusable = (findFirstFocusable, container) => {
618
- const next = findFirstFocusable(container);
619
- if (next) {
620
- if (next?.tagName === "INPUT") {
621
- return next;
622
- }
623
- if (container.nextElementSibling) {
624
- return findNextFocusable(findFirstFocusable, container.nextSibling);
625
- }
626
- }
627
- };
578
+ import { getSize as getSize3, mx as mx5 } from "@dxos/react-ui-theme";
628
579
  var createColumnBuilder = () => ({
629
580
  helper: createColumnHelper(),
630
581
  builder: new ColumnBuilder()
631
582
  });
632
- var defaults = (options, ...sources) => {
633
- return stripUndefinedValues(defaultsDeep({}, options, ...sources));
583
+ var ComboboxBuilderCell = (cellContext) => {
584
+ const { model, onUpdate } = cellContext.column.columnDef.meta;
585
+ return model ? /* @__PURE__ */ React8.createElement(CellCombobox, {
586
+ model,
587
+ value: cellContext.getValue(),
588
+ onValueChange: (value) => onUpdate?.(cellContext.row.original, cellContext.column.id, value)
589
+ }) : null;
590
+ };
591
+ var StringBuilderCell = (cellContext) => {
592
+ const { onUpdate } = cellContext.column.columnDef.meta;
593
+ const initialValue = cellContext.getValue();
594
+ const [value, setValue] = useState4(initialValue);
595
+ const inputRef = useRef2(null);
596
+ const handleSave = () => {
597
+ if (value === initialValue) {
598
+ return;
599
+ }
600
+ onUpdate?.(cellContext.row.original, cellContext.column.id, value);
601
+ };
602
+ const handleCancel = () => {
603
+ setValue(initialValue);
604
+ };
605
+ const rows = cellContext.table.getRowModel().flatRows;
606
+ const columns = cellContext.table.getVisibleFlatColumns();
607
+ const placeholder = cellContext.row.index === rows.length - 1 && columns[0].id === cellContext.column.id;
608
+ return /* @__PURE__ */ React8.createElement(Input2.Root, null, /* @__PURE__ */ React8.createElement(Input2.TextInput, {
609
+ ref: inputRef,
610
+ variant: "subdued",
611
+ placeholder: placeholder ? "Add row..." : void 0,
612
+ classNames: [
613
+ "is-full",
614
+ textPadding
615
+ ],
616
+ value: value ?? "",
617
+ onBlur: () => handleSave(),
618
+ onChange: (event) => setValue(event.target.value),
619
+ onKeyDown: (event) => event.key === "Enter" && handleSave() || event.key === "Escape" && handleCancel()
620
+ }));
621
+ };
622
+ var NumberBuilderCell = (cellContext) => {
623
+ const { onUpdate, cell, digits } = cellContext.column.columnDef.meta;
624
+ const value = cellContext.getValue();
625
+ const [text, setText] = useState4();
626
+ const handleEdit = () => {
627
+ if (onUpdate) {
628
+ setText(value !== void 0 ? String(value) : "");
629
+ }
630
+ };
631
+ const handleSave = () => {
632
+ const value2 = text?.trim().length ? Number(text) : NaN;
633
+ onUpdate?.(cellContext.row.original, cellContext.column.id, isNaN(value2) ? void 0 : value2);
634
+ setText(void 0);
635
+ };
636
+ const handleCancel = () => {
637
+ setText(void 0);
638
+ };
639
+ if (text !== void 0) {
640
+ return /* @__PURE__ */ React8.createElement(Input2.Root, null, /* @__PURE__ */ React8.createElement(Input2.TextInput, {
641
+ value: text,
642
+ classNames: [
643
+ "is-full text-end font-mono"
644
+ ],
645
+ onBlur: handleSave,
646
+ onChange: (event) => setText(event.target.value),
647
+ onKeyDown: (event) => event.key === "Escape" && handleCancel() || event.key === "Enter" && handleSave()
648
+ }));
649
+ }
650
+ return /* @__PURE__ */ React8.createElement("div", {
651
+ className: mx5('is-full text-end font-mono empty:after:content-["\xA0"]', textPadding, cell?.classNames),
652
+ onClick: handleEdit
653
+ }, value?.toLocaleString(void 0, {
654
+ minimumFractionDigits: digits ?? 0,
655
+ maximumFractionDigits: digits ?? 2
656
+ }));
657
+ };
658
+ var RowSelectorBuilderCell = (cellContext) => {
659
+ const { cell } = cellContext.column.columnDef.meta;
660
+ const { row } = cellContext;
661
+ const checked = row.getCanSelect() ? row.getIsSelected() : row.getCanSelectSubRows() && (row.getIsSomeSelected() ? "indeterminate" : row.getIsAllSubRowsSelected());
662
+ return /* @__PURE__ */ React8.createElement(Input2.Root, null, /* @__PURE__ */ React8.createElement(Input2.Checkbox, {
663
+ size: 4,
664
+ classNames: [
665
+ "mli-auto",
666
+ cell?.classNames
667
+ ],
668
+ checked,
669
+ onCheckedChange: (event) => {
670
+ if (row.getCanSelect()) {
671
+ row.getToggleSelectedHandler()(event);
672
+ }
673
+ },
674
+ disabled: !(row.getCanSelect() || row.getCanSelectSubRows())
675
+ }));
676
+ };
677
+ var SwitchBuilderCell = (cellContext) => {
678
+ const { onUpdate } = cellContext.column.columnDef.meta;
679
+ const value = cellContext.getValue();
680
+ return /* @__PURE__ */ React8.createElement(Input2.Root, null, /* @__PURE__ */ React8.createElement(Input2.Switch, {
681
+ classNames: "block mli-auto",
682
+ onClick: (event) => event.stopPropagation(),
683
+ disabled: !onUpdate,
684
+ checked: !!value,
685
+ onCheckedChange: (value2) => {
686
+ onUpdate?.(cellContext.row.original, cellContext.column.id, !!value2);
687
+ }
688
+ }));
634
689
  };
635
690
  var ColumnBuilder = class {
636
691
  /**
637
- * Select value
692
+ * Combobox value
638
693
  */
639
- select({ label, className, model, onUpdate, ...props }) {
640
- return defaults(props, {
694
+ combobox({ label, classNames, model, onUpdate, ...props }) {
695
+ return {
696
+ ...props,
641
697
  minSize: 100,
698
+ meta: {
699
+ ...props.meta,
700
+ model,
701
+ onUpdate,
702
+ cell: {
703
+ classNames,
704
+ ...props.meta?.cell
705
+ }
706
+ },
642
707
  header: (column) => {
643
- return /* @__PURE__ */ React4.createElement("div", {
644
- className: "truncate"
645
- }, label ?? column.header.id);
708
+ return label ?? column.header.id;
646
709
  },
647
- cell: model && onUpdate ? (cell) => /* @__PURE__ */ React4.createElement(ComboboxCell, {
648
- model,
649
- value: cell.getValue(),
650
- onValueChange: (value) => onUpdate?.(cell.row.original, cell.column.id, value)
651
- }) : (cell) => {
652
- const value = cell.getValue();
653
- return /* @__PURE__ */ React4.createElement("div", {
654
- className: mx4("truncate", className)
655
- }, value ? model.getText(value) : "");
710
+ cell: model && onUpdate ? ComboboxBuilderCell : (cellContext) => {
711
+ const cellValue = cellContext.getValue();
712
+ return /* @__PURE__ */ React8.createElement("div", {
713
+ className: mx5("truncate", classNames)
714
+ }, cellValue ? model?.getText(cellValue) : "");
656
715
  }
657
- });
716
+ };
658
717
  }
659
718
  /**
660
719
  * String formats.
661
720
  */
662
- string({ label, className, onUpdate, ...props } = {}) {
663
- return defaults(props, {
721
+ string({ label, classNames, onUpdate, ...props } = {}) {
722
+ return {
723
+ ...props,
664
724
  minSize: 100,
725
+ meta: {
726
+ ...props.meta,
727
+ onUpdate,
728
+ cell: {
729
+ ...props.meta?.cell,
730
+ classNames
731
+ }
732
+ },
665
733
  // TODO(burdon): Default.
666
734
  header: (column) => {
667
- return /* @__PURE__ */ React4.createElement("div", {
668
- className: "truncate"
669
- }, label ?? column.header.id);
735
+ return label ?? column.header.id;
670
736
  },
671
- cell: onUpdate ? (cell) => {
672
- const initialValue = cell.getValue();
673
- const [value, setValue] = useState4(initialValue);
674
- const inputRef = useRef3(null);
675
- const { findFirstFocusable } = useFocusFinders();
676
- const handleSave = (focusNext = false) => {
677
- if (value === initialValue) {
678
- return;
679
- }
680
- onUpdate?.(cell.row.original, cell.column.id, value);
681
- if (focusNext) {
682
- const rowElement = inputRef.current?.parentElement?.parentElement;
683
- setTimeout(() => {
684
- const next = findNextFocusable(findFirstFocusable, rowElement);
685
- next?.focus();
686
- });
687
- }
688
- };
689
- const handleCancel = () => {
690
- setValue(initialValue);
691
- };
692
- const rows = cell.table.getRowModel().flatRows;
693
- const columns = cell.table.getVisibleFlatColumns();
694
- const placeholder = cell.row.index === rows.length - 1 && columns[0].id === cell.column.id;
695
- return /* @__PURE__ */ React4.createElement(Input2.Root, null, /* @__PURE__ */ React4.createElement(Input2.TextInput, {
696
- ref: inputRef,
697
- variant: "subdued",
698
- placeholder: placeholder ? "Add row..." : void 0,
699
- classNames: "px-2",
700
- value: value ?? "",
701
- onBlur: () => handleSave(false),
702
- onChange: (event) => setValue(event.target.value),
703
- onKeyDown: (event) => event.key === "Enter" && handleSave(true) || event.key === "Escape" && handleCancel()
704
- }));
705
- } : (cell) => {
737
+ cell: onUpdate ? StringBuilderCell : (cell) => {
706
738
  const value = cell.getValue();
707
- return /* @__PURE__ */ React4.createElement("div", {
708
- className: mx4("truncate", className)
739
+ return /* @__PURE__ */ React8.createElement("div", {
740
+ className: mx5("truncate", textPadding, classNames)
709
741
  }, value);
710
742
  }
711
- });
743
+ };
712
744
  }
713
745
  /**
714
746
  * Number formats.
715
747
  */
716
- number({ label, minSize, className, digits, onUpdate, ...props } = {}) {
717
- return defaults(props, {
748
+ number({ label, minSize, classNames, digits, onUpdate, ...props } = {}) {
749
+ return {
750
+ ...props,
718
751
  size: 100,
719
752
  minSize: 100,
720
- header: (cell) => /* @__PURE__ */ React4.createElement("div", {
721
- className: "w-full truncate text-right"
722
- }, label ?? cell.header.id),
723
- cell: (cell) => {
724
- const value = cell.getValue();
725
- const [text, setText] = useState4();
726
- const handleEdit = () => {
727
- if (onUpdate) {
728
- setText(value !== void 0 ? String(value) : "");
729
- }
730
- };
731
- const handleSave = () => {
732
- const value2 = text?.trim().length ? Number(text) : NaN;
733
- onUpdate?.(cell.row.original, cell.column.id, isNaN(value2) ? void 0 : value2);
734
- setText(void 0);
735
- };
736
- const handleCancel = () => {
737
- setText(void 0);
738
- };
739
- if (text !== void 0) {
740
- return /* @__PURE__ */ React4.createElement("div", {
741
- className: mx4("grow text-right font-mono", className)
742
- }, /* @__PURE__ */ React4.createElement(Input2.Root, null, /* @__PURE__ */ React4.createElement(Input2.TextInput, {
743
- autoFocus: true,
744
- value: text,
745
- classNames: "px-2",
746
- onBlur: handleSave,
747
- onChange: (event) => setText(event.target.value),
748
- onKeyDown: (event) => event.key === "Escape" && handleCancel() || event.key === "Enter" && handleSave()
749
- })));
753
+ meta: {
754
+ ...props.meta,
755
+ onUpdate,
756
+ digits,
757
+ header: {
758
+ classNames: "text-end",
759
+ ...props.meta?.header
760
+ },
761
+ cell: {
762
+ ...props.meta?.cell,
763
+ classNames
750
764
  }
751
- return /* @__PURE__ */ React4.createElement("div", {
752
- className: mx4('grow w-full text-right font-mono empty:after:content-["\xA0"]', className),
753
- onClick: handleEdit
754
- }, value?.toLocaleString(void 0, {
755
- minimumFractionDigits: digits ?? 0,
756
- maximumFractionDigits: digits ?? 2
757
- }));
758
- }
759
- });
765
+ },
766
+ header: (cell) => label ?? cell.header.id,
767
+ cell: NumberBuilderCell
768
+ };
760
769
  }
761
770
  /**
762
771
  * Date formats.
763
772
  */
764
773
  // TODO(burdon): Date picker (pluggable renderers?)
765
- date({ label, format: formatSpec, relative, className, ...props } = {}) {
766
- return defaults(props, {
774
+ date({ label, format: formatSpec, relative, classNames, ...props } = {}) {
775
+ return {
776
+ ...props,
767
777
  size: 220,
768
778
  minSize: 100,
769
- header: (cell) => /* @__PURE__ */ React4.createElement("div", null, label ?? cell.header.id),
779
+ meta: {
780
+ ...props.meta,
781
+ cell: {
782
+ ...props.meta?.cell,
783
+ classNames
784
+ }
785
+ },
786
+ header: (cell) => label ?? cell.header.id,
770
787
  cell: (cell) => {
771
788
  const value = cell.getValue();
772
789
  try {
773
790
  const str = value ? formatSpec ? format(value, formatSpec) : relative ? formatDistanceToNow(value, {
774
791
  addSuffix: true
775
792
  }) : value.toISOString() : void 0;
776
- return /* @__PURE__ */ React4.createElement("div", {
777
- className: mx4("font-mono", className)
793
+ return /* @__PURE__ */ React8.createElement("div", {
794
+ className: mx5(textPadding, classNames)
778
795
  }, str);
779
796
  } catch (err) {
780
797
  console.log(value);
781
798
  return null;
782
799
  }
783
800
  }
784
- });
801
+ };
785
802
  }
786
803
  /**
787
804
  * PublicKey with tooltip.
788
805
  */
789
- key({ label, tooltip, ...props } = {}) {
790
- return defaults(props, {
791
- size: 86,
792
- minSize: 86,
793
- header: (cell) => /* @__PURE__ */ React4.createElement("div", null, label ?? cell.header.id),
806
+ key({ label, tooltip, classNames, ...props } = {}) {
807
+ return {
808
+ ...props,
809
+ size: 94,
810
+ minSize: 94,
811
+ meta: {
812
+ ...props.meta,
813
+ cell: {
814
+ ...props.meta?.cell,
815
+ classNames: [
816
+ "font-mono",
817
+ textPadding,
818
+ classNames
819
+ ]
820
+ }
821
+ },
822
+ header: (cell) => label ?? cell.header.id,
794
823
  cell: (cell) => {
795
824
  const value = cell.getValue();
796
825
  if (!value) {
797
826
  return;
798
827
  }
799
- const element = /* @__PURE__ */ React4.createElement("div", {
800
- className: "font-mono font-thin text-green-500 dark:text-green-300"
801
- }, value.truncate());
828
+ const element = value.truncate();
802
829
  if (!tooltip) {
803
830
  return element;
804
831
  }
805
- return /* @__PURE__ */ React4.createElement("div", {
806
- className: "group inline-flex gap-2 items-center"
807
- }, /* @__PURE__ */ React4.createElement(Tooltip.Provider, null, /* @__PURE__ */ React4.createElement(Tooltip.Root, null, /* @__PURE__ */ React4.createElement(Tooltip.Trigger, {
808
- asChild: true
809
- }, element), /* @__PURE__ */ React4.createElement(Tooltip.Content, {
832
+ return /* @__PURE__ */ React8.createElement(Tooltip.Provider, null, /* @__PURE__ */ React8.createElement(Tooltip.Root, null, /* @__PURE__ */ React8.createElement(Tooltip.Trigger, null, element), /* @__PURE__ */ React8.createElement(Tooltip.Portal, null, /* @__PURE__ */ React8.createElement(Tooltip.Content, {
810
833
  side: "right"
811
- }, /* @__PURE__ */ React4.createElement(Tooltip.Arrow, null), /* @__PURE__ */ React4.createElement(ClipboardText, {
834
+ }, /* @__PURE__ */ React8.createElement(Tooltip.Arrow, null), /* @__PURE__ */ React8.createElement(ClipboardText, {
812
835
  onClick: (ev) => {
813
836
  ev.stopPropagation();
814
837
  void navigator.clipboard.writeText(value.toHex());
815
838
  }
816
839
  })))));
817
840
  }
818
- });
841
+ };
819
842
  }
820
843
  /**
821
- * Checkbox.
844
+ * Row selector
822
845
  */
823
- checkbox({ label, className, onUpdate, ...props } = {}) {
824
- return defaults(props, {
825
- size: 40,
826
- minSize: 40,
827
- header: (column) => /* @__PURE__ */ React4.createElement("div", {
828
- className: "flex grow justify-center"
829
- }, label ?? column.header.id),
830
- cell: (cell) => {
831
- const value = cell.getValue();
832
- return /* @__PURE__ */ React4.createElement("div", {
833
- className: "flex grow justify-center"
834
- }, /* @__PURE__ */ React4.createElement(Input2.Root, null, /* @__PURE__ */ React4.createElement(Input2.Checkbox, {
835
- onClick: (event) => event.stopPropagation(),
836
- classNames: className,
837
- disabled: !onUpdate,
838
- checked: !!value,
839
- onCheckedChange: (value2) => {
840
- onUpdate?.(cell.row.original, cell.column.id, !!value2);
841
- }
842
- })));
843
- }
844
- });
846
+ selectRow({ classNames, onUpdate, id = "selectRow" } = {}) {
847
+ return {
848
+ id,
849
+ size: 32,
850
+ minSize: 32,
851
+ maxSize: 32,
852
+ meta: {
853
+ onUpdate,
854
+ cell: {
855
+ classNames
856
+ }
857
+ },
858
+ header: ({ table }) => {
859
+ const { rowsSelectable } = useTableContext("HELPER_SELECT_ROW_HEADER_CELL");
860
+ const checked = table.getIsSomeRowsSelected() ? "indeterminate" : table.getIsAllRowsSelected();
861
+ return rowsSelectable === "multi" ? /* @__PURE__ */ React8.createElement(Input2.Root, null, /* @__PURE__ */ React8.createElement(Input2.Checkbox, {
862
+ size: 4,
863
+ classNames: [
864
+ "mli-auto",
865
+ classNames
866
+ ],
867
+ checked,
868
+ onCheckedChange: () => table.toggleAllRowsSelected()
869
+ })) : null;
870
+ },
871
+ cell: RowSelectorBuilderCell
872
+ };
873
+ }
874
+ /**
875
+ * Switch
876
+ */
877
+ switch({ label, classNames, onUpdate, ...props } = {}) {
878
+ return {
879
+ ...props,
880
+ size: 50,
881
+ minSize: 50,
882
+ meta: {
883
+ ...props.meta,
884
+ onUpdate,
885
+ cell: {
886
+ ...props.meta?.cell,
887
+ classNames: [
888
+ textPadding,
889
+ classNames
890
+ ]
891
+ }
892
+ },
893
+ header: (column) => label ?? column.header.id,
894
+ cell: SwitchBuilderCell
895
+ };
845
896
  }
846
897
  /**
847
898
  * Icon based on boolean value.
@@ -849,41 +900,56 @@ var ColumnBuilder = class {
849
900
  icon({ label, size, on, off, ...props } = {}) {
850
901
  const IconOn = on?.Icon ?? Check2;
851
902
  const IconOff = off?.Icon ?? X2;
852
- return defaults(props, {
903
+ return {
904
+ ...props,
853
905
  size: size ?? 32,
854
- header: (column) => /* @__PURE__ */ React4.createElement("div", {
906
+ header: (column) => /* @__PURE__ */ React8.createElement("div", {
855
907
  className: "justify-center"
856
908
  }, label ?? column.header.id),
857
909
  cell: (cell) => {
858
910
  const value = cell.getValue();
859
911
  if (value) {
860
- return /* @__PURE__ */ React4.createElement("div", {
861
- className: "flex grow justify-center"
862
- }, /* @__PURE__ */ React4.createElement(IconOn, {
863
- className: mx4(getSize3(6), on?.className ?? "text-green-700")
864
- }));
912
+ return /* @__PURE__ */ React8.createElement(IconOn, {
913
+ className: mx5("block mli-auto", getSize3(6), on?.className ?? "text-green-700")
914
+ });
865
915
  } else if (value === false) {
866
- return /* @__PURE__ */ React4.createElement("div", {
867
- className: "flex grow justify-center"
868
- }, /* @__PURE__ */ React4.createElement(IconOff, {
869
- className: mx4(getSize3(6), off?.className ?? "text-red-700")
870
- }));
916
+ return /* @__PURE__ */ React8.createElement(IconOff, {
917
+ className: mx5("block mli-auto", getSize3(6), off?.className ?? "text-red-700")
918
+ });
871
919
  } else {
872
920
  return null;
873
921
  }
874
922
  }
875
- });
923
+ };
876
924
  }
877
925
  };
878
926
  export {
927
+ CellCombobox,
879
928
  ColumnBuilder,
880
929
  ColumnMenu,
881
930
  ColumnPanel,
882
- ComboboxCell,
883
931
  Table,
884
932
  columnTypes,
885
933
  createColumnBuilder,
886
- defaultTableSlots,
887
- updateSelection
934
+ currentRow,
935
+ flushPadding,
936
+ gridCellFocusRing,
937
+ groupTh,
938
+ headPadding,
939
+ selectedRow,
940
+ tableRoot,
941
+ tbodyRoot,
942
+ tbodyTr,
943
+ tdContent,
944
+ tdRoot,
945
+ textPadding,
946
+ tfootRoot,
947
+ tfootTh,
948
+ tfootTr,
949
+ theadResizeRoot,
950
+ theadResizeThumb,
951
+ theadRoot,
952
+ theadTh,
953
+ theadTr
888
954
  };
889
955
  //# sourceMappingURL=index.mjs.map