@dxos/react-ui-table 0.3.9-main.5167f76 → 0.3.9-main.52d137d

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 (36) hide show
  1. package/dist/lib/browser/index.mjs +229 -162
  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/TableBody.d.ts.map +1 -1
  12. package/dist/types/src/components/Table/props.d.ts +6 -2
  13. package/dist/types/src/components/Table/props.d.ts.map +1 -1
  14. package/dist/types/src/helpers.d.ts +2 -2
  15. package/dist/types/src/helpers.d.ts.map +1 -1
  16. package/dist/types/src/index.d.ts +1 -0
  17. package/dist/types/src/index.d.ts.map +1 -1
  18. package/dist/types/src/schema.d.ts +0 -1
  19. package/dist/types/src/schema.d.ts.map +1 -1
  20. package/dist/types/src/theme.d.ts +0 -2
  21. package/dist/types/src/theme.d.ts.map +1 -1
  22. package/dist/types/src/translations.d.ts +11 -0
  23. package/dist/types/src/translations.d.ts.map +1 -1
  24. package/package.json +12 -16
  25. package/src/components/Cell/CellCombobox.tsx +4 -1
  26. package/src/components/ColumnMenu.stories.tsx +3 -0
  27. package/src/components/ColumnMenu.tsx +16 -16
  28. package/src/components/Table/Table.stories.tsx +23 -12
  29. package/src/components/Table/Table.tsx +92 -26
  30. package/src/components/Table/TableBody.tsx +2 -1
  31. package/src/components/Table/props.ts +26 -14
  32. package/src/helpers.tsx +105 -84
  33. package/src/index.ts +1 -0
  34. package/src/schema.ts +0 -8
  35. package/src/theme.ts +14 -7
  36. 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
 
@@ -202,7 +208,7 @@ var [TableProvider, useUntypedTableContext] = createContext(TABLE_NAME);
202
208
  var useTableContext = (consumerName) => useUntypedTableContext(consumerName);
203
209
 
204
210
  // packages/ui/react-ui-table/src/theme.ts
205
- import { chromeSurface, fixedSurface, focusRing, groupBorder, hoverColors, mx as mx2 } from "@dxos/react-ui-theme";
211
+ import { chromeSurface, fixedSurface, focusRing, ghostSelected, ghostSelectedCurrent, groupBorder, mx as mx2 } from "@dxos/react-ui-theme";
206
212
  var currentRow = "!bg-neutral-75 !dark:bg-neutral-850";
207
213
  var selectedRow = "!bg-primary-100 dark:!bg-primary-700";
208
214
  var flushPadding = "pli-0 plb-0";
@@ -211,13 +217,13 @@ 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);
218
224
  var theadResizeThumb = (_props, ...etc) => mx2("flex group-hover:bg-neutral-700 -ml-[2px] w-[1px] h-full", ...etc);
219
225
  var tbodyRoot = (_props, ...etc) => mx2(...etc);
220
- var tbodyTr = ({ isSelected, isCurrent, canBeCurrent }, ...etc) => mx2("group", isSelected ? selectedRow : isCurrent && currentRow, canBeCurrent && focusRing, canBeCurrent && hoverColors, canBeCurrent && "cursor-pointer rounded", ...etc);
226
+ var tbodyTr = ({ canBeCurrent }, ...etc) => mx2("group", canBeCurrent ? ghostSelectedCurrent : ghostSelected, canBeCurrent && focusRing, canBeCurrent && "cursor-pointer rounded", ...etc);
221
227
  var tdRoot = ({ border, isGrid }, ...etc) => mx2("relative", flushPadding, border && "border", border && groupBorder, isGrid && gridCellFocusRing, ...etc);
222
228
  var tdContent = (_props, ...etc) => mx2(...etc);
223
229
  var tfootRoot = (_props, ...etc) => mx2("sticky block-end-0 z-10", chromeSurface, ...etc);
@@ -270,13 +276,14 @@ var TableBody = ({ rows }) => {
270
276
  return /* @__PURE__ */ React3.createElement("tr", {
271
277
  key: keyAccessor ? keyAccessor(row.original) : row.id,
272
278
  className: tbodyTr({
273
- isSelected,
274
- isCurrent,
275
279
  canBeCurrent
276
280
  }),
277
281
  ...isCurrent && {
278
282
  "aria-current": "location"
279
283
  },
284
+ ...isSelected && {
285
+ "aria-selected": "true"
286
+ },
280
287
  ...canBeCurrent && {
281
288
  tabIndex: 0,
282
289
  onClick: () => {
@@ -370,8 +377,57 @@ var TableHead = (_props) => {
370
377
  TableHead.displayName = TABLE_HEAD_NAME;
371
378
 
372
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
+ };
373
429
  var Table = (props) => {
374
- 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;
375
431
  const TableProvider2 = TableProvider;
376
432
  const [rowSelection = {}, directlySetRowSelection] = useControllableState({
377
433
  prop: props.rowSelection,
@@ -443,6 +499,7 @@ var Table = (props) => {
443
499
  // Debug
444
500
  debugTable: debug
445
501
  });
502
+ const rows = table.getRowModel().rows;
446
503
  useEffect(() => {
447
504
  if (onDataSelectionChange) {
448
505
  onDataSelectionChange(Object.keys(rowSelection).map((id) => table.getRowModel().rowsById[id].original));
@@ -461,25 +518,17 @@ var Table = (props) => {
461
518
  isGrid: role === "grid" || role === "treegrid"
462
519
  }, /* @__PURE__ */ React6.createElement("table", {
463
520
  role,
464
- className: tableRoot(props),
521
+ className: tableRoot(props, classNames),
465
522
  ...!fullWidth && {
466
523
  style: {
467
524
  width: table.getTotalSize()
468
525
  }
469
526
  }
470
- }, /* @__PURE__ */ React6.createElement(TableHead, null), grouping.length === 0 && /* @__PURE__ */ React6.createElement(TableBody, {
471
- rows: table.getRowModel().rows
472
- }), grouping.length !== 0 && table.getGroupedRowModel().rows.map((row, i) => {
473
- return /* @__PURE__ */ React6.createElement(Fragment, {
474
- key: i
475
- }, /* @__PURE__ */ React6.createElement("thead", null, /* @__PURE__ */ React6.createElement("tr", null, debug && /* @__PURE__ */ React6.createElement("th", null), /* @__PURE__ */ React6.createElement("th", {
476
- // TODO(burdon): Calculate row span.
477
- colSpan: table.getHeaderGroups()[0].headers.length,
478
- className: groupTh(props)
479
- }, table.getState().grouping[0], "[", String(row.getGroupingValue(table.getState().grouping[0])), "]"))), /* @__PURE__ */ React6.createElement(TableBody, {
480
- rows: row.subRows
481
- }));
482
- }), 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", {
483
532
  className: "font-mono text-xs text-neutral-500 my-4 p-2 ring"
484
533
  }, /* @__PURE__ */ React6.createElement("code", null, JSON.stringify(table.getState(), void 0, 2))));
485
534
  };
@@ -487,23 +536,9 @@ var Table = (props) => {
487
536
  // packages/ui/react-ui-table/src/components/Cell/CellCombobox.tsx
488
537
  import { CaretDown as CaretDown2 } from "@phosphor-icons/react";
489
538
  import React7, { useCallback as useCallback2, useState as useState3 } from "react";
490
- import { Popover as Popover2, useTranslation } from "@dxos/react-ui";
539
+ import { Popover as Popover2, useTranslation as useTranslation2 } from "@dxos/react-ui";
491
540
  import { PopoverCombobox } from "@dxos/react-ui-searchlist";
492
541
  import { descriptionText, getSize as getSize2, mx as mx4, staticPlaceholderText } from "@dxos/react-ui-theme";
493
-
494
- // packages/ui/react-ui-table/src/translations.ts
495
- var translationKey = "table";
496
- var translations_default = [
497
- {
498
- "en-US": {
499
- [translationKey]: {
500
- "no selection label": "\xA0"
501
- }
502
- }
503
- }
504
- ];
505
-
506
- // packages/ui/react-ui-table/src/components/Cell/CellCombobox.tsx
507
542
  var initialItems = (model, value) => value ? {
508
543
  [model.getId(value)]: {
509
544
  label: model.getText(value),
@@ -511,7 +546,7 @@ var initialItems = (model, value) => value ? {
511
546
  }
512
547
  } : {};
513
548
  var CellCombobox = ({ model, value, onValueChange }) => {
514
- const { t } = useTranslation(translationKey);
549
+ const { t } = useTranslation2(translationKey);
515
550
  const [items, setItems] = useState3(initialItems(model, value));
516
551
  const [loading, setLoading] = useState3(false);
517
552
  const [searchInputValue, setSearchInputValue] = useState3("");
@@ -540,7 +575,7 @@ var CellCombobox = ({ model, value, onValueChange }) => {
540
575
  variant: "ghost",
541
576
  classNames: "is-full rounded-none ring-inset"
542
577
  }, value ? /* @__PURE__ */ React7.createElement(React7.Fragment, null, /* @__PURE__ */ React7.createElement("span", {
543
- 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)
544
579
  }, model.getText(value)), /* @__PURE__ */ React7.createElement(CaretDown2, {
545
580
  weight: "bold",
546
581
  className: getSize2(3)
@@ -568,29 +603,25 @@ var CellCombobox = ({ model, value, onValueChange }) => {
568
603
  };
569
604
 
570
605
  // packages/ui/react-ui-table/src/helpers.tsx
606
+ import { useFocusFinders } from "@fluentui/react-tabster";
571
607
  import { Check as Check2, ClipboardText, X as X2 } from "@phosphor-icons/react";
572
608
  import { createColumnHelper } from "@tanstack/react-table";
573
609
  import format from "date-fns/format";
574
610
  import formatDistanceToNow from "date-fns/formatDistanceToNow";
575
- import defaultsDeep from "lodash.defaultsdeep";
576
- import React8, { useRef as useRef2, useState as useState4 } from "react";
611
+ import React8, { useEffect as useEffect2, useRef as useRef2, useState as useState4 } from "react";
577
612
  import { Input as Input2, Tooltip } from "@dxos/react-ui";
578
613
  import { getSize as getSize3, mx as mx5 } from "@dxos/react-ui-theme";
579
- import { stripUndefinedValues } from "@dxos/util";
580
614
  var createColumnBuilder = () => ({
581
615
  helper: createColumnHelper(),
582
616
  builder: new ColumnBuilder()
583
617
  });
584
- var defaults = (options, ...sources) => {
585
- return stripUndefinedValues(defaultsDeep({}, options, ...sources));
586
- };
587
618
  var ComboboxBuilderCell = (cellContext) => {
588
619
  const { model, onUpdate } = cellContext.column.columnDef.meta;
589
- return /* @__PURE__ */ React8.createElement(CellCombobox, {
620
+ return model ? /* @__PURE__ */ React8.createElement(CellCombobox, {
590
621
  model,
591
622
  value: cellContext.getValue(),
592
623
  onValueChange: (value) => onUpdate?.(cellContext.row.original, cellContext.column.id, value)
593
- });
624
+ }) : null;
594
625
  };
595
626
  var StringBuilderCell = (cellContext) => {
596
627
  const { onUpdate } = cellContext.column.columnDef.meta;
@@ -623,40 +654,55 @@ var StringBuilderCell = (cellContext) => {
623
654
  onKeyDown: (event) => event.key === "Enter" && handleSave() || event.key === "Escape" && handleCancel()
624
655
  }));
625
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
+ }) : "";
626
662
  var NumberBuilderCell = (cellContext) => {
627
- const { onUpdate, cell, digits } = cellContext.column.columnDef.meta;
663
+ const { onUpdate, digits } = cellContext.column.columnDef.meta;
628
664
  const value = cellContext.getValue();
629
- 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
+ ]);
630
674
  const handleEdit = () => {
631
675
  if (onUpdate) {
632
676
  setText(value !== void 0 ? String(value) : "");
633
677
  }
634
678
  };
635
679
  const handleSave = () => {
636
- const value2 = text?.trim().length ? Number(text) : NaN;
637
- onUpdate?.(cellContext.row.original, cellContext.column.id, isNaN(value2) ? void 0 : value2);
638
- 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();
639
684
  };
640
- const handleCancel = () => {
641
- setText(void 0);
685
+ const _handleCancel = () => {
686
+ setText(displayNumber(value, digits));
687
+ ref.current && findPrevFocusable(ref.current)?.focus();
642
688
  };
643
- if (text !== void 0) {
644
- return /* @__PURE__ */ React8.createElement(Input2.Root, null, /* @__PURE__ */ React8.createElement(Input2.TextInput, {
645
- value: text,
646
- classNames: [
647
- "is-full text-end font-mono"
648
- ],
649
- onBlur: handleSave,
650
- onChange: (event) => setText(event.target.value),
651
- onKeyDown: (event) => event.key === "Escape" && handleCancel() || event.key === "Enter" && handleSave()
652
- }));
653
- }
654
- return /* @__PURE__ */ React8.createElement("div", {
655
- className: mx5('is-full text-end font-mono empty:after:content-["\xA0"]', textPadding, cell?.classNames),
656
- onClick: handleEdit
657
- }, value?.toLocaleString(void 0, {
658
- minimumFractionDigits: digits ?? 0,
659
- 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
+ }
660
706
  }));
661
707
  };
662
708
  var RowSelectorBuilderCell = (cellContext) => {
@@ -696,15 +742,8 @@ var ColumnBuilder = class {
696
742
  * Combobox value
697
743
  */
698
744
  combobox({ label, classNames, model, onUpdate, ...props }) {
699
- return defaults(props, {
745
+ return {
700
746
  minSize: 100,
701
- meta: {
702
- model,
703
- onUpdate,
704
- cell: {
705
- classNames
706
- }
707
- },
708
747
  header: (column) => {
709
748
  return label ?? column.header.id;
710
749
  },
@@ -713,21 +752,25 @@ var ColumnBuilder = class {
713
752
  return /* @__PURE__ */ React8.createElement("div", {
714
753
  className: mx5("truncate", classNames)
715
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
+ }
716
765
  }
717
- });
766
+ };
718
767
  }
719
768
  /**
720
769
  * String formats.
721
770
  */
722
771
  string({ label, classNames, onUpdate, ...props } = {}) {
723
- return defaults(props, {
772
+ return {
724
773
  minSize: 100,
725
- meta: {
726
- onUpdate,
727
- cell: {
728
- classNames
729
- }
730
- },
731
774
  // TODO(burdon): Default.
732
775
  header: (column) => {
733
776
  return label ?? column.header.id;
@@ -737,43 +780,51 @@ var ColumnBuilder = class {
737
780
  return /* @__PURE__ */ React8.createElement("div", {
738
781
  className: mx5("truncate", textPadding, classNames)
739
782
  }, value);
783
+ },
784
+ ...props,
785
+ meta: {
786
+ ...props.meta,
787
+ onUpdate,
788
+ cell: {
789
+ ...props.meta?.cell,
790
+ classNames
791
+ }
740
792
  }
741
- });
793
+ };
742
794
  }
743
795
  /**
744
796
  * Number formats.
745
797
  */
746
798
  number({ label, minSize, classNames, digits, onUpdate, ...props } = {}) {
747
- return defaults(props, {
799
+ return {
748
800
  size: 100,
749
801
  minSize: 100,
802
+ header: (cell) => label ?? cell.header.id,
803
+ cell: NumberBuilderCell,
804
+ ...props,
750
805
  meta: {
806
+ ...props.meta,
751
807
  onUpdate,
752
808
  digits,
753
809
  header: {
754
- classNames: "text-end"
810
+ classNames: "text-end",
811
+ ...props.meta?.header
755
812
  },
756
813
  cell: {
814
+ ...props.meta?.cell,
757
815
  classNames
758
816
  }
759
- },
760
- header: (cell) => label ?? cell.header.id,
761
- cell: NumberBuilderCell
762
- });
817
+ }
818
+ };
763
819
  }
764
820
  /**
765
821
  * Date formats.
766
822
  */
767
823
  // TODO(burdon): Date picker (pluggable renderers?)
768
824
  date({ label, format: formatSpec, relative, classNames, ...props } = {}) {
769
- return defaults(props, {
825
+ return {
770
826
  size: 220,
771
827
  minSize: 100,
772
- meta: {
773
- cell: {
774
- classNames
775
- }
776
- },
777
828
  header: (cell) => label ?? cell.header.id,
778
829
  cell: (cell) => {
779
830
  const value = cell.getValue();
@@ -788,24 +839,24 @@ var ColumnBuilder = class {
788
839
  console.log(value);
789
840
  return null;
790
841
  }
842
+ },
843
+ ...props,
844
+ meta: {
845
+ ...props.meta,
846
+ cell: {
847
+ ...props.meta?.cell,
848
+ classNames
849
+ }
791
850
  }
792
- });
851
+ };
793
852
  }
794
853
  /**
795
854
  * PublicKey with tooltip.
796
855
  */
797
- key({ label, tooltip, ...props } = {}) {
798
- return defaults(props, {
856
+ key({ label, tooltip, classNames, ...props } = {}) {
857
+ return {
799
858
  size: 94,
800
859
  minSize: 94,
801
- meta: {
802
- cell: {
803
- classNames: [
804
- "font-mono",
805
- textPadding
806
- ]
807
- }
808
- },
809
860
  header: (cell) => label ?? cell.header.id,
810
861
  cell: (cell) => {
811
862
  const value = cell.getValue();
@@ -816,21 +867,33 @@ var ColumnBuilder = class {
816
867
  if (!tooltip) {
817
868
  return element;
818
869
  }
819
- 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, {
820
871
  side: "right"
821
872
  }, /* @__PURE__ */ React8.createElement(Tooltip.Arrow, null), /* @__PURE__ */ React8.createElement(ClipboardText, {
822
873
  onClick: (ev) => {
823
874
  ev.stopPropagation();
824
875
  void navigator.clipboard.writeText(value.toHex());
825
876
  }
826
- }))));
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
+ }
827
890
  }
828
- });
891
+ };
829
892
  }
830
893
  /**
831
894
  * Row selector
832
895
  */
833
- selectRow({ label, classNames, onUpdate, id = "selectRow", ...props } = {}) {
896
+ selectRow({ classNames, onUpdate, id = "selectRow" } = {}) {
834
897
  return {
835
898
  id,
836
899
  size: 32,
@@ -862,21 +925,24 @@ var ColumnBuilder = class {
862
925
  * Switch
863
926
  */
864
927
  switch({ label, classNames, onUpdate, ...props } = {}) {
865
- return defaults(props, {
928
+ return {
866
929
  size: 50,
867
930
  minSize: 50,
931
+ header: (column) => label ?? column.header.id,
932
+ cell: SwitchBuilderCell,
933
+ ...props,
868
934
  meta: {
935
+ ...props.meta,
869
936
  onUpdate,
870
937
  cell: {
938
+ ...props.meta?.cell,
871
939
  classNames: [
872
940
  textPadding,
873
941
  classNames
874
942
  ]
875
943
  }
876
- },
877
- header: (column) => label ?? column.header.id,
878
- cell: SwitchBuilderCell
879
- });
944
+ }
945
+ };
880
946
  }
881
947
  /**
882
948
  * Icon based on boolean value.
@@ -884,7 +950,7 @@ var ColumnBuilder = class {
884
950
  icon({ label, size, on, off, ...props } = {}) {
885
951
  const IconOn = on?.Icon ?? Check2;
886
952
  const IconOff = off?.Icon ?? X2;
887
- return defaults(props, {
953
+ return {
888
954
  size: size ?? 32,
889
955
  header: (column) => /* @__PURE__ */ React8.createElement("div", {
890
956
  className: "justify-center"
@@ -902,8 +968,9 @@ var ColumnBuilder = class {
902
968
  } else {
903
969
  return null;
904
970
  }
905
- }
906
- });
971
+ },
972
+ ...props
973
+ };
907
974
  }
908
975
  };
909
976
  export {
@@ -912,7 +979,6 @@ export {
912
979
  ColumnMenu,
913
980
  ColumnPanel,
914
981
  Table,
915
- columnTypes,
916
982
  createColumnBuilder,
917
983
  currentRow,
918
984
  flushPadding,
@@ -933,6 +999,7 @@ export {
933
999
  theadResizeThumb,
934
1000
  theadRoot,
935
1001
  theadTh,
936
- theadTr
1002
+ theadTr,
1003
+ translations_default as translations
937
1004
  };
938
1005
  //# sourceMappingURL=index.mjs.map