@dxos/react-ui-table 0.4.10-main.c42bfdb → 0.4.10-main.c75170d

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.
@@ -92,7 +92,7 @@ var CellCombobox = ({ model, value, onValueChange }) => {
92
92
 
93
93
  // packages/ui/react-ui-table/src/components/ColumnMenu/ColumnMenu.tsx
94
94
  import { X as X2, GearSix, CaretDown as CaretDown2, ArrowDown, ArrowUp } from "@phosphor-icons/react";
95
- import React3, { useRef as useRef2, useState as useState5, useCallback as useCallback2 } from "react";
95
+ import React3, { useRef as useRef2, useState as useState5, useCallback as useCallback3 } from "react";
96
96
  import { Button as Button2, DensityProvider, Popover as Popover2, DropdownMenu } from "@dxos/react-ui";
97
97
  import { getSize as getSize3, mx as mx3 } from "@dxos/react-ui-theme";
98
98
 
@@ -107,19 +107,21 @@ var Section = ({ children, className }) => /* @__PURE__ */ React2.createElement(
107
107
  className: mx2("p-2", className)
108
108
  }, children);
109
109
  var ColumnSettingsForm = ({ column, tableDef, tableDefs, onUpdate, onDelete, onClose }) => {
110
- const [prop, setProp] = useState2(column.id);
111
- const [refTable, setRefTable] = useState2(column.refTable);
112
- const [refProp, setRefProp] = useState2(column.refProp);
113
- const [type, setType] = useState2(String(column.type));
114
- const [label, setLabel] = useState2(column.label);
115
- const [digits, setDigits] = useState2(String(column.digits ?? "0"));
110
+ const [formState, setFormState] = useState2({
111
+ prop: column.id,
112
+ refTable: column.refTable,
113
+ refProp: column.refProp,
114
+ type: String(column.type),
115
+ label: column.label,
116
+ digits: String(column.digits ?? "0")
117
+ });
116
118
  const propRef = useRef(null);
117
119
  const { t } = useTranslation2(translationKey);
118
120
  const handleCancel = () => {
119
- setProp(column.id);
120
121
  onClose?.();
121
122
  };
122
123
  const handleSave = () => {
124
+ const { prop, refTable, refProp, type, label, digits } = formState;
123
125
  if (!prop.length || !prop.match(/^[a-zA-Z_].+/i)) {
124
126
  propRef.current?.focus();
125
127
  return;
@@ -131,7 +133,7 @@ var ColumnSettingsForm = ({ column, tableDef, tableDefs, onUpdate, onDelete, onC
131
133
  return;
132
134
  }
133
135
  }
134
- onUpdate?.(prop, {
136
+ onUpdate?.(column.id, {
135
137
  id: prop,
136
138
  prop,
137
139
  label,
@@ -148,22 +150,30 @@ var ColumnSettingsForm = ({ column, tableDef, tableDefs, onUpdate, onDelete, onC
148
150
  classNames: "mbe-1"
149
151
  }, t("column label label")), /* @__PURE__ */ React2.createElement(Input.TextInput, {
150
152
  placeholder: "Column label",
151
- value: label ?? "",
152
- onChange: (event) => setLabel(event.target.value),
153
+ value: formState.label ?? "",
154
+ onChange: (event) => setFormState((prevState) => ({
155
+ ...prevState,
156
+ label: event.target.value
157
+ })),
153
158
  autoFocus: true
154
159
  })), /* @__PURE__ */ React2.createElement(Input.Root, null, /* @__PURE__ */ React2.createElement(Input.Label, {
155
160
  classNames: "mbe-1 mbs-3"
156
161
  }, t("property key label")), /* @__PURE__ */ React2.createElement(Input.TextInput, {
157
162
  ref: propRef,
158
163
  placeholder: "Property key",
159
- // TODO(burdon): Provide hooks for value normalization, ENTER, ESC, etc.
160
- value: prop ?? "",
161
- onChange: (event) => setProp(event.target.value.replace(/[^\w_]/g, ""))
164
+ value: formState.prop ?? "",
165
+ onChange: (event) => setFormState((prevState) => ({
166
+ ...prevState,
167
+ prop: event.target.value.replace(/[^\w_]/g, "")
168
+ }))
162
169
  })), /* @__PURE__ */ React2.createElement(Input.Root, null, /* @__PURE__ */ React2.createElement(Input.Label, {
163
170
  classNames: "mbe-1 mbs-3"
164
171
  }, t("column type label")), /* @__PURE__ */ React2.createElement(Select.Root, {
165
- value: type,
166
- onValueChange: setType
172
+ value: formState.type,
173
+ onValueChange: (value) => setFormState((prevState) => ({
174
+ ...prevState,
175
+ type: value
176
+ }))
167
177
  }, /* @__PURE__ */ React2.createElement(Select.TriggerButton, {
168
178
  placeholder: "Type",
169
179
  classNames: "is-full"
@@ -172,37 +182,46 @@ var ColumnSettingsForm = ({ column, tableDef, tableDefs, onUpdate, onDelete, onC
172
182
  "boolean",
173
183
  "string",
174
184
  "ref"
175
- ].map((type2) => /* @__PURE__ */ React2.createElement(Select.Option, {
176
- key: type2,
177
- value: type2
178
- }, t(`${type2} column type label`))))))))), type === "number" && /* @__PURE__ */ React2.createElement(React2.Fragment, null, /* @__PURE__ */ React2.createElement(Section, null, /* @__PURE__ */ React2.createElement(Input.Root, null, /* @__PURE__ */ React2.createElement(Input.Label, {
185
+ ].map((type) => /* @__PURE__ */ React2.createElement(Select.Option, {
186
+ key: type,
187
+ value: type
188
+ }, t(`${type} column type label`))))))))), formState.type === "number" && /* @__PURE__ */ React2.createElement(Section, null, /* @__PURE__ */ React2.createElement(Input.Root, null, /* @__PURE__ */ React2.createElement(Input.Label, {
179
189
  classNames: "mbe-1 mbs-3"
180
190
  }, t("digits label")), /* @__PURE__ */ React2.createElement(Input.TextInput, {
181
- value: digits ?? "",
182
- onChange: (event) => setDigits(event.target.value)
183
- })))), type === "ref" && /* @__PURE__ */ React2.createElement(React2.Fragment, null, /* @__PURE__ */ React2.createElement(Section, null, /* @__PURE__ */ React2.createElement(Input.Root, null, /* @__PURE__ */ React2.createElement(Input.Label, {
191
+ value: formState.digits ?? "",
192
+ onChange: (event) => setFormState((prevState) => ({
193
+ ...prevState,
194
+ digits: event.target.value
195
+ }))
196
+ }))), formState.type === "ref" && /* @__PURE__ */ React2.createElement(Section, null, /* @__PURE__ */ React2.createElement(Input.Root, null, /* @__PURE__ */ React2.createElement(Input.Label, {
184
197
  classNames: "mbe-1 mbs-3"
185
198
  }, "Table"), /* @__PURE__ */ React2.createElement(Select.Root, {
186
- value: refTable,
187
- onValueChange: setRefTable
199
+ value: formState.refTable,
200
+ onValueChange: (value) => setFormState((prevState) => ({
201
+ ...prevState,
202
+ refTable: value
203
+ }))
188
204
  }, /* @__PURE__ */ React2.createElement(Select.TriggerButton, {
189
205
  placeholder: "Table",
190
206
  classNames: "is-full"
191
207
  }), /* @__PURE__ */ React2.createElement(Select.Portal, null, /* @__PURE__ */ React2.createElement(Select.Content, null, /* @__PURE__ */ React2.createElement(Select.Viewport, null, tableDefs.filter((t2) => t2.id !== tableDef.id).map(({ id, name }) => /* @__PURE__ */ React2.createElement(Select.Option, {
192
208
  key: id,
193
209
  value: id
194
- }, name ?? id))))))), refTable && /* @__PURE__ */ React2.createElement(Input.Root, null, /* @__PURE__ */ React2.createElement(Input.Label, {
210
+ }, name ?? id))))))), formState.refTable && /* @__PURE__ */ React2.createElement(Input.Root, null, /* @__PURE__ */ React2.createElement(Input.Label, {
195
211
  classNames: "mbe-1 mbs-3"
196
212
  }, "Table property"), /* @__PURE__ */ React2.createElement(Select.Root, {
197
- value: refProp,
198
- onValueChange: setRefProp
213
+ value: formState.refProp,
214
+ onValueChange: (value) => setFormState((prevState) => ({
215
+ ...prevState,
216
+ refProp: value
217
+ }))
199
218
  }, /* @__PURE__ */ React2.createElement(Select.TriggerButton, {
200
219
  placeholder: "Property",
201
220
  classNames: "is-full"
202
- }), /* @__PURE__ */ React2.createElement(Select.Portal, null, /* @__PURE__ */ React2.createElement(Select.Content, null, /* @__PURE__ */ React2.createElement(Select.Viewport, null, tableDefs.find((tableDef2) => tableDef2.id === refTable)?.columns.map(({ id, label: label2 }) => /* @__PURE__ */ React2.createElement(Select.Option, {
221
+ }), /* @__PURE__ */ React2.createElement(Select.Portal, null, /* @__PURE__ */ React2.createElement(Select.Content, null, /* @__PURE__ */ React2.createElement(Select.Viewport, null, tableDefs.find((tableDef2) => tableDef2.id === formState.refTable)?.columns.map(({ id, label }) => /* @__PURE__ */ React2.createElement(Select.Option, {
203
222
  key: id,
204
223
  value: id
205
- }, label2 ?? id))))))))), /* @__PURE__ */ React2.createElement(Separator, {
224
+ }, label ?? id)))))))), /* @__PURE__ */ React2.createElement(Separator, {
206
225
  classNames: "mli-2"
207
226
  }), /* @__PURE__ */ React2.createElement(Section, {
208
227
  className: "space-b-1.5"
@@ -280,38 +299,58 @@ var useColumnSorting = (column) => {
280
299
  };
281
300
 
282
301
  // packages/ui/react-ui-table/src/hooks/usePinLastRow.ts
283
- import { useEffect, useState as useState4 } from "react";
302
+ import { useCallback as useCallback2, useEffect, useState as useState4 } from "react";
284
303
  var usePinLastRow = (pinLastRow, table, data, getScrollElement) => {
285
304
  const [pinnedRowKey, setPinnedRowKey] = useState4();
286
- useEffect(() => {
287
- if (!pinLastRow) {
288
- return;
305
+ const scrollToBottom = useCallback2(() => {
306
+ const scrollElement = getScrollElement?.();
307
+ if (scrollElement) {
308
+ requestAnimationFrame(() => scrollElement.scrollTo({
309
+ top: scrollElement.scrollHeight
310
+ }));
289
311
  }
312
+ }, [
313
+ getScrollElement
314
+ ]);
315
+ const pinRow = useCallback2((rowToPin) => {
316
+ table.resetRowPinning();
317
+ rowToPin.pin("bottom");
318
+ setPinnedRowKey(rowToPin.id);
319
+ }, [
320
+ table
321
+ ]);
322
+ const clearRowPinning = useCallback2(() => {
323
+ table.resetRowPinning();
324
+ setPinnedRowKey(void 0);
325
+ }, [
326
+ table
327
+ ]);
328
+ const pinLastRowCallback = useCallback2(() => {
290
329
  const rows = table.getRowModel().rows;
291
- const rowToPin = rows[rows.length - 1];
292
- const rowId = rowToPin.id;
293
- if (rowId === pinnedRowKey) {
330
+ if (rows.length === 0) {
331
+ return clearRowPinning();
332
+ }
333
+ const lastRow = rows[rows.length - 1];
334
+ if (lastRow.id === pinnedRowKey) {
294
335
  return;
295
336
  }
296
- table.resetRowPinning();
297
- rowToPin.pin("bottom");
298
- const scrollElement = getScrollElement?.();
299
- const isFirstRender = pinnedRowKey === void 0;
300
- if (scrollElement && !isFirstRender) {
301
- requestAnimationFrame(() => {
302
- scrollElement.scrollTo({
303
- top: scrollElement.scrollHeight
304
- });
305
- });
337
+ pinRow(lastRow);
338
+ if (pinnedRowKey !== void 0) {
339
+ scrollToBottom();
306
340
  }
307
- setPinnedRowKey(rowId);
308
341
  }, [
309
- pinLastRow,
310
342
  table,
311
- getScrollElement,
312
- pinnedRowKey,
313
- setPinnedRowKey,
314
- data
343
+ scrollToBottom,
344
+ pinnedRowKey
345
+ ]);
346
+ useEffect(() => {
347
+ if (pinLastRow) {
348
+ pinLastRowCallback();
349
+ }
350
+ }, [
351
+ data,
352
+ pinLastRow,
353
+ pinLastRowCallback
315
354
  ]);
316
355
  };
317
356
 
@@ -323,14 +362,14 @@ var ColumnMenu = ({ column, ...props }) => {
323
362
  const columnSettingsAnchorRef = useRef2(null);
324
363
  const [isColumnSettingsOpen, setIsColumnSettingsOpen] = useState5(false);
325
364
  const shouldPreventFocusOnClose = useRef2(false);
326
- const onOpenColumnSettings = useCallback2(() => {
365
+ const onOpenColumnSettings = useCallback3(() => {
327
366
  shouldPreventFocusOnClose.current = true;
328
367
  setIsColumnSettingsOpen(true);
329
368
  }, [
330
369
  shouldPreventFocusOnClose,
331
370
  setIsColumnSettingsOpen
332
371
  ]);
333
- const onDropdownCloseAutoFocus = useCallback2((event) => {
372
+ const onDropdownCloseAutoFocus = useCallback3((event) => {
334
373
  if (shouldPreventFocusOnClose.current) {
335
374
  event.preventDefault();
336
375
  shouldPreventFocusOnClose.current = false;
@@ -444,7 +483,7 @@ var SortIndicator = ({ direction, onClick }) => {
444
483
  import { useControllableState } from "@radix-ui/react-use-controllable-state";
445
484
  import { getCoreRowModel, getSortedRowModel, useReactTable, getGroupedRowModel, getExpandedRowModel } from "@tanstack/react-table";
446
485
  import { useVirtualizer } from "@tanstack/react-virtual";
447
- import React9, { Fragment, useCallback as useCallback3, useEffect as useEffect2, useState as useState6 } from "react";
486
+ import React9, { Fragment, useCallback as useCallback4, useEffect as useEffect2, useState as useState6 } from "react";
448
487
  import { log } from "@dxos/log";
449
488
  import { useDefaultValue, useOnTransition } from "@dxos/react-ui";
450
489
 
@@ -660,7 +699,7 @@ var Table = (props) => {
660
699
  setColumnSizing
661
700
  ]);
662
701
  const [columnSizingInfo, setColumnSizingInfo] = useState6({});
663
- const notifyColumnResize = useCallback3(() => onColumnResize?.(columnSizing), [
702
+ const notifyColumnResize = useCallback4(() => onColumnResize?.(columnSizing), [
664
703
  onColumnResize,
665
704
  columnSizing
666
705
  ]);
@@ -670,7 +709,7 @@ var Table = (props) => {
670
709
  onChange: props.onRowSelectionChange,
671
710
  defaultProp: props.defaultRowSelection
672
711
  });
673
- const handleRowSelectionChange = useCallback3((updaterOrValue) => {
712
+ const handleRowSelectionChange = useCallback4((updaterOrValue) => {
674
713
  const nextRowSelection = typeof updaterOrValue === "function" ? updaterOrValue(rowSelection) : updaterOrValue;
675
714
  if (rowsSelectable === "multi") {
676
715
  setRowSelection(nextRowSelection);
@@ -742,7 +781,7 @@ var Table = (props) => {
742
781
  if (!getScrollElement) {
743
782
  log.warn("Table: getScrollElement is not set. This is required for virtualized tables.", void 0, {
744
783
  F: __dxlog_file,
745
- L: 159,
784
+ L: 160,
746
785
  S: void 0,
747
786
  C: (f, a) => f(...a)
748
787
  });
@@ -762,12 +801,6 @@ var Table = (props) => {
762
801
  var TableImpl = (props) => {
763
802
  const { debug, classNames, getScrollElement, role, footer, grouping, fullWidth } = props;
764
803
  const { table } = useTableContext();
765
- const centerRows = table.getCenterRows();
766
- const bottomRows = table.getBottomRows();
767
- const rows = [
768
- ...centerRows,
769
- ...bottomRows
770
- ];
771
804
  if (debug) {
772
805
  return /* @__PURE__ */ React9.createElement("pre", {
773
806
  className: "font-mono text-xs text-neutral-500 m-1 p-2 ring"
@@ -787,14 +820,28 @@ var TableImpl = (props) => {
787
820
  getScrollElement
788
821
  }) : /* @__PURE__ */ React9.createElement(VirtualizedTableContent, {
789
822
  getScrollElement
790
- }) : /* @__PURE__ */ React9.createElement(TableBody, {
823
+ }) : /* @__PURE__ */ React9.createElement(UnvirtualizedTableContent, null) : /* @__PURE__ */ React9.createElement(GroupedTableContent, null), footer && /* @__PURE__ */ React9.createElement(TableFooter, null));
824
+ };
825
+ var UnvirtualizedTableContent = () => {
826
+ const { table } = useTableContext();
827
+ const centerRows = table.getCenterRows();
828
+ const pinnedRows = table.getBottomRows();
829
+ const rows = [
830
+ ...centerRows,
831
+ ...pinnedRows
832
+ ];
833
+ return /* @__PURE__ */ React9.createElement(TableBody, {
791
834
  rows
792
- }) : /* @__PURE__ */ React9.createElement(GroupedTableContent, null), footer && /* @__PURE__ */ React9.createElement(TableFooter, null));
835
+ });
793
836
  };
794
837
  var VirtualizedTableContent = ({ getScrollElement }) => {
795
838
  const { table } = useTableContext();
796
839
  const centerRows = table.getCenterRows();
797
- const pinnedRows = table.getBottomRows();
840
+ let pinnedRows = [];
841
+ try {
842
+ pinnedRows = table.getBottomRows();
843
+ } catch (_) {
844
+ }
798
845
  const { getTotalSize, getVirtualItems } = useVirtualizer({
799
846
  getScrollElement,
800
847
  count: centerRows.length,
@@ -1277,14 +1324,45 @@ var ColumnBuilder = class {
1277
1324
  };
1278
1325
 
1279
1326
  // packages/ui/react-ui-table/src/schema/schema.ts
1280
- import { AST } from "@effect/schema";
1327
+ import * as AST from "@effect/schema/AST";
1328
+ var classifySchemaProperties = (schema) => {
1329
+ const recurse = (node, path, acc) => {
1330
+ const properties = AST.getPropertySignatures(node);
1331
+ properties.forEach((prop) => {
1332
+ const propName = prop.name.toString();
1333
+ if (prop.isOptional) {
1334
+ const unwrappedAst = unwrapOptionProperty(prop);
1335
+ if (isStruct(unwrappedAst)) {
1336
+ return recurse(unwrappedAst, [
1337
+ ...path,
1338
+ propName
1339
+ ], acc);
1340
+ }
1341
+ }
1342
+ if (isStruct(prop.type)) {
1343
+ recurse(prop.type, [
1344
+ ...path,
1345
+ propName
1346
+ ], acc);
1347
+ } else {
1348
+ acc.push([
1349
+ path.concat(propName).join("."),
1350
+ propertyToColumn(prop)
1351
+ ]);
1352
+ }
1353
+ });
1354
+ return acc;
1355
+ };
1356
+ return recurse(schema.ast, [], []);
1357
+ };
1358
+ var isStruct = (node) => AST.isTypeLiteral(node);
1281
1359
  var isOptionalUnion = (prop) => AST.isUnion(prop.type) && prop.isOptional;
1282
1360
  var unwrapOptionProperty = (prop) => {
1283
1361
  if (!isOptionalUnion(prop)) {
1284
- throw new Error("Not an optional property");
1362
+ throw new Error(`Not an optional property: ${String(prop.name)}`);
1285
1363
  }
1286
1364
  if (!AST.isUnion(prop.type)) {
1287
- throw new Error("Not a union type");
1365
+ throw new Error(`Not a union type: ${String(prop.name)}`);
1288
1366
  }
1289
1367
  const [type, _undefinedCase] = prop.type.types;
1290
1368
  return type;
@@ -1310,44 +1388,13 @@ var typeToColumn = (type) => {
1310
1388
  }
1311
1389
  return "display";
1312
1390
  };
1313
- var propertyToColumn = (property) => {
1314
- let type = property.type;
1315
- if (property.isOptional) {
1316
- type = unwrapOptionProperty(property);
1391
+ var propertyToColumn = (prop) => {
1392
+ let type = prop.type;
1393
+ if (prop.isOptional) {
1394
+ type = unwrapOptionProperty(prop);
1317
1395
  }
1318
1396
  return typeToColumn(type);
1319
1397
  };
1320
- var isStruct = (node) => AST.isTypeLiteral(node);
1321
- var classifySchemaProperties = (schema) => {
1322
- const recurse = (node, path, acc) => {
1323
- const properties = AST.getPropertySignatures(node);
1324
- properties.forEach((prop) => {
1325
- const propName = prop.name.toString();
1326
- if (prop.isOptional) {
1327
- const unwrappedAst = unwrapOptionProperty(prop);
1328
- if (isStruct(unwrappedAst)) {
1329
- return recurse(unwrappedAst, [
1330
- ...path,
1331
- propName
1332
- ], acc);
1333
- }
1334
- }
1335
- if (isStruct(prop.type)) {
1336
- recurse(prop.type, [
1337
- ...path,
1338
- propName
1339
- ], acc);
1340
- } else {
1341
- acc.push([
1342
- path.concat(propName).join("."),
1343
- propertyToColumn(prop)
1344
- ]);
1345
- }
1346
- });
1347
- return acc;
1348
- };
1349
- return recurse(schema.ast, [], []);
1350
- };
1351
1398
 
1352
1399
  // packages/ui/react-ui-table/src/schema/schemaToColumns.ts
1353
1400
  var schemaToColumnDefs = (schema) => {