@dxos/react-ui-table 0.3.9-main.325dd0a → 0.3.9-main.35e0812

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 (33) hide show
  1. package/dist/lib/browser/index.mjs +224 -158
  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/CellCombobox.d.ts.map +1 -1
  5. package/dist/types/src/components/ColumnMenu.d.ts.map +1 -1
  6. package/dist/types/src/components/ColumnMenu.stories.d.ts +1 -0
  7. package/dist/types/src/components/ColumnMenu.stories.d.ts.map +1 -1
  8. package/dist/types/src/components/Table/Table.d.ts.map +1 -1
  9. package/dist/types/src/components/Table/Table.stories.d.ts +1 -1
  10. package/dist/types/src/components/Table/Table.stories.d.ts.map +1 -1
  11. package/dist/types/src/components/Table/props.d.ts +6 -2
  12. package/dist/types/src/components/Table/props.d.ts.map +1 -1
  13. package/dist/types/src/helpers.d.ts +2 -2
  14. package/dist/types/src/helpers.d.ts.map +1 -1
  15. package/dist/types/src/index.d.ts +1 -0
  16. package/dist/types/src/index.d.ts.map +1 -1
  17. package/dist/types/src/schema.d.ts +0 -1
  18. package/dist/types/src/schema.d.ts.map +1 -1
  19. package/dist/types/src/theme.d.ts.map +1 -1
  20. package/dist/types/src/translations.d.ts +11 -0
  21. package/dist/types/src/translations.d.ts.map +1 -1
  22. package/package.json +12 -16
  23. package/src/components/Cell/CellCombobox.tsx +4 -1
  24. package/src/components/ColumnMenu.stories.tsx +3 -0
  25. package/src/components/ColumnMenu.tsx +16 -16
  26. package/src/components/Table/Table.stories.tsx +23 -12
  27. package/src/components/Table/Table.tsx +92 -26
  28. package/src/components/Table/props.ts +26 -14
  29. package/src/helpers.tsx +105 -84
  30. package/src/index.ts +1 -0
  31. package/src/schema.ts +0 -8
  32. package/src/theme.ts +2 -2
  33. package/src/translations.ts +11 -0
@@ -1,45 +1,42 @@
1
1
  // packages/ui/react-ui-table/src/components/ColumnMenu.tsx
2
2
  import { Check, CaretDown, Trash, X } from "@phosphor-icons/react";
3
3
  import React, { useRef, useState } from "react";
4
- import { Button, DensityProvider, Input, Popover, Select, Separator } from "@dxos/react-ui";
4
+ import { Button, DensityProvider, Input, Popover, Select, Separator, useTranslation } from "@dxos/react-ui";
5
5
  import { getSize, mx } from "@dxos/react-ui-theme";
6
6
  import { safeParseInt } from "@dxos/util";
7
7
 
8
- // packages/ui/react-ui-table/src/schema.ts
9
- var columnTypes = /* @__PURE__ */ new Map([
10
- [
11
- "string",
12
- "Text"
13
- ],
14
- [
15
- "boolean",
16
- "Checkbox"
17
- ],
18
- [
19
- "number",
20
- "Number"
21
- ],
22
- [
23
- "date",
24
- "Date"
25
- ],
26
- [
27
- "ref",
28
- "Reference"
29
- ]
30
- ]);
8
+ // packages/ui/react-ui-table/src/translations.ts
9
+ var translationKey = "table";
10
+ var translations_default = [
11
+ {
12
+ "en-US": {
13
+ [translationKey]: {
14
+ "no selection label": "\xA0",
15
+ "number column type label": "Number",
16
+ "boolean column type label": "Toggle",
17
+ "date column type label": "Date",
18
+ "string column type label": "Text",
19
+ "ref column type label": "Reference",
20
+ "digits label": "Decimal places",
21
+ "save label": "Save",
22
+ "delete label": "Delete",
23
+ "column label label": "Label",
24
+ "property key label": "Property",
25
+ "column type label": "Type"
26
+ }
27
+ }
28
+ }
29
+ ];
31
30
 
32
31
  // packages/ui/react-ui-table/src/components/ColumnMenu.tsx
33
32
  var ColumnMenu = ({ column, ...props }) => {
34
33
  const title = column.label?.length ? column.label : column.id;
35
34
  return /* @__PURE__ */ React.createElement("div", {
36
- className: "flex grow items-center overflow-hidden"
35
+ className: "flex items-center gap-2"
37
36
  }, /* @__PURE__ */ React.createElement("div", {
38
- className: "truncate",
37
+ className: "flex-1 min-is-0 truncate",
39
38
  title
40
39
  }, title), /* @__PURE__ */ React.createElement("div", {
41
- className: "grow"
42
- }), /* @__PURE__ */ React.createElement("div", {
43
40
  className: "flex shrink-0"
44
41
  }, /* @__PURE__ */ React.createElement(ColumnPanel, {
45
42
  ...props,
@@ -59,6 +56,7 @@ var ColumnPanel = ({ context, tableDefs, tableDef, column, onUpdate, onDelete })
59
56
  const [label, setLabel] = useState(column.label);
60
57
  const [digits, setDigits] = useState(String(column.digits ?? "0"));
61
58
  const propRef = useRef(null);
59
+ const { t } = useTranslation(translationKey);
62
60
  const handleCancel = () => {
63
61
  setProp(column.id);
64
62
  setOpen(false);
@@ -93,7 +91,7 @@ var ColumnPanel = ({ context, tableDefs, tableDef, column, onUpdate, onDelete })
93
91
  asChild: true
94
92
  }, /* @__PURE__ */ React.createElement(Button, {
95
93
  variant: "ghost",
96
- classNames: "p-0"
94
+ classNames: "p-1"
97
95
  }, /* @__PURE__ */ React.createElement(CaretDown, {
98
96
  className: getSize(4)
99
97
  }))), /* @__PURE__ */ React.createElement(Popover.Portal, null, /* @__PURE__ */ React.createElement(Popover.Content, null, /* @__PURE__ */ React.createElement(Popover.Viewport, {
@@ -104,14 +102,14 @@ var ColumnPanel = ({ context, tableDefs, tableDef, column, onUpdate, onDelete })
104
102
  className: "flex flex-col gap-1"
105
103
  }, /* @__PURE__ */ React.createElement(Section, null, /* @__PURE__ */ React.createElement(Input.Root, null, /* @__PURE__ */ React.createElement(Input.Label, {
106
104
  classNames: "mbe-1"
107
- }, "Label"), /* @__PURE__ */ React.createElement(Input.TextInput, {
105
+ }, t("column label label")), /* @__PURE__ */ React.createElement(Input.TextInput, {
108
106
  placeholder: "Column label",
109
107
  value: label ?? "",
110
108
  onChange: (event) => setLabel(event.target.value),
111
109
  autoFocus: true
112
110
  })), /* @__PURE__ */ React.createElement(Input.Root, null, /* @__PURE__ */ React.createElement(Input.Label, {
113
111
  classNames: "mbe-1 mbs-3"
114
- }, "Property"), /* @__PURE__ */ React.createElement(Input.TextInput, {
112
+ }, t("property key label")), /* @__PURE__ */ React.createElement(Input.TextInput, {
115
113
  ref: propRef,
116
114
  placeholder: "Property key",
117
115
  // TODO(burdon): Provide hooks for value normalization, ENTER, ESC, etc.
@@ -119,18 +117,23 @@ var ColumnPanel = ({ context, tableDefs, tableDef, column, onUpdate, onDelete })
119
117
  onChange: (event) => setProp(event.target.value.replace(/[^\w_]/g, ""))
120
118
  })), /* @__PURE__ */ React.createElement(Input.Root, null, /* @__PURE__ */ React.createElement(Input.Label, {
121
119
  classNames: "mbe-1 mbs-3"
122
- }, "Type"), /* @__PURE__ */ React.createElement(Select.Root, {
120
+ }, t("column type label")), /* @__PURE__ */ React.createElement(Select.Root, {
123
121
  value: type,
124
122
  onValueChange: setType
125
123
  }, /* @__PURE__ */ React.createElement(Select.TriggerButton, {
126
124
  placeholder: "Type",
127
125
  classNames: "is-full"
128
- }), /* @__PURE__ */ React.createElement(Select.Portal, null, /* @__PURE__ */ React.createElement(Select.Content, null, /* @__PURE__ */ React.createElement(Select.Viewport, null, Array.from(columnTypes.entries()).map(([type2, label2]) => /* @__PURE__ */ React.createElement(Select.Option, {
126
+ }), /* @__PURE__ */ React.createElement(Select.Portal, null, /* @__PURE__ */ React.createElement(Select.Content, null, /* @__PURE__ */ React.createElement(Select.Viewport, null, [
127
+ "number",
128
+ "boolean",
129
+ "string",
130
+ "ref"
131
+ ].map((type2) => /* @__PURE__ */ React.createElement(Select.Option, {
129
132
  key: type2,
130
133
  value: type2
131
- }, label2)))))))), type === "number" && /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(Section, null, /* @__PURE__ */ React.createElement(Input.Root, null, /* @__PURE__ */ React.createElement(Input.Label, {
134
+ }, t(`${type2} column type label`))))))))), type === "number" && /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(Section, null, /* @__PURE__ */ React.createElement(Input.Root, null, /* @__PURE__ */ React.createElement(Input.Label, {
132
135
  classNames: "mbe-1 mbs-3"
133
- }, "Decimal places"), /* @__PURE__ */ React.createElement(Input.TextInput, {
136
+ }, t("digits label")), /* @__PURE__ */ React.createElement(Input.TextInput, {
134
137
  value: digits ?? "",
135
138
  onChange: (event) => setDigits(event.target.value)
136
139
  })))), type === "ref" && /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(Section, null, /* @__PURE__ */ React.createElement(Input.Root, null, /* @__PURE__ */ React.createElement(Input.Label, {
@@ -141,7 +144,7 @@ var ColumnPanel = ({ context, tableDefs, tableDef, column, onUpdate, onDelete })
141
144
  }, /* @__PURE__ */ React.createElement(Select.TriggerButton, {
142
145
  placeholder: "Table",
143
146
  classNames: "is-full"
144
- }), /* @__PURE__ */ React.createElement(Select.Portal, null, /* @__PURE__ */ React.createElement(Select.Content, null, /* @__PURE__ */ React.createElement(Select.Viewport, null, tableDefs.filter((t) => t.id !== tableDef.id).map(({ id, name }) => /* @__PURE__ */ React.createElement(Select.Option, {
147
+ }), /* @__PURE__ */ React.createElement(Select.Portal, null, /* @__PURE__ */ React.createElement(Select.Content, null, /* @__PURE__ */ React.createElement(Select.Viewport, null, tableDefs.filter((t2) => t2.id !== tableDef.id).map(({ id, name }) => /* @__PURE__ */ React.createElement(Select.Option, {
145
148
  key: id,
146
149
  value: id
147
150
  }, name ?? id))))))), refTable && /* @__PURE__ */ React.createElement(Input.Root, null, /* @__PURE__ */ React.createElement(Input.Label, {
@@ -163,21 +166,23 @@ var ColumnPanel = ({ context, tableDefs, tableDef, column, onUpdate, onDelete })
163
166
  variant: "primary",
164
167
  classNames: "is-full flex gap-2",
165
168
  onClick: handleSave
166
- }, /* @__PURE__ */ React.createElement("span", null, "Save"), /* @__PURE__ */ React.createElement("div", {
169
+ }, /* @__PURE__ */ React.createElement("span", null, t("save label")), /* @__PURE__ */ React.createElement("div", {
167
170
  className: "grow"
168
171
  }), /* @__PURE__ */ React.createElement(Check, {
169
172
  className: getSize(5)
170
173
  })), /* @__PURE__ */ React.createElement(Button, {
171
174
  classNames: "is-full flex gap-2",
172
175
  onClick: handleCancel
173
- }, /* @__PURE__ */ React.createElement("span", null, "Cancel"), /* @__PURE__ */ React.createElement("div", {
176
+ }, /* @__PURE__ */ React.createElement("span", null, t("cancel label", {
177
+ ns: "os"
178
+ })), /* @__PURE__ */ React.createElement("div", {
174
179
  className: "grow"
175
180
  }), /* @__PURE__ */ React.createElement(X, {
176
181
  className: getSize(5)
177
182
  })), /* @__PURE__ */ React.createElement(Button, {
178
183
  classNames: "is-full flex gap-2",
179
184
  onClick: () => onDelete?.(column.id)
180
- }, /* @__PURE__ */ React.createElement("span", null, "Delete"), /* @__PURE__ */ React.createElement("div", {
185
+ }, /* @__PURE__ */ React.createElement("span", null, t("delete label")), /* @__PURE__ */ React.createElement("div", {
181
186
  className: "grow"
182
187
  }), /* @__PURE__ */ React.createElement(Trash, {
183
188
  className: getSize(5)
@@ -187,6 +192,7 @@ var ColumnPanel = ({ context, tableDefs, tableDef, column, onUpdate, onDelete })
187
192
  // packages/ui/react-ui-table/src/components/Table/Table.tsx
188
193
  import { useControllableState } from "@radix-ui/react-use-controllable-state";
189
194
  import { getCoreRowModel, getGroupedRowModel, useReactTable } from "@tanstack/react-table";
195
+ import { useVirtualizer } from "@tanstack/react-virtual";
190
196
  import React6, { Fragment, useCallback, useEffect, useState as useState2 } from "react";
191
197
  import { debounce } from "@dxos/async";
192
198
 
@@ -211,7 +217,7 @@ var headPadding = "pli-2 plb-1.5";
211
217
  var gridCellFocusRing = "focus:z-[11] focus:outline outline-2 outline-primary-500 dark:outline-primary-400";
212
218
  var tableRoot = ({ fullWidth }, ...etc) => mx2("table-fixed", fullWidth && "is-full", ...etc);
213
219
  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);
220
+ var theadRoot = ({ header, stickyHeader }, ...etc) => mx2(header ? stickyHeader && "sticky block-start-[--sticky-top] z-[1]" : "collapse", header && fixedSurface, ...etc);
215
221
  var theadTr = (_props, ...etc) => mx2("group", ...etc);
216
222
  var theadTh = ({ border }, ...etc) => mx2("relative text-start font-medium select-none truncate", headPadding, border && "border", border && groupBorder, ...etc);
217
223
  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);
@@ -371,8 +377,57 @@ var TableHead = (_props) => {
371
377
  TableHead.displayName = TABLE_HEAD_NAME;
372
378
 
373
379
  // packages/ui/react-ui-table/src/components/Table/Table.tsx
380
+ var VirtualizedTableContent = ({ getScrollElement }) => {
381
+ const { table: { getRowModel } } = useTableContext("VirtualizedTableContent");
382
+ const rows = getRowModel().rows;
383
+ const { getTotalSize, getVirtualItems } = useVirtualizer({
384
+ getScrollElement,
385
+ count: rows.length,
386
+ overscan: 16,
387
+ estimateSize: () => 33
388
+ });
389
+ const virtualRows = getVirtualItems();
390
+ const totalSize = getTotalSize();
391
+ const paddingTop = virtualRows.length > 0 ? virtualRows?.[0]?.start || 0 : 0;
392
+ const paddingBottom = virtualRows.length > 0 ? totalSize - (virtualRows?.[virtualRows.length - 1]?.end || 0) : 0;
393
+ return /* @__PURE__ */ React6.createElement(React6.Fragment, null, paddingTop > 0 && /* @__PURE__ */ React6.createElement("tbody", {
394
+ role: "none"
395
+ }, /* @__PURE__ */ React6.createElement("tr", {
396
+ role: "none"
397
+ }, /* @__PURE__ */ React6.createElement("td", {
398
+ style: {
399
+ height: `${paddingTop}px`
400
+ },
401
+ role: "none"
402
+ }))), /* @__PURE__ */ React6.createElement(TableBody, {
403
+ rows: virtualRows.map((virtualRow) => rows[virtualRow.index])
404
+ }), paddingBottom > 0 && /* @__PURE__ */ React6.createElement("tbody", {
405
+ role: "none"
406
+ }, /* @__PURE__ */ React6.createElement("tr", {
407
+ role: "none"
408
+ }, /* @__PURE__ */ React6.createElement("td", {
409
+ style: {
410
+ height: `${paddingBottom}px`
411
+ },
412
+ role: "none"
413
+ }))));
414
+ };
415
+ var GroupedTableContent = () => {
416
+ const { table: { getGroupedRowModel: getGroupedRowModel1, getHeaderGroups, getState }, debug } = useTableContext("GroupedTableContent");
417
+ return /* @__PURE__ */ React6.createElement(React6.Fragment, null, getGroupedRowModel1().rows.map((row, i) => {
418
+ return /* @__PURE__ */ React6.createElement(Fragment, {
419
+ key: i
420
+ }, /* @__PURE__ */ React6.createElement("thead", null, /* @__PURE__ */ React6.createElement("tr", null, debug && /* @__PURE__ */ React6.createElement("th", null), /* @__PURE__ */ React6.createElement("th", {
421
+ // TODO(burdon): Calculate row span.
422
+ colSpan: getHeaderGroups()[0].headers.length,
423
+ className: groupTh({})
424
+ }, getState().grouping[0], "[", String(row.getGroupingValue(getState().grouping[0])), "]"))), /* @__PURE__ */ React6.createElement(TableBody, {
425
+ rows: row.subRows
426
+ }));
427
+ }));
428
+ };
374
429
  var Table = (props) => {
375
- const { role, data = [], columns = [], onColumnResize, columnVisibility, header = true, footer, rowsSelectable, fullWidth, debug, onDataSelectionChange } = props;
430
+ const { role, data = [], columns = [], onColumnResize, columnVisibility, header = true, footer, rowsSelectable, fullWidth, debug, onDataSelectionChange, classNames, getScrollElement } = props;
376
431
  const TableProvider2 = TableProvider;
377
432
  const [rowSelection = {}, directlySetRowSelection] = useControllableState({
378
433
  prop: props.rowSelection,
@@ -444,6 +499,7 @@ var Table = (props) => {
444
499
  // Debug
445
500
  debugTable: debug
446
501
  });
502
+ const rows = table.getRowModel().rows;
447
503
  useEffect(() => {
448
504
  if (onDataSelectionChange) {
449
505
  onDataSelectionChange(Object.keys(rowSelection).map((id) => table.getRowModel().rowsById[id].original));
@@ -462,25 +518,17 @@ var Table = (props) => {
462
518
  isGrid: role === "grid" || role === "treegrid"
463
519
  }, /* @__PURE__ */ React6.createElement("table", {
464
520
  role,
465
- className: tableRoot(props),
521
+ className: tableRoot(props, classNames),
466
522
  ...!fullWidth && {
467
523
  style: {
468
524
  width: table.getTotalSize()
469
525
  }
470
526
  }
471
- }, /* @__PURE__ */ React6.createElement(TableHead, null), grouping.length === 0 && /* @__PURE__ */ React6.createElement(TableBody, {
472
- rows: table.getRowModel().rows
473
- }), grouping.length !== 0 && table.getGroupedRowModel().rows.map((row, i) => {
474
- return /* @__PURE__ */ React6.createElement(Fragment, {
475
- key: i
476
- }, /* @__PURE__ */ React6.createElement("thead", null, /* @__PURE__ */ React6.createElement("tr", null, debug && /* @__PURE__ */ React6.createElement("th", null), /* @__PURE__ */ React6.createElement("th", {
477
- // TODO(burdon): Calculate row span.
478
- colSpan: table.getHeaderGroups()[0].headers.length,
479
- className: groupTh(props)
480
- }, table.getState().grouping[0], "[", String(row.getGroupingValue(table.getState().grouping[0])), "]"))), /* @__PURE__ */ React6.createElement(TableBody, {
481
- rows: row.subRows
482
- }));
483
- }), footer && /* @__PURE__ */ React6.createElement(TableFooter, null)), debug && /* @__PURE__ */ React6.createElement("pre", {
527
+ }, /* @__PURE__ */ React6.createElement(TableHead, null), grouping.length === 0 ? getScrollElement ? /* @__PURE__ */ React6.createElement(VirtualizedTableContent, {
528
+ getScrollElement
529
+ }) : /* @__PURE__ */ React6.createElement(TableBody, {
530
+ rows
531
+ }) : /* @__PURE__ */ React6.createElement(GroupedTableContent, null), footer && /* @__PURE__ */ React6.createElement(TableFooter, null)), debug && /* @__PURE__ */ React6.createElement("pre", {
484
532
  className: "font-mono text-xs text-neutral-500 my-4 p-2 ring"
485
533
  }, /* @__PURE__ */ React6.createElement("code", null, JSON.stringify(table.getState(), void 0, 2))));
486
534
  };
@@ -488,23 +536,9 @@ var Table = (props) => {
488
536
  // packages/ui/react-ui-table/src/components/Cell/CellCombobox.tsx
489
537
  import { CaretDown as CaretDown2 } from "@phosphor-icons/react";
490
538
  import React7, { useCallback as useCallback2, useState as useState3 } from "react";
491
- import { Popover as Popover2, useTranslation } from "@dxos/react-ui";
539
+ import { Popover as Popover2, useTranslation as useTranslation2 } from "@dxos/react-ui";
492
540
  import { PopoverCombobox } from "@dxos/react-ui-searchlist";
493
541
  import { descriptionText, getSize as getSize2, mx as mx4, staticPlaceholderText } from "@dxos/react-ui-theme";
494
-
495
- // packages/ui/react-ui-table/src/translations.ts
496
- var translationKey = "table";
497
- var translations_default = [
498
- {
499
- "en-US": {
500
- [translationKey]: {
501
- "no selection label": "\xA0"
502
- }
503
- }
504
- }
505
- ];
506
-
507
- // packages/ui/react-ui-table/src/components/Cell/CellCombobox.tsx
508
542
  var initialItems = (model, value) => value ? {
509
543
  [model.getId(value)]: {
510
544
  label: model.getText(value),
@@ -512,7 +546,7 @@ var initialItems = (model, value) => value ? {
512
546
  }
513
547
  } : {};
514
548
  var CellCombobox = ({ model, value, onValueChange }) => {
515
- const { t } = useTranslation(translationKey);
549
+ const { t } = useTranslation2(translationKey);
516
550
  const [items, setItems] = useState3(initialItems(model, value));
517
551
  const [loading, setLoading] = useState3(false);
518
552
  const [searchInputValue, setSearchInputValue] = useState3("");
@@ -541,7 +575,7 @@ var CellCombobox = ({ model, value, onValueChange }) => {
541
575
  variant: "ghost",
542
576
  classNames: "is-full rounded-none ring-inset"
543
577
  }, 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)
578
+ className: mx4("font-normal text-start text-base flex-1 min-is-0 truncate mie-2", !value && staticPlaceholderText)
545
579
  }, model.getText(value)), /* @__PURE__ */ React7.createElement(CaretDown2, {
546
580
  weight: "bold",
547
581
  className: getSize2(3)
@@ -569,29 +603,25 @@ var CellCombobox = ({ model, value, onValueChange }) => {
569
603
  };
570
604
 
571
605
  // packages/ui/react-ui-table/src/helpers.tsx
606
+ import { useFocusFinders } from "@fluentui/react-tabster";
572
607
  import { Check as Check2, ClipboardText, X as X2 } from "@phosphor-icons/react";
573
608
  import { createColumnHelper } from "@tanstack/react-table";
574
609
  import format from "date-fns/format";
575
610
  import formatDistanceToNow from "date-fns/formatDistanceToNow";
576
- import defaultsDeep from "lodash.defaultsdeep";
577
- import React8, { useRef as useRef2, useState as useState4 } from "react";
611
+ import React8, { useEffect as useEffect2, useRef as useRef2, useState as useState4 } from "react";
578
612
  import { Input as Input2, Tooltip } from "@dxos/react-ui";
579
613
  import { getSize as getSize3, mx as mx5 } from "@dxos/react-ui-theme";
580
- import { stripUndefinedValues } from "@dxos/util";
581
614
  var createColumnBuilder = () => ({
582
615
  helper: createColumnHelper(),
583
616
  builder: new ColumnBuilder()
584
617
  });
585
- var defaults = (options, ...sources) => {
586
- return stripUndefinedValues(defaultsDeep({}, options, ...sources));
587
- };
588
618
  var ComboboxBuilderCell = (cellContext) => {
589
619
  const { model, onUpdate } = cellContext.column.columnDef.meta;
590
- return /* @__PURE__ */ React8.createElement(CellCombobox, {
620
+ return model ? /* @__PURE__ */ React8.createElement(CellCombobox, {
591
621
  model,
592
622
  value: cellContext.getValue(),
593
623
  onValueChange: (value) => onUpdate?.(cellContext.row.original, cellContext.column.id, value)
594
- });
624
+ }) : null;
595
625
  };
596
626
  var StringBuilderCell = (cellContext) => {
597
627
  const { onUpdate } = cellContext.column.columnDef.meta;
@@ -624,40 +654,55 @@ var StringBuilderCell = (cellContext) => {
624
654
  onKeyDown: (event) => event.key === "Enter" && handleSave() || event.key === "Escape" && handleCancel()
625
655
  }));
626
656
  };
657
+ var parseNumber = (text) => text?.trim().length ? Number(text) : NaN;
658
+ var displayNumber = (value, digits) => value || value === 0 ? value.toLocaleString(void 0, {
659
+ minimumFractionDigits: digits ?? 0,
660
+ maximumFractionDigits: digits ?? 2
661
+ }) : "";
627
662
  var NumberBuilderCell = (cellContext) => {
628
- const { onUpdate, cell, digits } = cellContext.column.columnDef.meta;
663
+ const { onUpdate, digits } = cellContext.column.columnDef.meta;
629
664
  const value = cellContext.getValue();
630
- const [text, setText] = useState4();
665
+ const [text, setText] = useState4(displayNumber(value, digits));
666
+ const { findPrevFocusable } = useFocusFinders();
667
+ const ref = useRef2(null);
668
+ useEffect2(() => {
669
+ (!document.activeElement || document.activeElement !== ref.current) && setText(displayNumber(value, digits));
670
+ }, [
671
+ digits,
672
+ value
673
+ ]);
631
674
  const handleEdit = () => {
632
675
  if (onUpdate) {
633
676
  setText(value !== void 0 ? String(value) : "");
634
677
  }
635
678
  };
636
679
  const handleSave = () => {
637
- const value2 = text?.trim().length ? Number(text) : NaN;
638
- onUpdate?.(cellContext.row.original, cellContext.column.id, isNaN(value2) ? void 0 : value2);
639
- setText(void 0);
680
+ const nextValue = parseNumber(text);
681
+ onUpdate?.(cellContext.row.original, cellContext.column.id, isNaN(nextValue) ? void 0 : nextValue);
682
+ setText(displayNumber(nextValue, digits));
683
+ ref.current && document.activeElement === ref.current && findPrevFocusable(ref.current)?.focus();
640
684
  };
641
- const handleCancel = () => {
642
- setText(void 0);
685
+ const _handleCancel = () => {
686
+ setText(displayNumber(value, digits));
687
+ ref.current && findPrevFocusable(ref.current)?.focus();
643
688
  };
644
- if (text !== void 0) {
645
- return /* @__PURE__ */ React8.createElement(Input2.Root, null, /* @__PURE__ */ React8.createElement(Input2.TextInput, {
646
- value: text,
647
- classNames: [
648
- "is-full text-end font-mono"
649
- ],
650
- onBlur: handleSave,
651
- onChange: (event) => setText(event.target.value),
652
- onKeyDown: (event) => event.key === "Escape" && handleCancel() || event.key === "Enter" && handleSave()
653
- }));
654
- }
655
- return /* @__PURE__ */ React8.createElement("div", {
656
- className: mx5('is-full text-end font-mono empty:after:content-["\xA0"]', textPadding, cell?.classNames),
657
- onClick: handleEdit
658
- }, value?.toLocaleString(void 0, {
659
- minimumFractionDigits: digits ?? 0,
660
- maximumFractionDigits: digits ?? 2
689
+ return /* @__PURE__ */ React8.createElement(Input2.Root, null, /* @__PURE__ */ React8.createElement(Input2.TextInput, {
690
+ ref,
691
+ variant: "subdued",
692
+ value: text,
693
+ classNames: [
694
+ "is-full text-end font-mono",
695
+ textPadding
696
+ ],
697
+ onBlur: handleSave,
698
+ onFocus: handleEdit,
699
+ onChange: ({ target: { value: value2 } }) => setText(value2),
700
+ onKeyDown: (event) => {
701
+ return (
702
+ /* (event.key === 'Escape' && handleCancel()) || */
703
+ event.key === "Enter" && handleSave()
704
+ );
705
+ }
661
706
  }));
662
707
  };
663
708
  var RowSelectorBuilderCell = (cellContext) => {
@@ -697,15 +742,8 @@ var ColumnBuilder = class {
697
742
  * Combobox value
698
743
  */
699
744
  combobox({ label, classNames, model, onUpdate, ...props }) {
700
- return defaults(props, {
745
+ return {
701
746
  minSize: 100,
702
- meta: {
703
- model,
704
- onUpdate,
705
- cell: {
706
- classNames
707
- }
708
- },
709
747
  header: (column) => {
710
748
  return label ?? column.header.id;
711
749
  },
@@ -714,21 +752,25 @@ var ColumnBuilder = class {
714
752
  return /* @__PURE__ */ React8.createElement("div", {
715
753
  className: mx5("truncate", classNames)
716
754
  }, cellValue ? model?.getText(cellValue) : "");
755
+ },
756
+ ...props,
757
+ meta: {
758
+ ...props.meta,
759
+ model,
760
+ onUpdate,
761
+ cell: {
762
+ classNames,
763
+ ...props.meta?.cell
764
+ }
717
765
  }
718
- });
766
+ };
719
767
  }
720
768
  /**
721
769
  * String formats.
722
770
  */
723
771
  string({ label, classNames, onUpdate, ...props } = {}) {
724
- return defaults(props, {
772
+ return {
725
773
  minSize: 100,
726
- meta: {
727
- onUpdate,
728
- cell: {
729
- classNames
730
- }
731
- },
732
774
  // TODO(burdon): Default.
733
775
  header: (column) => {
734
776
  return label ?? column.header.id;
@@ -738,43 +780,51 @@ var ColumnBuilder = class {
738
780
  return /* @__PURE__ */ React8.createElement("div", {
739
781
  className: mx5("truncate", textPadding, classNames)
740
782
  }, value);
783
+ },
784
+ ...props,
785
+ meta: {
786
+ ...props.meta,
787
+ onUpdate,
788
+ cell: {
789
+ ...props.meta?.cell,
790
+ classNames
791
+ }
741
792
  }
742
- });
793
+ };
743
794
  }
744
795
  /**
745
796
  * Number formats.
746
797
  */
747
798
  number({ label, minSize, classNames, digits, onUpdate, ...props } = {}) {
748
- return defaults(props, {
799
+ return {
749
800
  size: 100,
750
801
  minSize: 100,
802
+ header: (cell) => label ?? cell.header.id,
803
+ cell: NumberBuilderCell,
804
+ ...props,
751
805
  meta: {
806
+ ...props.meta,
752
807
  onUpdate,
753
808
  digits,
754
809
  header: {
755
- classNames: "text-end"
810
+ classNames: "text-end",
811
+ ...props.meta?.header
756
812
  },
757
813
  cell: {
814
+ ...props.meta?.cell,
758
815
  classNames
759
816
  }
760
- },
761
- header: (cell) => label ?? cell.header.id,
762
- cell: NumberBuilderCell
763
- });
817
+ }
818
+ };
764
819
  }
765
820
  /**
766
821
  * Date formats.
767
822
  */
768
823
  // TODO(burdon): Date picker (pluggable renderers?)
769
824
  date({ label, format: formatSpec, relative, classNames, ...props } = {}) {
770
- return defaults(props, {
825
+ return {
771
826
  size: 220,
772
827
  minSize: 100,
773
- meta: {
774
- cell: {
775
- classNames
776
- }
777
- },
778
828
  header: (cell) => label ?? cell.header.id,
779
829
  cell: (cell) => {
780
830
  const value = cell.getValue();
@@ -789,24 +839,24 @@ var ColumnBuilder = class {
789
839
  console.log(value);
790
840
  return null;
791
841
  }
842
+ },
843
+ ...props,
844
+ meta: {
845
+ ...props.meta,
846
+ cell: {
847
+ ...props.meta?.cell,
848
+ classNames
849
+ }
792
850
  }
793
- });
851
+ };
794
852
  }
795
853
  /**
796
854
  * PublicKey with tooltip.
797
855
  */
798
- key({ label, tooltip, ...props } = {}) {
799
- return defaults(props, {
856
+ key({ label, tooltip, classNames, ...props } = {}) {
857
+ return {
800
858
  size: 94,
801
859
  minSize: 94,
802
- meta: {
803
- cell: {
804
- classNames: [
805
- "font-mono",
806
- textPadding
807
- ]
808
- }
809
- },
810
860
  header: (cell) => label ?? cell.header.id,
811
861
  cell: (cell) => {
812
862
  const value = cell.getValue();
@@ -817,21 +867,33 @@ var ColumnBuilder = class {
817
867
  if (!tooltip) {
818
868
  return element;
819
869
  }
820
- return /* @__PURE__ */ React8.createElement(Tooltip.Provider, null, /* @__PURE__ */ React8.createElement(Tooltip.Root, null, /* @__PURE__ */ React8.createElement(Tooltip.Trigger, null, element), /* @__PURE__ */ React8.createElement(Tooltip.Content, {
870
+ 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, {
821
871
  side: "right"
822
872
  }, /* @__PURE__ */ React8.createElement(Tooltip.Arrow, null), /* @__PURE__ */ React8.createElement(ClipboardText, {
823
873
  onClick: (ev) => {
824
874
  ev.stopPropagation();
825
875
  void navigator.clipboard.writeText(value.toHex());
826
876
  }
827
- }))));
877
+ })))));
878
+ },
879
+ ...props,
880
+ meta: {
881
+ ...props.meta,
882
+ cell: {
883
+ ...props.meta?.cell,
884
+ classNames: [
885
+ "font-mono",
886
+ textPadding,
887
+ classNames
888
+ ]
889
+ }
828
890
  }
829
- });
891
+ };
830
892
  }
831
893
  /**
832
894
  * Row selector
833
895
  */
834
- selectRow({ label, classNames, onUpdate, id = "selectRow", ...props } = {}) {
896
+ selectRow({ classNames, onUpdate, id = "selectRow" } = {}) {
835
897
  return {
836
898
  id,
837
899
  size: 32,
@@ -863,21 +925,24 @@ var ColumnBuilder = class {
863
925
  * Switch
864
926
  */
865
927
  switch({ label, classNames, onUpdate, ...props } = {}) {
866
- return defaults(props, {
928
+ return {
867
929
  size: 50,
868
930
  minSize: 50,
931
+ header: (column) => label ?? column.header.id,
932
+ cell: SwitchBuilderCell,
933
+ ...props,
869
934
  meta: {
935
+ ...props.meta,
870
936
  onUpdate,
871
937
  cell: {
938
+ ...props.meta?.cell,
872
939
  classNames: [
873
940
  textPadding,
874
941
  classNames
875
942
  ]
876
943
  }
877
- },
878
- header: (column) => label ?? column.header.id,
879
- cell: SwitchBuilderCell
880
- });
944
+ }
945
+ };
881
946
  }
882
947
  /**
883
948
  * Icon based on boolean value.
@@ -885,7 +950,7 @@ var ColumnBuilder = class {
885
950
  icon({ label, size, on, off, ...props } = {}) {
886
951
  const IconOn = on?.Icon ?? Check2;
887
952
  const IconOff = off?.Icon ?? X2;
888
- return defaults(props, {
953
+ return {
889
954
  size: size ?? 32,
890
955
  header: (column) => /* @__PURE__ */ React8.createElement("div", {
891
956
  className: "justify-center"
@@ -903,8 +968,9 @@ var ColumnBuilder = class {
903
968
  } else {
904
969
  return null;
905
970
  }
906
- }
907
- });
971
+ },
972
+ ...props
973
+ };
908
974
  }
909
975
  };
910
976
  export {
@@ -913,7 +979,6 @@ export {
913
979
  ColumnMenu,
914
980
  ColumnPanel,
915
981
  Table,
916
- columnTypes,
917
982
  createColumnBuilder,
918
983
  currentRow,
919
984
  flushPadding,
@@ -934,6 +999,7 @@ export {
934
999
  theadResizeThumb,
935
1000
  theadRoot,
936
1001
  theadTh,
937
- theadTr
1002
+ theadTr,
1003
+ translations_default as translations
938
1004
  };
939
1005
  //# sourceMappingURL=index.mjs.map