@dxos/react-ui-table 0.8.3 → 0.8.4-main.c1de068

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 (125) hide show
  1. package/dist/lib/browser/chunk-5XLSHLOG.mjs +1751 -0
  2. package/dist/lib/browser/chunk-5XLSHLOG.mjs.map +7 -0
  3. package/dist/lib/browser/chunk-L2LSB6KV.mjs +18 -0
  4. package/dist/lib/browser/chunk-L2LSB6KV.mjs.map +7 -0
  5. package/dist/lib/browser/index.mjs +240 -1639
  6. package/dist/lib/browser/index.mjs.map +4 -4
  7. package/dist/lib/browser/meta.json +1 -1
  8. package/dist/lib/browser/testing/index.mjs +121 -0
  9. package/dist/lib/browser/testing/index.mjs.map +7 -0
  10. package/dist/lib/browser/types/index.mjs +3 -5
  11. package/dist/lib/node-esm/chunk-NXZ4CJYX.mjs +20 -0
  12. package/dist/lib/node-esm/chunk-NXZ4CJYX.mjs.map +7 -0
  13. package/dist/lib/node-esm/chunk-Y66YLSTC.mjs +1752 -0
  14. package/dist/lib/node-esm/chunk-Y66YLSTC.mjs.map +7 -0
  15. package/dist/lib/node-esm/index.mjs +240 -1639
  16. package/dist/lib/node-esm/index.mjs.map +4 -4
  17. package/dist/lib/node-esm/meta.json +1 -1
  18. package/dist/lib/node-esm/testing/index.mjs +122 -0
  19. package/dist/lib/node-esm/testing/index.mjs.map +7 -0
  20. package/dist/lib/node-esm/types/index.mjs +3 -5
  21. package/dist/types/src/components/Table/ColumnSettings.d.ts +3 -1
  22. package/dist/types/src/components/Table/ColumnSettings.d.ts.map +1 -1
  23. package/dist/types/src/components/Table/CreateRefPanel.d.ts.map +1 -1
  24. package/dist/types/src/components/Table/DynamicTable.d.ts +1 -1
  25. package/dist/types/src/components/Table/DynamicTable.d.ts.map +1 -1
  26. package/dist/types/src/components/Table/DynamicTable.stories.d.ts +1 -1
  27. package/dist/types/src/components/Table/DynamicTable.stories.d.ts.map +1 -1
  28. package/dist/types/src/components/Table/Table.d.ts.map +1 -1
  29. package/dist/types/src/components/Table/Table.stories.d.ts +1 -1
  30. package/dist/types/src/components/Table/Table.stories.d.ts.map +1 -1
  31. package/dist/types/src/components/Table/relations.stories.d.ts +1 -1
  32. package/dist/types/src/components/Table/relations.stories.d.ts.map +1 -1
  33. package/dist/types/src/components/TableCellEditor/CellValidationMessage.d.ts +2 -1
  34. package/dist/types/src/components/TableCellEditor/CellValidationMessage.d.ts.map +1 -1
  35. package/dist/types/src/components/TableCellEditor/FormCellEditor.d.ts +2 -1
  36. package/dist/types/src/components/TableCellEditor/FormCellEditor.d.ts.map +1 -1
  37. package/dist/types/src/components/TableCellEditor/TableCellEditor.d.ts +3 -2
  38. package/dist/types/src/components/TableCellEditor/TableCellEditor.d.ts.map +1 -1
  39. package/dist/types/src/components/TableCellEditor/TableCellEditor.stories.d.ts +1 -1
  40. package/dist/types/src/components/TableCellEditor/TableCellEditor.stories.d.ts.map +1 -1
  41. package/dist/types/src/components/testing.d.ts +3 -40
  42. package/dist/types/src/components/testing.d.ts.map +1 -1
  43. package/dist/types/src/hooks/index.d.ts +1 -0
  44. package/dist/types/src/hooks/index.d.ts.map +1 -1
  45. package/dist/types/src/hooks/useAddRow.d.ts +13 -0
  46. package/dist/types/src/hooks/useAddRow.d.ts.map +1 -0
  47. package/dist/types/src/hooks/useTableModel.d.ts +7 -6
  48. package/dist/types/src/hooks/useTableModel.d.ts.map +1 -1
  49. package/dist/types/src/index.d.ts +1 -2
  50. package/dist/types/src/index.d.ts.map +1 -1
  51. package/dist/types/src/model/selection-model.d.ts +2 -1
  52. package/dist/types/src/model/selection-model.d.ts.map +1 -1
  53. package/dist/types/src/model/table-model.d.ts +56 -20
  54. package/dist/types/src/model/table-model.d.ts.map +1 -1
  55. package/dist/types/src/model/table-presentation.d.ts +8 -0
  56. package/dist/types/src/model/table-presentation.d.ts.map +1 -1
  57. package/dist/types/src/model/table-sorting.d.ts +2 -2
  58. package/dist/types/src/model/table-sorting.d.ts.map +1 -1
  59. package/dist/types/src/playwright/playwright.config.d.ts +3 -0
  60. package/dist/types/src/playwright/playwright.config.d.ts.map +1 -0
  61. package/dist/types/src/testing/index.d.ts +2 -0
  62. package/dist/types/src/testing/index.d.ts.map +1 -0
  63. package/dist/types/src/testing/useTestTableModel.d.ts +41 -0
  64. package/dist/types/src/testing/useTestTableModel.d.ts.map +1 -0
  65. package/dist/types/src/translations.d.ts +3 -4
  66. package/dist/types/src/translations.d.ts.map +1 -1
  67. package/dist/types/src/types/index.d.ts +1 -1
  68. package/dist/types/src/types/index.d.ts.map +1 -1
  69. package/dist/types/src/types/schema.d.ts +8 -0
  70. package/dist/types/src/types/schema.d.ts.map +1 -0
  71. package/dist/types/src/util/dynamic-table.d.ts +3 -4
  72. package/dist/types/src/util/dynamic-table.d.ts.map +1 -1
  73. package/dist/types/src/util/table-buttons.d.ts +15 -1
  74. package/dist/types/src/util/table-buttons.d.ts.map +1 -1
  75. package/dist/types/src/util/table.d.ts +8 -11
  76. package/dist/types/src/util/table.d.ts.map +1 -1
  77. package/dist/types/tsconfig.tsbuildinfo +1 -1
  78. package/package.json +48 -40
  79. package/src/components/Table/ColumnSettings.tsx +14 -10
  80. package/src/components/Table/CreateRefPanel.tsx +5 -3
  81. package/src/components/Table/DynamicTable.stories.tsx +2 -2
  82. package/src/components/Table/DynamicTable.tsx +13 -7
  83. package/src/components/Table/Table.stories.tsx +104 -148
  84. package/src/components/Table/Table.tsx +50 -32
  85. package/src/components/Table/relations.stories.tsx +27 -35
  86. package/src/components/TableCellEditor/CellValidationMessage.tsx +6 -1
  87. package/src/components/TableCellEditor/FormCellEditor.tsx +30 -21
  88. package/src/components/TableCellEditor/TableCellEditor.stories.tsx +24 -28
  89. package/src/components/TableCellEditor/TableCellEditor.tsx +79 -21
  90. package/src/components/testing.ts +7 -24
  91. package/src/hooks/index.ts +1 -0
  92. package/src/hooks/useAddRow.ts +36 -0
  93. package/src/hooks/useTableModel.ts +20 -16
  94. package/src/index.ts +1 -2
  95. package/src/model/selection-model.ts +4 -2
  96. package/src/model/table-model.test.ts +7 -8
  97. package/src/model/table-model.ts +267 -78
  98. package/src/model/table-presentation.test.ts +6 -7
  99. package/src/model/table-presentation.ts +215 -132
  100. package/src/model/table-sorting.ts +9 -9
  101. package/src/playwright/playwright.config.ts +17 -0
  102. package/src/playwright/smoke.spec.ts +21 -20
  103. package/src/testing/index.ts +5 -0
  104. package/src/testing/useTestTableModel.ts +122 -0
  105. package/src/translations.ts +5 -3
  106. package/src/types/index.ts +2 -2
  107. package/src/types/schema.ts +16 -0
  108. package/src/util/dynamic-table.ts +19 -17
  109. package/src/util/table-buttons.ts +24 -1
  110. package/src/util/table.ts +33 -111
  111. package/dist/lib/browser/chunk-TL7CKQQV.mjs +0 -27
  112. package/dist/lib/browser/chunk-TL7CKQQV.mjs.map +0 -7
  113. package/dist/lib/node/chunk-O2VPBNS5.cjs +0 -50
  114. package/dist/lib/node/chunk-O2VPBNS5.cjs.map +0 -7
  115. package/dist/lib/node/index.cjs +0 -2739
  116. package/dist/lib/node/index.cjs.map +0 -7
  117. package/dist/lib/node/meta.json +0 -1
  118. package/dist/lib/node/types/index.cjs +0 -31
  119. package/dist/lib/node/types/index.cjs.map +0 -7
  120. package/dist/lib/node-esm/chunk-GBT6GD4G.mjs +0 -29
  121. package/dist/lib/node-esm/chunk-GBT6GD4G.mjs.map +0 -7
  122. package/dist/types/src/types/table.d.ts +0 -56
  123. package/dist/types/src/types/table.d.ts.map +0 -1
  124. package/src/playwright/playwright.config.cts +0 -18
  125. package/src/types/table.ts +0 -27
@@ -1,12 +1,28 @@
1
1
  import { createRequire } from 'node:module';const require = createRequire(import.meta.url);
2
2
  import {
3
- TableSchema,
4
- TableType
5
- } from "./chunk-GBT6GD4G.mjs";
3
+ BUTTON_IDENTIFIERS,
4
+ CONTROL_IDENTIFIERS,
5
+ CheckboxStory,
6
+ ModalController,
7
+ SwitchStory,
8
+ TableModel,
9
+ TablePresentation,
10
+ cellClassesForRowSelection,
11
+ createTable,
12
+ getBaseSchema,
13
+ makeDynamicTable,
14
+ narrowSchema,
15
+ tableButtons,
16
+ tableControls,
17
+ touch,
18
+ useAddRow,
19
+ useTableModel
20
+ } from "./chunk-Y66YLSTC.mjs";
21
+ import "./chunk-NXZ4CJYX.mjs";
6
22
 
7
- // packages/ui/react-ui-table/src/translations.ts
8
- var translationKey = "table";
9
- var translations_default = [
23
+ // src/translations.ts
24
+ var translationKey = "react-ui-table";
25
+ var translations = [
10
26
  {
11
27
  "en-US": {
12
28
  [translationKey]: {
@@ -36,19 +52,20 @@ var translations_default = [
36
52
  }
37
53
  ];
38
54
 
39
- // packages/ui/react-ui-table/src/components/Table/Table.tsx
55
+ // src/components/Table/Table.tsx
40
56
  import { useSignals as _useSignals8 } from "@preact-signals/safe-react/tracking";
41
- import React8, { forwardRef, useCallback as useCallback5, useImperativeHandle, useState as useState3, useMemo as useMemo5, useEffect as useEffect3 } from "react";
42
- import { getValue as getValue4 } from "@dxos/echo-schema";
43
- import { invariant as invariant4 } from "@dxos/invariant";
44
- import { Filter } from "@dxos/react-client/echo";
57
+ import React8, { forwardRef, useCallback as useCallback5, useImperativeHandle, useState as useState4, useMemo as useMemo5, useEffect as useEffect4 } from "react";
58
+ import { Filter } from "@dxos/echo";
59
+ import { getValue } from "@dxos/echo-schema";
60
+ import { invariant as invariant3 } from "@dxos/invariant";
61
+ import { getSpace as getSpace2 } from "@dxos/react-client/echo";
45
62
  import { useTranslation as useTranslation3 } from "@dxos/react-ui";
46
63
  import { useAttention } from "@dxos/react-ui-attention";
47
64
  import { closestCell, Grid, gridSeparatorInlineEnd, gridSeparatorBlockEnd } from "@dxos/react-ui-grid";
48
- import { mx as mx2 } from "@dxos/react-ui-theme";
65
+ import { mx } from "@dxos/react-ui-theme";
49
66
  import { isNotFalsy, safeParseInt } from "@dxos/util";
50
67
 
51
- // packages/ui/react-ui-table/src/components/Table/ColumnActionsMenu.tsx
68
+ // src/components/Table/ColumnActionsMenu.tsx
52
69
  import { useSignals as _useSignals } from "@preact-signals/safe-react/tracking";
53
70
  import React from "react";
54
71
  import { DropdownMenu, useTranslation } from "@dxos/react-ui";
@@ -89,17 +106,16 @@ var ColumnActionsMenu = ({ model, modals }) => {
89
106
  }
90
107
  };
91
108
 
92
- // packages/ui/react-ui-table/src/components/Table/ColumnSettings.tsx
109
+ // src/components/Table/ColumnSettings.tsx
93
110
  import { useSignals as _useSignals2 } from "@preact-signals/safe-react/tracking";
94
111
  import React2, { useCallback, useEffect, useMemo, useState } from "react";
95
112
  import { Popover } from "@dxos/react-ui";
96
113
  import { FieldEditor } from "@dxos/react-ui-form";
97
- var ColumnSettings = ({ model, modals, onNewColumn }) => {
114
+ var ColumnSettings = ({ registry, model, modals, onNewColumn }) => {
98
115
  var _effect = _useSignals2();
99
116
  try {
100
117
  const [newField, setNewField] = useState();
101
118
  const state = modals.state.value;
102
- const space = model?.space;
103
119
  useEffect(() => {
104
120
  if (state?.type === "columnSettings" && state.mode.type === "create" && model?.projection) {
105
121
  setNewField(model.projection.createFieldProjection());
@@ -117,12 +133,12 @@ var ColumnSettings = ({ model, modals, onNewColumn }) => {
117
133
  if (state?.type === "columnSettings") {
118
134
  const { mode } = state;
119
135
  if (mode.type === "edit") {
120
- return model?.view?.fields.find((f) => f.id === mode.fieldId);
136
+ return model?.projection?.fields.find((f) => f.id === mode.fieldId);
121
137
  }
122
138
  }
123
139
  return void 0;
124
140
  }, [
125
- model?.view?.fields,
141
+ model?.projection?.fields,
126
142
  state
127
143
  ]);
128
144
  const field = existingField ?? newField;
@@ -133,14 +149,14 @@ var ColumnSettings = ({ model, modals, onNewColumn }) => {
133
149
  ]);
134
150
  const handleCancel = useCallback(() => {
135
151
  if (state?.type === "columnSettings" && state.mode.type === "create" && newField) {
136
- model?.projection?.deleteFieldProjection(newField.id);
152
+ model?.projection.deleteFieldProjection(newField.id);
137
153
  }
138
154
  }, [
139
155
  model?.projection,
140
156
  state,
141
157
  newField
142
158
  ]);
143
- if (!model?.view || !model.projection || !field) {
159
+ if (!model?.projection || !field) {
144
160
  return null;
145
161
  }
146
162
  return /* @__PURE__ */ React2.createElement(Popover.Root, {
@@ -151,10 +167,9 @@ var ColumnSettings = ({ model, modals, onNewColumn }) => {
151
167
  }), /* @__PURE__ */ React2.createElement(Popover.Portal, null, /* @__PURE__ */ React2.createElement(Popover.Content, {
152
168
  classNames: "md:is-64"
153
169
  }, /* @__PURE__ */ React2.createElement(Popover.Viewport, null, /* @__PURE__ */ React2.createElement(FieldEditor, {
154
- view: model.view,
155
170
  projection: model.projection,
156
171
  field,
157
- registry: space?.db.schemaRegistry,
172
+ registry,
158
173
  onSave: handleSave,
159
174
  onCancel: handleCancel
160
175
  })), /* @__PURE__ */ React2.createElement(Popover.Arrow, null))));
@@ -163,11 +178,12 @@ var ColumnSettings = ({ model, modals, onNewColumn }) => {
163
178
  }
164
179
  };
165
180
 
166
- // packages/ui/react-ui-table/src/components/Table/CreateRefPanel.tsx
181
+ // src/components/Table/CreateRefPanel.tsx
167
182
  import { useSignals as _useSignals3 } from "@preact-signals/safe-react/tracking";
168
183
  import { Schema } from "effect";
169
184
  import React3, { useCallback as useCallback2, useMemo as useMemo2 } from "react";
170
- import { live } from "@dxos/react-client/echo";
185
+ import { live } from "@dxos/live-object";
186
+ import { getSpace } from "@dxos/react-client/echo";
171
187
  import { Popover as Popover2 } from "@dxos/react-ui";
172
188
  import { Form } from "@dxos/react-ui-form";
173
189
  import { useGridContext } from "@dxos/react-ui-grid";
@@ -175,7 +191,7 @@ var CreateRefPanel = ({ model, modals, __gridScope }) => {
175
191
  var _effect = _useSignals3();
176
192
  try {
177
193
  const { id: gridId } = useGridContext("TableCellEditor", __gridScope);
178
- const space = model?.space;
194
+ const space = model && getSpace(model?.view);
179
195
  const state = modals.state.value;
180
196
  const schema = useMemo2(() => {
181
197
  if (!space || state?.type !== "createRefPanel") {
@@ -216,7 +232,7 @@ var CreateRefPanel = ({ model, modals, __gridScope }) => {
216
232
  }, [
217
233
  modals
218
234
  ]);
219
- if (!model?.view || !model.projection) {
235
+ if (!model?.projection) {
220
236
  return null;
221
237
  }
222
238
  return /* @__PURE__ */ React3.createElement(Popover2.Root, {
@@ -243,7 +259,7 @@ var CreateRefPanel = ({ model, modals, __gridScope }) => {
243
259
  }
244
260
  };
245
261
 
246
- // packages/ui/react-ui-table/src/components/Table/RowActionsMenu.tsx
262
+ // src/components/Table/RowActionsMenu.tsx
247
263
  import { useSignals as _useSignals4 } from "@preact-signals/safe-react/tracking";
248
264
  import React4 from "react";
249
265
  import { DropdownMenu as DropdownMenu2, useTranslation as useTranslation2 } from "@dxos/react-ui";
@@ -278,1445 +294,32 @@ var RowActionsMenu = ({ model, modals }) => {
278
294
  }
279
295
  };
280
296
 
281
- // packages/ui/react-ui-table/src/model/table-model.ts
282
- import { computed as computed3, effect as effect2, signal as signal3 } from "@preact/signals-core";
283
- import { Resource as Resource2 } from "@dxos/context";
284
- import { FormatEnum as FormatEnum3, getValue as getValue2, setValue, getSnapshot, getSchema } from "@dxos/echo-schema";
285
- import { invariant } from "@dxos/invariant";
286
- import { isLiveObject, makeRef } from "@dxos/live-object";
287
- import { formatForEditing, parseValue } from "@dxos/react-ui-form";
288
- import { validateSchema } from "@dxos/schema";
289
-
290
- // packages/ui/react-ui-table/src/model/selection-model.ts
291
- import { computed, effect, signal } from "@preact/signals-core";
292
- import { Resource } from "@dxos/context";
293
-
294
- // packages/ui/react-ui-table/src/util/dynamic-table.ts
295
- import { Obj, Ref } from "@dxos/echo";
296
- import { getTypename, toJsonSchema } from "@dxos/echo-schema";
297
- import { createView, getSchemaFromPropertyDefinitions, ViewProjection } from "@dxos/schema";
298
- var getBaseSchema = ({ typename, properties, jsonSchema, schema }) => {
299
- if (typename && properties) {
300
- const schema2 = getSchemaFromPropertyDefinitions(typename, properties);
301
- return {
302
- typename: schema2.typename,
303
- jsonSchema: schema2.jsonSchema
304
- };
305
- } else if (schema) {
306
- return {
307
- typename: getTypename(schema),
308
- jsonSchema: toJsonSchema(schema)
309
- };
310
- } else if (typename && jsonSchema) {
311
- return {
312
- typename,
313
- jsonSchema
314
- };
315
- } else {
316
- throw new Error("invalid properties");
317
- }
318
- };
319
- var makeDynamicTable = ({ typename, jsonSchema, properties }) => {
320
- const view = createView({
321
- name: "dynamic-table",
322
- typename,
323
- jsonSchema,
324
- ...properties && {
325
- fields: properties.map((property) => property.name)
326
- }
327
- });
328
- const table = Obj.make(TableType, {
329
- name: "dynamic-table",
330
- view: Ref.make(view)
331
- });
332
- const projection = new ViewProjection(jsonSchema, view);
333
- if (properties && view.fields) {
334
- setProperties(view, projection, properties);
335
- }
336
- return {
337
- table,
338
- projection
339
- };
340
- };
341
- var setProperties = (view, projection, properties) => {
342
- for (const property of properties) {
343
- const field = view.fields.find((field2) => field2.path === property.name);
344
- if (field) {
345
- if (property.size !== void 0) {
346
- field.size = property.size;
347
- }
348
- if (property.title !== void 0) {
349
- const fieldProjection = projection.getFieldProjection(field.id);
350
- projection.setFieldProjection({
351
- ...fieldProjection,
352
- props: {
353
- ...fieldProjection.props,
354
- title: property.title
355
- }
356
- });
357
- }
358
- if (property.sort) {
359
- const fieldId = field.id;
360
- view.query.sort = [
361
- {
362
- fieldId,
363
- direction: property.sort
364
- }
365
- ];
366
- }
367
- }
368
- }
369
- };
370
-
371
- // packages/ui/react-ui-table/src/util/signals.ts
372
- var touch = (value) => value;
373
-
374
- // packages/ui/react-ui-table/src/util/table.ts
375
- import { Schema as Schema2 } from "effect";
376
- import { Format, FormatEnum, Ref as Ref2, TypedObject, TypeEnum } from "@dxos/echo-schema";
377
- import { PublicKey } from "@dxos/react-client";
378
- import { live as live2 } from "@dxos/react-client/echo";
379
- import { createFieldId, createView as createView2, getSchemaProperties, ViewProjection as ViewProjection2 } from "@dxos/schema";
380
- var initializeTable = async ({ client, space, table, typename, initialRow = true }) => {
381
- if (typename) {
382
- const schema = await space.db.graph.getSchemaByTypename(typename, space.db);
383
- if (!schema) {
384
- throw new Error(`Schema not found: ${typename}`);
385
- }
386
- const fields = getSchemaProperties(schema.ast).map((prop) => prop.name);
387
- table.view = Ref2.make(createView2({
388
- // TODO(ZaymonFC): Don't hardcode name?
389
- name: "View",
390
- typename: schema.typename,
391
- jsonSchema: schema.jsonSchema,
392
- fields
393
- }));
394
- return schema;
395
- } else {
396
- const [schema] = await space.db.schemaRegistry.register([
397
- createContactSchema()
398
- ]);
399
- const fields = ContactFields;
400
- table.view = Ref2.make(createView2({
401
- name: "View",
402
- typename: schema.typename,
403
- jsonSchema: schema.jsonSchema,
404
- fields
405
- }));
406
- createProjection(schema, table.view.target);
407
- if (initialRow) {
408
- space.db.add(live2(schema, {}));
409
- }
410
- return schema;
411
- }
412
- };
413
- var createContactSchema = () => TypedObject({
414
- typename: `example.com/type/${PublicKey.random().truncate()}`,
415
- version: "0.1.0"
416
- })({
417
- name: Schema2.optional(Schema2.String).annotations({
418
- title: "Name"
419
- }),
420
- active: Schema2.optional(Schema2.Boolean).annotations({
421
- title: "Active"
422
- }),
423
- email: Schema2.optional(Format.Email),
424
- salary: Schema2.optional(Format.Currency()).annotations({
425
- title: "Salary"
426
- })
427
- });
428
- var ContactFields = [
429
- "name",
430
- "email",
431
- "salary",
432
- "active"
433
- ];
434
- var createProjection = (schema, view) => {
435
- const projection = new ViewProjection2(schema.jsonSchema, view);
436
- projection.setFieldProjection({
437
- field: {
438
- id: view.fields.find((f) => f.path === "salary").id,
439
- path: "salary",
440
- size: 150
441
- }
442
- });
443
- projection.setFieldProjection({
444
- field: {
445
- id: view.fields.find((f) => f.path === "active").id,
446
- path: "active",
447
- size: 100
448
- }
449
- });
450
- projection.setFieldProjection({
451
- field: {
452
- id: createFieldId(),
453
- path: "manager",
454
- referencePath: "name"
455
- },
456
- props: {
457
- property: "manager",
458
- type: TypeEnum.Ref,
459
- format: FormatEnum.Ref,
460
- referenceSchema: schema.typename,
461
- title: "Manager"
462
- }
463
- });
464
- return projection;
465
- };
466
-
467
- // packages/ui/react-ui-table/src/util/table-buttons.ts
468
- var BUTTON_IDENTIFIERS = {
469
- columnSettings: "data-table-column-settings-button",
470
- newColumn: "data-table-new-column-button",
471
- referencedCell: "data-table-ref-cell-button",
472
- rowMenu: "data-table-row-menu-button",
473
- sort: "data-table-sort-button"
474
- };
475
- var createButton = ({ attr, data, disabled = false, icon, testId, type = "primary" }) => {
476
- const dataAttrs = Object.entries(data).map(([k, v]) => `${k}="${v}"`).join(" ");
477
- const positionClass = type === "primary" ? "inline-end-2" : "inline-end-9";
478
- return `<button ${attr} data-testid="${testId}" class="dx-button is-6 pli-0.5 min-bs-0 absolute inset-block-1 ${positionClass}" ${dataAttrs} ${disabled ? "disabled" : ""}><svg data-size="4"><use href="/icons.svg#${icon}"/></svg></button>`;
479
- };
480
- var addColumnButton = {
481
- attr: BUTTON_IDENTIFIERS.newColumn,
482
- icon: "ph--plus--regular",
483
- render: ({ disabled }) => {
484
- return createButton({
485
- attr: BUTTON_IDENTIFIERS.newColumn,
486
- icon: addColumnButton.icon,
487
- disabled,
488
- data: {},
489
- testId: "table-new-column-button"
490
- });
491
- },
492
- getData: (_el) => ({
493
- type: "newColumn"
494
- })
495
- };
496
- var columnSettingsButton = {
497
- attr: BUTTON_IDENTIFIERS.columnSettings,
498
- icon: "ph--caret-down--regular",
499
- render: ({ fieldId }) => {
500
- return createButton({
501
- attr: BUTTON_IDENTIFIERS.columnSettings,
502
- icon: columnSettingsButton.icon,
503
- data: {
504
- "data-field-id": fieldId
505
- },
506
- testId: "table-column-settings-button"
507
- });
508
- },
509
- getData: (el) => ({
510
- type: "columnSettings",
511
- fieldId: el.getAttribute("data-field-id")
512
- })
513
- };
514
- var rowMenuButton = {
515
- attr: BUTTON_IDENTIFIERS.rowMenu,
516
- icon: "ph--dots-three--regular",
517
- render: ({ rowIndex }) => {
518
- return createButton({
519
- attr: BUTTON_IDENTIFIERS.rowMenu,
520
- icon: rowMenuButton.icon,
521
- data: {
522
- "data-row-index": rowIndex.toString()
523
- },
524
- testId: "table-row-menu-button"
525
- });
526
- },
527
- getData: (el) => ({
528
- type: "rowMenu",
529
- rowIndex: Number(el.getAttribute("data-row-index"))
530
- })
531
- };
532
- var sortButton = {
533
- attr: BUTTON_IDENTIFIERS.sort,
534
- icon: "ph--sort-ascending--regular",
535
- render: ({ fieldId, direction }) => {
536
- return createButton({
537
- attr: BUTTON_IDENTIFIERS.sort,
538
- icon: direction === "desc" ? "ph--sort-descending--regular" : "ph--sort-ascending--regular",
539
- data: {
540
- "data-field-id": fieldId,
541
- "data-direction": direction ?? ""
542
- },
543
- testId: "table-sort-button",
544
- // TODO(ZaymonFC): All buttons should be rendered into an absolutely positioned flex container.
545
- // This is a bit hacky.
546
- type: "secondary"
547
- });
548
- },
549
- getData: (el) => ({
550
- type: "sort",
551
- fieldId: el.getAttribute("data-field-id"),
552
- direction: el.getAttribute("data-direction")
553
- })
554
- };
555
- var tableButtons = {
556
- addColumn: addColumnButton,
557
- columnSettings: columnSettingsButton,
558
- rowMenu: rowMenuButton,
559
- sort: sortButton
560
- };
561
-
562
- // packages/ui/react-ui-table/src/util/table-controls.ts
563
- var CONTROL_IDENTIFIERS = {
564
- checkbox: "data-table-checkbox",
565
- switch: "data-table-switch"
566
- };
567
- var BASE_CLASSES = {
568
- checkbox: "absolute inset-block-[.375rem] inline-end-[.375rem] dx-checkbox",
569
- switch: "absolute inset-block-[.25rem] inline-end-[.25rem] dx-checkbox--switch"
570
- };
571
- var renderAttributes = (data) => {
572
- return Object.entries(data).map(([k, v]) => `${k}="${v}"`).join(" ");
573
- };
574
- var renderInput = (baseClass, attrs, checked = false, disabled = false, preventToggle = false, testId) => {
575
- return `<input type="checkbox" class="${baseClass}" ${renderAttributes(attrs)} ${checked ? "checked" : ""} ${preventToggle ? 'onclick="return false"' : ""} ${disabled ? "disabled" : ""} data-testid="${testId}"/>`;
576
- };
577
- var CheckboxStory = ({ rowIndex, header = false, checked = false, disabled = false }) => {
578
- const attrs = {
579
- [CONTROL_IDENTIFIERS.checkbox]: "",
580
- "data-row-index": rowIndex.toString(),
581
- ...header && {
582
- "data-header": ""
583
- }
584
- };
585
- return renderInput(BASE_CLASSES.checkbox, attrs, checked, disabled, true, "table-selection");
586
- };
587
- var SwitchStory = ({ colIndex, rowIndex, checked = false, disabled = false }) => {
588
- const attrs = {
589
- [CONTROL_IDENTIFIERS.switch]: "",
590
- "data-row-index": rowIndex.toString(),
591
- "data-col-index": colIndex.toString()
592
- };
593
- return renderInput(BASE_CLASSES.switch, attrs, checked, disabled, true, "table-switch");
594
- };
595
- var tableControls = {
596
- checkbox: {
597
- attr: CONTROL_IDENTIFIERS.checkbox,
598
- render: CheckboxStory,
599
- getData: (el) => ({
600
- type: "checkbox",
601
- rowIndex: Number(el.getAttribute("data-row-index")),
602
- header: el.hasAttribute("data-header")
603
- })
604
- },
605
- switch: {
606
- attr: CONTROL_IDENTIFIERS.switch,
607
- render: SwitchStory,
608
- getData: (el) => ({
609
- type: "switch",
610
- rowIndex: Number(el.getAttribute("data-row-index")),
611
- colIndex: Number(el.getAttribute("data-col-index"))
612
- })
613
- }
614
- };
615
-
616
- // packages/ui/react-ui-table/src/util/schema.ts
617
- import { Schema as Schema3 } from "effect";
618
- import { isTypeLiteral, TypeLiteral } from "effect/SchemaAST";
619
- var narrowSchema = (schema, paths) => {
620
- const ast = schema?.ast;
621
- if (isTypeLiteral(ast)) {
622
- const propertySignatures = ast.propertySignatures.filter((signature) => paths.includes(signature.name.toString()));
623
- if (propertySignatures.length > 0) {
624
- const narrowType = new TypeLiteral(propertySignatures, []);
625
- return Schema3.make(narrowType);
626
- }
627
- }
628
- return void 0;
629
- };
630
-
631
- // packages/ui/react-ui-table/src/model/selection-model.ts
632
- var SelectionModel = class extends Resource {
633
- constructor(_rows, _selectionMode, _onSelectionChanged) {
634
- super(), this._rows = _rows, this._selectionMode = _selectionMode, this._onSelectionChanged = _onSelectionChanged, this._selection = signal(/* @__PURE__ */ new Set()), this._validSelectedIds = computed(() => {
635
- const rows = this._rows.value;
636
- if (!rows) {
637
- return /* @__PURE__ */ new Set();
638
- }
639
- const validIds = new Set(rows.map((row) => row.id));
640
- return new Set([
641
- ...this._selection.value
642
- ].filter((id) => validIds.has(id)));
643
- }), this._hasSelection = computed(() => this._validSelectedIds.value.size > 0), this._allSelected = computed(() => {
644
- const rows = this._rows.value;
645
- if (rows.length === 0) {
646
- return false;
647
- }
648
- return rows.every((row) => this._selection.value.has(row.id));
649
- }), this.getSelectedRows = () => {
650
- const selectedIds = this._validSelectedIds.value;
651
- return this._rows.value.filter((row) => selectedIds.has(row.id));
652
- }, this.isRowIndexSelected = (rowIndex) => {
653
- const row = this._rows.value[rowIndex];
654
- return this._selection.value.has(row.id);
655
- }, this.isObjectSelected = (object) => {
656
- return this._selection.value.has(object.id);
657
- }, this.toggleSelectionForRowIndex = (rowIndex) => {
658
- const row = this._rows.value[rowIndex];
659
- const newSelection = new Set(this._selection.value);
660
- if (newSelection.has(row.id)) {
661
- newSelection.delete(row.id);
662
- } else {
663
- if (this._selectionMode === "single") {
664
- newSelection.clear();
665
- }
666
- newSelection.add(row.id);
667
- }
668
- this._selection.value = newSelection;
669
- }, this.setSelection = (mode) => {
670
- switch (mode) {
671
- case "all": {
672
- this._selection.value = new Set(this._rows.value.map((row) => row.id));
673
- break;
674
- }
675
- case "none": {
676
- this._selection.value = /* @__PURE__ */ new Set();
677
- break;
678
- }
679
- }
680
- };
681
- }
682
- async _open() {
683
- const selectionWatcher = effect(() => {
684
- touch(this._selection.value);
685
- this._onSelectionChanged?.();
686
- });
687
- this._ctx.onDispose(selectionWatcher);
688
- }
689
- //
690
- // Getters
691
- //
692
- get selection() {
693
- return this._selection;
694
- }
695
- get hasSelection() {
696
- return this._hasSelection;
697
- }
698
- get allRowsSeleted() {
699
- return this._allSelected;
700
- }
701
- get selectionMode() {
702
- return this._selectionMode;
703
- }
704
- };
705
-
706
- // packages/ui/react-ui-table/src/model/table-sorting.ts
707
- import { computed as computed2, signal as signal2 } from "@preact/signals-core";
708
- import orderBy from "lodash.orderby";
709
- import { getValue, FormatEnum as FormatEnum2, TypeEnum as TypeEnum2 } from "@dxos/echo-schema";
710
- import { formatForDisplay } from "@dxos/react-ui-form";
711
- var TableSorting = class {
712
- constructor(rows, _view, _projection) {
713
- this._view = _view;
714
- this._projection = _projection;
715
- this._displayToDataIndex = /* @__PURE__ */ new Map();
716
- this._localSort = signal2(void 0);
717
- this._rows = rows;
718
- this._isDirty = computed2(() => {
719
- const local = this._localSort.value;
720
- const viewSort = this._view?.query.sort?.[0];
721
- if (local?.type === "cleared") {
722
- return viewSort !== void 0;
723
- }
724
- if (local?.type === "active") {
725
- if (!viewSort) {
726
- return true;
727
- }
728
- return local.sort.fieldId !== viewSort.fieldId || local.sort.direction !== viewSort.direction;
729
- }
730
- return false;
731
- });
732
- this.sortedRows = this.initialiseSortedRows();
733
- }
734
- /**
735
- * @reactive
736
- * @returns Local sort if present, falls back to view sort.
737
- */
738
- get sorting() {
739
- const local = this._localSort.value;
740
- if (local?.type === "cleared") {
741
- return void 0;
742
- }
743
- if (local?.type === "active") {
744
- return local.sort;
745
- }
746
- return this._view?.query.sort?.[0];
747
- }
748
- /**
749
- * @reactive
750
- * @returns Whether local sort differs from view sort.
751
- */
752
- get isDirty() {
753
- return this._isDirty.value;
754
- }
755
- getDataIndex(displayIndex) {
756
- return this._displayToDataIndex.get(displayIndex) ?? displayIndex;
757
- }
758
- setSort(fieldId, direction) {
759
- this._localSort.value = {
760
- type: "active",
761
- sort: {
762
- fieldId,
763
- direction
764
- }
765
- };
766
- }
767
- toggleSort(fieldId) {
768
- if (!this._view || !this.sorting || this.sorting.fieldId !== fieldId) {
769
- return;
770
- }
771
- switch (this.sorting.direction) {
772
- case "asc": {
773
- this.setSort(fieldId, "desc");
774
- break;
775
- }
776
- case "desc": {
777
- this.setSort(fieldId, "asc");
778
- break;
779
- }
780
- }
781
- }
782
- clearSort() {
783
- this._localSort.value = {
784
- type: "cleared"
785
- };
786
- }
787
- save() {
788
- if (this._view && this._localSort.value !== void 0) {
789
- if (this._localSort.value.type === "active") {
790
- this._view.query.sort = [
791
- this._localSort.value.sort
792
- ];
793
- } else {
794
- this._view.query.sort = [];
795
- }
796
- this._localSort.value = void 0;
797
- }
798
- }
799
- //
800
- // Initialisation.
801
- //
802
- initialiseSortedRows() {
803
- return computed2(() => {
804
- this._displayToDataIndex.clear();
805
- const sort = this.sorting;
806
- if (!sort || !this._view) {
807
- return this._rows.value;
808
- }
809
- const field = this._view.fields.find((f) => f.id === sort.fieldId);
810
- if (!field) {
811
- return this._rows.value;
812
- }
813
- const { props } = this._projection.getFieldProjection(field.id);
814
- const dataWithIndices = this._rows.value.map((item, index) => {
815
- const sortValue = this.getSortValue(props, field, item);
816
- const isEmpty = !(props.type === TypeEnum2.Boolean) && (sortValue == null || sortValue === "");
817
- return {
818
- item,
819
- index,
820
- value: sortValue,
821
- isEmpty
822
- };
823
- });
824
- const ordered = orderBy(dataWithIndices, [
825
- "isEmpty",
826
- "value"
827
- ], [
828
- "asc",
829
- sort.direction
830
- ]);
831
- ordered.forEach(({ index: dataIndex }, displayIndex) => {
832
- if (displayIndex !== dataIndex) {
833
- this._displayToDataIndex.set(displayIndex, dataIndex);
834
- }
835
- });
836
- return ordered.map(({ item }) => item);
837
- });
838
- }
839
- getSortValue(props, field, item) {
840
- const { type, format } = props;
841
- const value = getValue(item, field.path);
842
- if (type === TypeEnum2.Boolean) {
843
- return !!value;
844
- }
845
- if (type === TypeEnum2.Number) {
846
- return value;
847
- }
848
- if (value == null) {
849
- return value;
850
- }
851
- if (format === FormatEnum2.SingleSelect) {
852
- const options = props.options;
853
- if (!options) {
854
- return void 0;
855
- }
856
- const option = options.find((option2) => option2.id === value);
857
- return option ? options.indexOf(option) : void 0;
858
- }
859
- if (format === FormatEnum2.Ref && field.referencePath) {
860
- const refValue = getValue(value.target, field.referencePath);
861
- return refValue;
862
- }
863
- return formatForDisplay({
864
- type,
865
- format,
866
- value
867
- });
868
- }
869
- };
870
-
871
- // packages/ui/react-ui-table/src/util/tag.ts
872
- var TAG_PATTERN_REGEX = /\[([^\]]+)\]\(([^)]+)\)/g;
873
- var extractTagIds = (value) => {
874
- if (typeof value !== "string") {
875
- return void 0;
876
- }
877
- const ids = [];
878
- let match;
879
- while ((match = TAG_PATTERN_REGEX.exec(value)) !== null) {
880
- if (match[2]) {
881
- ids.push(match[2]);
882
- }
883
- }
884
- return ids.length > 0 ? ids : void 0;
885
- };
886
-
887
- // packages/ui/react-ui-table/src/model/table-model.ts
888
- var __dxlog_file = "/home/runner/work/dxos/dxos/packages/ui/react-ui-table/src/model/table-model.ts";
889
- var defaultFeatures = {
890
- selection: {
891
- enabled: true,
892
- mode: "multiple"
893
- },
894
- dataEditable: false,
895
- schemaEditable: false
896
- };
897
- var TableModel = class extends Resource2 {
898
- constructor({ id, space, view, projection, features = {}, sorting = [], pinnedRows = {
899
- top: [],
900
- bottom: []
901
- }, rowActions = [], onCellUpdate, onDeleteColumn, onDeleteRows, onInsertRow, onRowOrderChange, onRowAction }) {
902
- super();
903
- this._visibleRange = signal3({
904
- start: {
905
- row: 0,
906
- col: 0
907
- },
908
- end: {
909
- row: 0,
910
- col: 0
911
- }
912
- });
913
- this._rows = signal3([]);
914
- //
915
- // Data
916
- //
917
- this.setRows = (obj) => {
918
- this._rows.value = obj;
919
- };
920
- this.getRowCount = () => this._rows.value.length;
921
- this.getColumnCount = () => this._view?.fields.length ?? 0;
922
- this.insertRow = (rowIndex) => {
923
- const row = rowIndex !== void 0 ? this._sorting.getDataIndex(rowIndex) : this._rows.value.length;
924
- this._onInsertRow?.(row);
925
- };
926
- this.deleteRow = (rowIndex) => {
927
- const row = this._sorting.getDataIndex(rowIndex);
928
- const obj = this._rows.value[row];
929
- const objectsToDelete = [];
930
- if (this.features.selection.enabled && this._selection.hasSelection.value) {
931
- const selectedRows = this._selection.getSelectedRows();
932
- objectsToDelete.push(...selectedRows);
933
- } else {
934
- objectsToDelete.push(obj);
935
- }
936
- this._onDeleteRows?.(row, objectsToDelete);
937
- };
938
- this.handleRowAction = (actionId, rowIndex) => {
939
- if (!this._onRowAction) {
940
- return;
941
- }
942
- const row = this._sorting.getDataIndex(rowIndex);
943
- const data = this._rows.value[row];
944
- if (data) {
945
- this._onRowAction(actionId, data);
946
- }
947
- };
948
- this.getCellData = ({ col, row }) => {
949
- const fields = this._view?.fields ?? [];
950
- if (col < 0 || col >= fields.length) {
951
- return void 0;
952
- }
953
- const field = fields[col];
954
- const dataIndex = this._sorting.getDataIndex(row);
955
- const value = getValue2(this._rows.value[dataIndex], field.path);
956
- if (value == null) {
957
- return "";
958
- }
959
- const { props } = this._projection.getFieldProjection(field.id);
960
- switch (props.format) {
961
- case FormatEnum3.Ref: {
962
- if (!field.referencePath) {
963
- return "";
964
- }
965
- return getValue2(value.target, field.referencePath);
966
- }
967
- default: {
968
- return formatForEditing({
969
- type: props.type,
970
- format: props.format,
971
- value
972
- });
973
- }
974
- }
975
- };
976
- this.validateCellData = async ({ col, row }, value) => {
977
- const rowIdx = this._sorting.getDataIndex(row);
978
- const fields = this._view?.fields ?? [];
979
- if (col < 0 || col >= fields.length) {
980
- return {
981
- valid: false,
982
- error: "Invalid column index"
983
- };
984
- }
985
- const field = fields[col];
986
- const { props } = this._projection.getFieldProjection(field.id);
987
- const currentRow = this._rows.value[rowIdx];
988
- invariant(currentRow, "Invalid row index", {
989
- F: __dxlog_file,
990
- L: 355,
991
- S: this,
992
- A: [
993
- "currentRow",
994
- "'Invalid row index'"
995
- ]
996
- });
997
- const snapshot = getSnapshot(currentRow);
998
- const transformedValue = editorTextToCellValue(props, value);
999
- setValue(snapshot, field.path, transformedValue);
1000
- const schema = getSchema(currentRow);
1001
- invariant(schema, void 0, {
1002
- F: __dxlog_file,
1003
- L: 365,
1004
- S: this,
1005
- A: [
1006
- "schema",
1007
- ""
1008
- ]
1009
- });
1010
- const validationResult = validateSchema(schema, snapshot);
1011
- if (validationResult && validationResult.length > 0) {
1012
- const error = validationResult[0];
1013
- invariant(error.path === field.path, void 0, {
1014
- F: __dxlog_file,
1015
- L: 370,
1016
- S: this,
1017
- A: [
1018
- "error.path === field.path",
1019
- ""
1020
- ]
1021
- });
1022
- return {
1023
- valid: false,
1024
- error: error.message
1025
- };
1026
- }
1027
- return {
1028
- valid: true
1029
- };
1030
- };
1031
- this.setCellData = ({ col, row }, value) => {
1032
- const rowIdx = this._sorting.getDataIndex(row);
1033
- const fields = this._view?.fields ?? [];
1034
- if (col < 0 || col >= fields.length) {
1035
- return;
1036
- }
1037
- const field = fields[col];
1038
- const { props } = this._projection.getFieldProjection(field.id);
1039
- const transformedValue = editorTextToCellValue(props, value);
1040
- if (props.format === FormatEnum3.Ref && !isLiveObject(value)) {
1041
- return;
1042
- }
1043
- setValue(this._rows.value[rowIdx], field.path, transformedValue);
1044
- };
1045
- this._id = id;
1046
- this._space = space;
1047
- this._view = view;
1048
- this._projection = projection;
1049
- this._features = {
1050
- ...defaultFeatures,
1051
- ...features
1052
- };
1053
- invariant(!(this._features.dataEditable && this._features.selection.enabled && this._features.selection.mode === "single"), "Single selection is not compatible with editable tables.", {
1054
- F: __dxlog_file,
1055
- L: 126,
1056
- S: this,
1057
- A: [
1058
- "!(this._features.dataEditable && this._features.selection.enabled && this._features.selection.mode === 'single')",
1059
- "'Single selection is not compatible with editable tables.'"
1060
- ]
1061
- });
1062
- this._sorting = new TableSorting(this._rows, this._view, projection);
1063
- if (sorting.length > 0) {
1064
- const [sort] = sorting;
1065
- this._sorting.setSort(sort.fieldId, sort.direction);
1066
- }
1067
- this._pinnedRows = pinnedRows;
1068
- this._rowActions = rowActions;
1069
- this._onInsertRow = onInsertRow;
1070
- this._onDeleteRows = onDeleteRows;
1071
- this._onDeleteColumn = onDeleteColumn;
1072
- this._onCellUpdate = onCellUpdate;
1073
- this._onRowOrderChange = onRowOrderChange;
1074
- this._onRowAction = onRowAction;
1075
- }
1076
- get id() {
1077
- return this._id;
1078
- }
1079
- get space() {
1080
- return this._space;
1081
- }
1082
- get view() {
1083
- return this._view;
1084
- }
1085
- get projection() {
1086
- return this._projection;
1087
- }
1088
- get rows() {
1089
- return this._sorting.sortedRows;
1090
- }
1091
- get features() {
1092
- return this._features;
1093
- }
1094
- /**
1095
- * @reactive
1096
- */
1097
- get sorting() {
1098
- return this._sorting;
1099
- }
1100
- /**
1101
- * Gets the row data at the specified display index.
1102
- */
1103
- getRowAt(displayIndex) {
1104
- if (displayIndex < 0 || displayIndex >= this._sorting.sortedRows.value.length) {
1105
- return void 0;
1106
- }
1107
- return this._sorting.sortedRows.value[displayIndex];
1108
- }
1109
- get pinnedRows() {
1110
- return this._pinnedRows;
1111
- }
1112
- get columnMeta() {
1113
- invariant(this._columnMeta, void 0, {
1114
- F: __dxlog_file,
1115
- L: 195,
1116
- S: this,
1117
- A: [
1118
- "this._columnMeta",
1119
- ""
1120
- ]
1121
- });
1122
- return this._columnMeta;
1123
- }
1124
- get selection() {
1125
- return this._selection;
1126
- }
1127
- /** @reactive */
1128
- get isViewDirty() {
1129
- return this._sorting.isDirty;
1130
- }
1131
- get rowActions() {
1132
- return this._rowActions;
1133
- }
1134
- //
1135
- // Initialisation
1136
- //
1137
- async _open() {
1138
- this.initializeColumnMeta();
1139
- this.initializeEffects();
1140
- this._selection = new SelectionModel(this._sorting.sortedRows, this._features.selection.mode ?? "multiple", () => this._onRowOrderChange?.());
1141
- await this._selection.open(this._ctx);
1142
- }
1143
- initializeColumnMeta() {
1144
- this._columnMeta = computed3(() => {
1145
- const fields = this._view?.fields ?? [];
1146
- const meta = Object.fromEntries(fields.map((field, index) => [
1147
- index,
1148
- {
1149
- size: field?.size ?? 256,
1150
- resizeable: true
1151
- }
1152
- ]));
1153
- return {
1154
- grid: meta,
1155
- frozenColsStart: {
1156
- 0: {
1157
- size: 30,
1158
- resizeable: false
1159
- }
1160
- },
1161
- frozenColsEnd: {
1162
- 0: {
1163
- size: 40,
1164
- resizeable: false
1165
- }
1166
- }
1167
- };
1168
- });
1169
- }
1170
- initializeEffects() {
1171
- const rowOrderWatcher = effect2(() => {
1172
- touch(this._sorting.sortedRows.value);
1173
- this._onRowOrderChange?.();
1174
- });
1175
- this._ctx.onDispose(rowOrderWatcher);
1176
- const rowEffectManager = effect2(() => {
1177
- const { start, end } = touch(this._visibleRange.value);
1178
- const rowEffects = [];
1179
- for (let row = start.row; row <= end.row; row++) {
1180
- rowEffects.push(effect2(() => {
1181
- const obj = this._sorting.sortedRows.value[row];
1182
- this._view?.fields.forEach((field) => touch(getValue2(obj, field.path)));
1183
- this._onCellUpdate?.({
1184
- row,
1185
- col: start.col,
1186
- plane: "grid"
1187
- });
1188
- }));
1189
- }
1190
- return () => rowEffects.forEach((cleanup) => cleanup());
1191
- });
1192
- this._ctx.onDispose(rowEffectManager);
1193
- }
1194
- /**
1195
- * Updates a cell's value using a transform function.
1196
- * @param {DxGridPlanePosition} position - The position of the cell to update.
1197
- * @param {(value: any) => any} update - A function that takes the current value and returns the updated value.
1198
- */
1199
- updateCellData({ col, row }, update) {
1200
- const dataRow = this._sorting.getDataIndex(row);
1201
- const fields = this._view?.fields ?? [];
1202
- const field = fields[col];
1203
- const value = getValue2(this._rows.value[dataRow], field.path);
1204
- const updatedValue = update(value);
1205
- setValue(this._rows.value[dataRow], field.path, updatedValue);
1206
- }
1207
- //
1208
- // Column Operations
1209
- //
1210
- deleteColumn(fieldId) {
1211
- if (!this._view) {
1212
- return;
1213
- }
1214
- const field = this._view?.fields.find((field2) => field2.id === fieldId);
1215
- if (field && this._onDeleteColumn) {
1216
- this._onDeleteColumn(field.id);
1217
- }
1218
- }
1219
- //
1220
- // Resize
1221
- //
1222
- setColumnWidth(columnIndex, width) {
1223
- const fields = this._view?.fields ?? [];
1224
- if (columnIndex < fields.length) {
1225
- const newWidth = Math.max(0, width);
1226
- const field = fields[columnIndex];
1227
- if (field) {
1228
- field.size = newWidth;
1229
- }
1230
- }
1231
- }
1232
- //
1233
- // Pinning
1234
- //
1235
- // TODO(burdon): Change to setPinned(on/off).
1236
- pinRow(rowIndex, side) {
1237
- this._pinnedRows[side].push(rowIndex);
1238
- }
1239
- unpinRow(rowIndex) {
1240
- this._pinnedRows.top = this._pinnedRows.top.filter((index) => index !== rowIndex);
1241
- this._pinnedRows.bottom = this._pinnedRows.bottom.filter((index) => index !== rowIndex);
1242
- }
1243
- //
1244
- // View operations
1245
- //
1246
- saveView() {
1247
- this._sorting.save();
1248
- }
1249
- };
1250
- var editorTextToCellValue = (props, value) => {
1251
- switch (props.format) {
1252
- case FormatEnum3.Ref: {
1253
- if (isLiveObject(value)) {
1254
- return makeRef(value);
1255
- } else {
1256
- return value;
1257
- }
1258
- }
1259
- case FormatEnum3.SingleSelect: {
1260
- const ids = extractTagIds(value);
1261
- if (ids && ids.length > 0) {
1262
- return ids[0];
1263
- } else {
1264
- return value;
1265
- }
1266
- }
1267
- case FormatEnum3.MultiSelect: {
1268
- const ids = extractTagIds(value);
1269
- return ids || value;
1270
- }
1271
- default: {
1272
- return parseValue({
1273
- type: props.type,
1274
- format: props.format,
1275
- value
1276
- });
1277
- }
1278
- }
1279
- };
1280
-
1281
- // packages/ui/react-ui-table/src/model/modal-controller.ts
1282
- import { signal as signal4 } from "@preact/signals-core";
1283
- import { log } from "@dxos/log";
1284
- var __dxlog_file2 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-table/src/model/modal-controller.ts";
1285
- var ModalController = class {
1286
- constructor() {
1287
- this._state = signal4({
1288
- type: "closed"
1289
- });
1290
- this._triggerRef = {
1291
- current: null
1292
- };
1293
- this.setTrigger = (trigger) => {
1294
- this._triggerRef.current = trigger;
1295
- };
1296
- this.showRowMenu = (rowIndex) => {
1297
- this._state.value = {
1298
- type: "row",
1299
- rowIndex
1300
- };
1301
- };
1302
- this.showColumnMenu = (fieldId) => {
1303
- this._state.value = {
1304
- type: "column",
1305
- fieldId
1306
- };
1307
- };
1308
- this.showColumnCreator = () => {
1309
- this._state.value = {
1310
- type: "columnSettings",
1311
- mode: {
1312
- type: "create"
1313
- }
1314
- };
1315
- };
1316
- this.showReferencePanel = (targetId, schemaId) => {
1317
- this._state.value = {
1318
- type: "refPanel",
1319
- targetId,
1320
- typename: schemaId
1321
- };
1322
- };
1323
- this.openColumnSettings = () => {
1324
- if (this._state.value.type === "column") {
1325
- const fieldId = this._state.value.fieldId;
1326
- requestAnimationFrame(() => {
1327
- this._state.value = {
1328
- type: "columnSettings",
1329
- mode: {
1330
- type: "edit",
1331
- fieldId
1332
- }
1333
- };
1334
- });
1335
- }
1336
- };
1337
- this.openCreateRef = (typename, anchorCell, initialValues, onCreate) => {
1338
- if (anchorCell) {
1339
- this._triggerRef.current = anchorCell;
1340
- this._state.value = {
1341
- type: "createRefPanel",
1342
- typename,
1343
- initialValues,
1344
- onCreate
1345
- };
1346
- } else {
1347
- log.warn("anchor cell not found while creating new ref", void 0, {
1348
- F: __dxlog_file2,
1349
- L: 86,
1350
- S: this,
1351
- C: (f, a) => f(...a)
1352
- });
1353
- }
1354
- };
1355
- this.close = () => {
1356
- this._state.value = {
1357
- type: "closed"
1358
- };
1359
- };
1360
- }
1361
- get state() {
1362
- return this._state;
1363
- }
1364
- get trigger() {
1365
- return this._triggerRef;
1366
- }
1367
- };
1368
-
1369
- // packages/ui/react-ui-table/src/model/table-presentation.ts
1370
- import { signal as signal5 } from "@preact/signals-core";
1371
- import { isNotNullable } from "effect/Predicate";
1372
- import { FormatEnum as FormatEnum4, getObjectDXN, getValue as getValue3, TypeEnum as TypeEnum3 } from "@dxos/echo-schema";
1373
- import { cellClassesForFieldType, formatForDisplay as formatForDisplay2 } from "@dxos/react-ui-form";
1374
- import { toPlaneCellIndex } from "@dxos/react-ui-grid";
1375
- import { mx } from "@dxos/react-ui-theme";
1376
- import { VIEW_FIELD_LIMIT } from "@dxos/schema";
1377
- var TablePresentation = class {
1378
- constructor(model, _visibleRange = signal5({
1379
- start: {
1380
- row: 0,
1381
- col: 0
1382
- },
1383
- end: {
1384
- row: 0,
1385
- col: 0
1386
- }
1387
- })) {
1388
- this.model = model;
1389
- this._visibleRange = _visibleRange;
1390
- }
1391
- getCells(range, plane) {
1392
- let cells;
1393
- switch (plane) {
1394
- case "grid":
1395
- this._visibleRange.value = range;
1396
- cells = this.getMainGridCells(range);
1397
- break;
1398
- case "frozenRowsStart":
1399
- cells = this.getHeaderCells(range);
1400
- break;
1401
- case "frozenColsStart":
1402
- cells = this.getSelectionColumnCells(range);
1403
- break;
1404
- case "frozenColsEnd":
1405
- cells = this.getActionColumnCells(range);
1406
- break;
1407
- case "fixedStartStart":
1408
- cells = this.getSelectAllCell();
1409
- break;
1410
- case "fixedStartEnd":
1411
- cells = this.getNewColumnCell();
1412
- break;
1413
- default:
1414
- cells = {};
1415
- }
1416
- if (plane === "grid" && this.model.features.dataEditable === false) {
1417
- Object.values(cells).forEach((cell) => {
1418
- cell.readonly = "text-select";
1419
- });
1420
- }
1421
- return cells;
1422
- }
1423
- getMainGridCells(range) {
1424
- const cells = {};
1425
- const fields = this.model.view?.fields ?? [];
1426
- const addCell = (obj, field, colIndex, displayIndex) => {
1427
- const { props } = this.model.projection.getFieldProjection(field.id);
1428
- const cell = {
1429
- get value() {
1430
- const value = getValue3(obj, field.path);
1431
- if (value == null) {
1432
- return "";
1433
- }
1434
- if (props.type === "array") {
1435
- return "";
1436
- }
1437
- switch (props.format) {
1438
- case FormatEnum4.Boolean:
1439
- case FormatEnum4.SingleSelect:
1440
- case FormatEnum4.MultiSelect: {
1441
- return "";
1442
- }
1443
- case FormatEnum4.Ref: {
1444
- if (!field.referencePath) {
1445
- return "";
1446
- }
1447
- return getValue3(value.target, field.referencePath);
1448
- }
1449
- default: {
1450
- return formatForDisplay2({
1451
- type: props.type,
1452
- format: props.format,
1453
- value
1454
- });
1455
- }
1456
- }
1457
- }
1458
- };
1459
- const classes = [];
1460
- const formatClasses = cellClassesForFieldType({
1461
- type: props.type,
1462
- format: props.format
1463
- });
1464
- if (formatClasses) {
1465
- classes.push(formatClasses);
1466
- }
1467
- const rowSelectionClasses = cellClassesForRowSelection(this.model.selection.isObjectSelected(obj), this.model.selection.selectionMode);
1468
- if (rowSelectionClasses) {
1469
- classes.push(rowSelectionClasses);
1470
- }
1471
- if (classes.length > 0) {
1472
- cell.className = mx(classes.flat());
1473
- }
1474
- if (props.type === TypeEnum3.Array) {
1475
- const targetArray = getValue3(obj, field.path);
1476
- if (targetArray && Array.isArray(targetArray)) {
1477
- const getLabel = (value) => {
1478
- if (!value) {
1479
- return void 0;
1480
- }
1481
- if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
1482
- return String(value);
1483
- }
1484
- if (Array.isArray(value)) {
1485
- return "Array";
1486
- }
1487
- if (typeof value === "object" && value.name) {
1488
- return value.name;
1489
- }
1490
- if (typeof value === "object" && value.value) {
1491
- return `${value.value}`;
1492
- }
1493
- return "Object";
1494
- };
1495
- const tags = targetArray.map(getLabel).filter(isNotNullable).map((title) => {
1496
- return `<span class="dx-tag rounded-xl" data-hue="neutral">${title}</span>`;
1497
- }).join("");
1498
- cell.accessoryHtml = `<div role='none' class="flex flex-row gap-1 overflow-x-auto">${tags}</div>`;
1499
- }
1500
- }
1501
- if (props.format === FormatEnum4.Ref && props.referenceSchema) {
1502
- const targetObj = getValue3(obj, field.path)?.target;
1503
- if (targetObj) {
1504
- const dxn = getObjectDXN(targetObj)?.toString();
1505
- cell.accessoryHtml = `<dx-ref-tag refId=${dxn} class="dx-button is-6 pli-[3px] pbe-[2px] min-bs-0 absolute inline-end-1"><dx-icon icon="ph--link-simple--regular"/></dx-ref-tag>`;
1506
- }
1507
- }
1508
- if (props.format === FormatEnum4.Boolean) {
1509
- const value = getValue3(obj, field.path);
1510
- cell.accessoryHtml = tableControls.switch.render({
1511
- colIndex,
1512
- rowIndex: displayIndex,
1513
- checked: value ?? false
1514
- });
1515
- cell.readonly = "no-text-select";
1516
- }
1517
- if (props.format === FormatEnum4.SingleSelect) {
1518
- const value = getValue3(obj, field.path);
1519
- const options = this.model.projection.getFieldProjection(field.id).props.options;
1520
- if (options) {
1521
- const option = options.find((o) => o.id === value);
1522
- if (option) {
1523
- cell.accessoryHtml = `<span class="dx-tag" data-hue="${option.color}">${option.title}</span>`;
1524
- }
1525
- }
1526
- }
1527
- if (props.format === FormatEnum4.MultiSelect) {
1528
- const values = getValue3(obj, field.path);
1529
- const options = this.model.projection.getFieldProjection(field.id).props.options;
1530
- if (options && values && values.length > 0) {
1531
- const tags = values.map((value) => {
1532
- const option = options.find((o) => o.id === value);
1533
- if (option) {
1534
- return `<span class="dx-tag" data-hue="${option.color}">${option.title}</span>`;
1535
- }
1536
- return null;
1537
- }).filter(Boolean).join(" ");
1538
- if (tags) {
1539
- cell.accessoryHtml = `<div role='none' class="flex flex-row gap-1">${tags}</div>`;
1540
- }
1541
- }
1542
- }
1543
- const idx = toPlaneCellIndex({
1544
- col: colIndex,
1545
- row: displayIndex
1546
- });
1547
- cells[idx] = cell;
1548
- };
1549
- for (let row = range.start.row; row <= range.end.row && row < this.model.getRowCount(); row++) {
1550
- for (let col = range.start.col; col <= range.end.col && col < fields.length; col++) {
1551
- const field = fields[col];
1552
- if (!field) {
1553
- continue;
1554
- }
1555
- addCell(this.model.rows.value[row], field, col, row);
1556
- }
1557
- }
1558
- return cells;
1559
- }
1560
- getHeaderCells(range) {
1561
- const cells = {};
1562
- const fields = this.model.view?.fields ?? [];
1563
- for (let col = range.start.col; col <= range.end.col && col < fields.length; col++) {
1564
- const { field, props } = this.model.projection.getFieldProjection(fields[col].id);
1565
- const sorting = this.model.sorting?.sorting;
1566
- const direction = sorting?.fieldId === field.id ? sorting.direction : void 0;
1567
- cells[toPlaneCellIndex({
1568
- col,
1569
- row: 0
1570
- })] = {
1571
- // TODO(burdon): Use same logic as form for fallback title.
1572
- value: props.title ?? field.path,
1573
- readonly: true,
1574
- resizeHandle: "col",
1575
- accessoryHtml: `
1576
- ${direction !== void 0 ? tableButtons.sort.render({
1577
- fieldId: field.id,
1578
- direction
1579
- }) : ""}
1580
- ${tableButtons.columnSettings.render({
1581
- fieldId: field.id
1582
- })}
1583
- `,
1584
- className: "!bg-toolbarSurface"
1585
- };
1586
- }
1587
- return cells;
1588
- }
1589
- getSelectionColumnCells(range) {
1590
- const cells = {};
1591
- for (let row = range.start.row; row <= range.end.row && row < this.model.getRowCount(); row++) {
1592
- const isSelected = this.model.selection.isRowIndexSelected(row);
1593
- const classes = cellClassesForRowSelection(isSelected, this.model.selection.selectionMode);
1594
- cells[toPlaneCellIndex({
1595
- col: 0,
1596
- row
1597
- })] = {
1598
- value: "",
1599
- readonly: "no-text-select",
1600
- className: classes ? mx(classes) : void 0,
1601
- accessoryHtml: tableControls.checkbox.render({
1602
- rowIndex: row,
1603
- checked: isSelected
1604
- })
1605
- };
1606
- }
1607
- return cells;
1608
- }
1609
- getActionColumnCells(range) {
1610
- const cells = {};
1611
- for (let row = range.start.row; row <= range.end.row && row < this.model.getRowCount(); row++) {
1612
- const isSelected = this.model.selection.isRowIndexSelected(row);
1613
- const classes = cellClassesForRowSelection(isSelected, this.model.selection.selectionMode);
1614
- cells[toPlaneCellIndex({
1615
- col: 0,
1616
- row
1617
- })] = {
1618
- value: "",
1619
- readonly: true,
1620
- className: classes ? mx(classes) : void 0,
1621
- accessoryHtml: tableButtons.rowMenu.render({
1622
- rowIndex: row
1623
- })
1624
- };
1625
- }
1626
- return cells;
1627
- }
1628
- getSelectAllCell() {
1629
- if (!this.model.features.selection.enabled || this.model.selection.selectionMode === "single") {
1630
- return {
1631
- [toPlaneCellIndex({
1632
- col: 0,
1633
- row: 0
1634
- })]: {
1635
- className: "!bg-toolbarSurface",
1636
- readonly: true,
1637
- value: ""
1638
- }
1639
- };
1640
- }
1641
- return {
1642
- [toPlaneCellIndex({
1643
- col: 0,
1644
- row: 0
1645
- })]: {
1646
- accessoryHtml: tableControls.checkbox.render({
1647
- rowIndex: 0,
1648
- header: true,
1649
- checked: this.model.selection.allRowsSeleted.value
1650
- }),
1651
- className: "!bg-toolbarSurface",
1652
- readonly: true,
1653
- value: ""
1654
- }
1655
- };
1656
- }
1657
- getNewColumnCell() {
1658
- return {
1659
- [toPlaneCellIndex({
1660
- col: 0,
1661
- row: 0
1662
- })]: {
1663
- accessoryHtml: this.model.features.schemaEditable ? tableButtons.addColumn.render({
1664
- disabled: (this.model.view?.fields?.length ?? 0) >= VIEW_FIELD_LIMIT
1665
- }) : void 0,
1666
- className: "!bg-toolbarSurface",
1667
- readonly: true,
1668
- value: ""
1669
- }
1670
- };
1671
- }
1672
- };
1673
- var cellClassesForRowSelection = (selected, selectionMode) => {
1674
- if (!selected) {
1675
- if (selectionMode === "single") {
1676
- return [
1677
- "!cursor-pointer"
1678
- ];
1679
- } else {
1680
- return void 0;
1681
- }
1682
- }
1683
- switch (selectionMode) {
1684
- case "single":
1685
- return [
1686
- "!bg-currentRelated hover:bg-hoverSurface",
1687
- "!cursor-pointer"
1688
- ];
1689
- case "multiple":
1690
- return [
1691
- "!bg-gridCellSelected"
1692
- ];
1693
- }
1694
- };
1695
-
1696
- // packages/ui/react-ui-table/src/components/TableCellEditor/TableCellEditor.tsx
297
+ // src/components/TableCellEditor/TableCellEditor.tsx
1697
298
  import { useSignals as _useSignals7 } from "@preact-signals/safe-react/tracking";
1698
- import React7, { useCallback as useCallback4, useMemo as useMemo4, useRef as useRef2, useState as useState2 } from "react";
1699
- import { FormatEnum as FormatEnum5, TypeEnum as TypeEnum4 } from "@dxos/echo-schema";
1700
- import { invariant as invariant3 } from "@dxos/invariant";
299
+ import React7, { useCallback as useCallback4, useEffect as useEffect3, useMemo as useMemo4, useRef as useRef2, useState as useState3 } from "react";
300
+ import { FormatEnum, TypeEnum } from "@dxos/echo-schema";
301
+ import { invariant as invariant2 } from "@dxos/invariant";
1701
302
  import { useThemeContext } from "@dxos/react-ui";
1702
303
  import { createMarkdownExtensions } from "@dxos/react-ui-editor";
1703
304
  import { cellQuery, editorKeys, parseCellIndex as parseCellIndex2, useGridContext as useGridContext4, GridCellEditor } from "@dxos/react-ui-grid";
1704
- import { tagPickerExtension, createLinks } from "@dxos/react-ui-tag-picker";
305
+ import { tagPicker, createLinks } from "@dxos/react-ui-tag-picker";
1705
306
 
1706
- // packages/ui/react-ui-table/src/components/TableCellEditor/CellValidationMessage.tsx
307
+ // src/components/TableCellEditor/CellValidationMessage.tsx
1707
308
  import { useSignals as _useSignals5 } from "@preact-signals/safe-react/tracking";
1708
309
  import React5 from "react";
1709
310
  import { useGridContext as useGridContext2 } from "@dxos/react-ui-grid";
1710
- var CellValidationMessage = ({ validationError, __gridScope }) => {
311
+ var CellValidationMessage = ({ validationError, variant = "error", __gridScope }) => {
1711
312
  var _effect = _useSignals5();
1712
313
  try {
1713
314
  const { editing, editBox: box } = useGridContext2("GridSheetCellEditor", __gridScope);
1714
315
  if (!editing || !validationError) {
1715
316
  return null;
1716
317
  }
318
+ const bgClass = variant === "error" ? "bg-errorSurface" : "bg-warningSurface";
319
+ const textClass = variant === "error" ? "text-errorSurfaceText" : "text-warningSurfaceText";
1717
320
  return /* @__PURE__ */ React5.createElement("div", {
1718
321
  role: "none",
1719
- className: "absolute bg-errorSurface text-errorSurfaceText rounded-bs-sm text-xs p-1",
322
+ className: `absolute ${bgClass} ${textClass} rounded-bs-sm text-xs p-1`,
1720
323
  style: {
1721
324
  ...{
1722
325
  "--dx-gridCellWidth": `${box?.inlineSize ?? 200}px`
@@ -1732,27 +335,32 @@ var CellValidationMessage = ({ validationError, __gridScope }) => {
1732
335
  }
1733
336
  };
1734
337
 
1735
- // packages/ui/react-ui-table/src/components/TableCellEditor/FormCellEditor.tsx
338
+ // src/components/TableCellEditor/FormCellEditor.tsx
1736
339
  import { useSignals as _useSignals6 } from "@preact-signals/safe-react/tracking";
1737
- import React6, { useCallback as useCallback3, useEffect as useEffect2, useMemo as useMemo3, useRef } from "react";
1738
- import { getSnapshot as getSnapshot2 } from "@dxos/echo-schema";
1739
- import { invariant as invariant2 } from "@dxos/invariant";
340
+ import React6, { useCallback as useCallback3, useEffect as useEffect2, useMemo as useMemo3, useRef, useState as useState2 } from "react";
341
+ import { getSnapshot } from "@dxos/echo-schema";
342
+ import { invariant } from "@dxos/invariant";
1740
343
  import { Popover as Popover3 } from "@dxos/react-ui";
1741
344
  import { Form as Form2 } from "@dxos/react-ui-form";
1742
345
  import { parseCellIndex, useGridContext as useGridContext3 } from "@dxos/react-ui-grid";
1743
346
  import { getDeep, setDeep } from "@dxos/util";
1744
- var __dxlog_file3 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-table/src/components/TableCellEditor/FormCellEditor.tsx";
1745
- var FormCellEditor = ({ fieldProjection, model, schema, __gridScope }) => {
347
+ var __dxlog_file = "/__w/dxos/dxos/packages/ui/react-ui-table/src/components/TableCellEditor/FormCellEditor.tsx";
348
+ var FormCellEditor = ({ fieldProjection, model, schema, onSave, __gridScope }) => {
1746
349
  var _effect = _useSignals6();
1747
350
  try {
1748
- const { editing, setEditing } = useGridContext3("ArrayEditor", __gridScope);
1749
- const cellRef = useRef(null);
351
+ const { editing: contextEditing, setEditing } = useGridContext3("ArrayEditor", __gridScope);
352
+ const [editing, setLocalEditing] = useState2(false);
353
+ const anchorRef = useRef(null);
1750
354
  useEffect2(() => {
1751
- if (editing && editing.cellElement) {
1752
- cellRef.current = editing.cellElement;
355
+ if (contextEditing && contextEditing.cellElement) {
356
+ anchorRef.current = contextEditing.cellElement.querySelector(".dx-grid__cell__content");
357
+ setLocalEditing(true);
358
+ } else {
359
+ anchorRef.current = null;
360
+ setLocalEditing(false);
1753
361
  }
1754
362
  }, [
1755
- editing?.cellElement
363
+ contextEditing
1756
364
  ]);
1757
365
  const narrowedSchema = useMemo3(() => {
1758
366
  if (!schema) {
@@ -1766,12 +374,12 @@ var FormCellEditor = ({ fieldProjection, model, schema, __gridScope }) => {
1766
374
  fieldProjection.field.path
1767
375
  ]);
1768
376
  const originalRow = useMemo3(() => {
1769
- if (model && editing) {
1770
- const cell = parseCellIndex(editing.index);
377
+ if (model && contextEditing) {
378
+ const cell = parseCellIndex(contextEditing.index);
1771
379
  const row = model.getRowAt(cell.row);
1772
- invariant2(row, void 0, {
1773
- F: __dxlog_file3,
1774
- L: 47,
380
+ invariant(row, void 0, {
381
+ F: __dxlog_file,
382
+ L: 55,
1775
383
  S: void 0,
1776
384
  A: [
1777
385
  "row",
@@ -1783,11 +391,11 @@ var FormCellEditor = ({ fieldProjection, model, schema, __gridScope }) => {
1783
391
  return void 0;
1784
392
  }, [
1785
393
  model,
1786
- editing
394
+ contextEditing
1787
395
  ]);
1788
396
  const formValues = useMemo3(() => {
1789
397
  if (originalRow) {
1790
- return getSnapshot2(originalRow);
398
+ return getSnapshot(originalRow);
1791
399
  }
1792
400
  }, [
1793
401
  originalRow
@@ -1801,6 +409,8 @@ var FormCellEditor = ({ fieldProjection, model, schema, __gridScope }) => {
1801
409
  path
1802
410
  ], value);
1803
411
  setEditing(null);
412
+ setLocalEditing(false);
413
+ onSave?.();
1804
414
  }, [
1805
415
  fieldProjection.field.path,
1806
416
  originalRow
@@ -1808,21 +418,21 @@ var FormCellEditor = ({ fieldProjection, model, schema, __gridScope }) => {
1808
418
  const handleOpenChange = useCallback3((nextOpen) => {
1809
419
  if (nextOpen === false) {
1810
420
  setEditing(null);
421
+ onSave?.();
1811
422
  }
1812
- }, [
1813
- setEditing
1814
- ]);
423
+ setLocalEditing(nextOpen);
424
+ }, []);
1815
425
  if (!editing) {
1816
426
  return null;
1817
427
  }
1818
428
  return /* @__PURE__ */ React6.createElement(Popover3.Root, {
1819
- open: editing !== null,
429
+ open: editing,
1820
430
  onOpenChange: handleOpenChange
1821
431
  }, /* @__PURE__ */ React6.createElement(Popover3.VirtualTrigger, {
1822
- virtualRef: cellRef
432
+ virtualRef: anchorRef
1823
433
  }), /* @__PURE__ */ React6.createElement(Popover3.Content, {
1824
434
  tabIndex: -1,
1825
- classNames: "popover-card-width"
435
+ classNames: "popover-card-width density-fine"
1826
436
  }, /* @__PURE__ */ React6.createElement(Popover3.Arrow, null), /* @__PURE__ */ React6.createElement(Popover3.Viewport, null, /* @__PURE__ */ React6.createElement(Form2, {
1827
437
  values: formValues,
1828
438
  schema: narrowedSchema,
@@ -1833,7 +443,7 @@ var FormCellEditor = ({ fieldProjection, model, schema, __gridScope }) => {
1833
443
  }
1834
444
  };
1835
445
 
1836
- // packages/ui/react-ui-table/src/components/TableCellEditor/extension.ts
446
+ // src/components/TableCellEditor/extension.ts
1837
447
  import { autocompletion, pickedCompletion } from "@codemirror/autocomplete";
1838
448
  import { EditorView } from "@codemirror/view";
1839
449
  var completion = ({ debug, onQuery, onMatch }) => {
@@ -1872,15 +482,15 @@ var completion = ({ debug, onQuery, onMatch }) => {
1872
482
  ];
1873
483
  };
1874
484
 
1875
- // packages/ui/react-ui-table/src/components/TableCellEditor/TableCellEditor.tsx
1876
- var __dxlog_file4 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-table/src/components/TableCellEditor/TableCellEditor.tsx";
485
+ // src/components/TableCellEditor/TableCellEditor.tsx
486
+ var __dxlog_file2 = "/__w/dxos/dxos/packages/ui/react-ui-table/src/components/TableCellEditor/TableCellEditor.tsx";
1877
487
  var newValue = Symbol.for("newValue");
1878
488
  var createOption = (text) => ({
1879
489
  [newValue]: true,
1880
490
  text
1881
491
  });
1882
492
  var isCreateOption = (data) => typeof data === "object" && data[newValue];
1883
- var TableValueEditor = ({ model, modals, schema, onEnter, onFocus, onQuery, __gridScope }) => {
493
+ var TableValueEditor = ({ model, modals, schema, onEnter, onFocus, onSave, onQuery, __gridScope }) => {
1884
494
  var _effect = _useSignals7();
1885
495
  try {
1886
496
  const { editing } = useGridContext4("TableValueEditor", __gridScope);
@@ -1889,11 +499,11 @@ var TableValueEditor = ({ model, modals, schema, onEnter, onFocus, onQuery, __gr
1889
499
  return;
1890
500
  }
1891
501
  const { col } = parseCellIndex2(editing.index);
1892
- const field = model.projection.view.fields[col];
502
+ const field = model.projection.fields[col];
1893
503
  const fieldProjection2 = model.projection.getFieldProjection(field.id);
1894
- invariant3(fieldProjection2, void 0, {
1895
- F: __dxlog_file4,
1896
- L: 74,
504
+ invariant2(fieldProjection2, void 0, {
505
+ F: __dxlog_file2,
506
+ L: 76,
1897
507
  S: void 0,
1898
508
  A: [
1899
509
  "fieldProjection",
@@ -1905,12 +515,13 @@ var TableValueEditor = ({ model, modals, schema, onEnter, onFocus, onQuery, __gr
1905
515
  model,
1906
516
  editing
1907
517
  ]);
1908
- if (fieldProjection?.props.type === TypeEnum4.Array) {
518
+ if (fieldProjection?.props.type === TypeEnum.Array || fieldProjection?.props.format === FormatEnum.SingleSelect) {
1909
519
  return /* @__PURE__ */ React7.createElement(FormCellEditor, {
1910
520
  fieldProjection,
1911
521
  model,
1912
522
  schema,
1913
- __gridScope
523
+ __gridScope,
524
+ onSave
1914
525
  });
1915
526
  }
1916
527
  return /* @__PURE__ */ React7.createElement(TableCellEditor, {
@@ -1919,29 +530,36 @@ var TableValueEditor = ({ model, modals, schema, onEnter, onFocus, onQuery, __gr
1919
530
  onEnter,
1920
531
  onFocus,
1921
532
  onQuery,
533
+ onSave,
1922
534
  __gridScope
1923
535
  });
1924
536
  } finally {
1925
537
  _effect.f();
1926
538
  }
1927
539
  };
1928
- var TableCellEditor = ({ model, modals, onEnter, onFocus, onQuery, __gridScope }) => {
540
+ var editorSlots = {
541
+ scroller: {
542
+ className: "!plb-[--dx-grid-cell-editor-padding-block]"
543
+ }
544
+ };
545
+ var TableCellEditor = ({ model, modals, onEnter, onFocus, onQuery, onSave, __gridScope }) => {
1929
546
  var _effect = _useSignals7();
1930
547
  try {
1931
548
  const { id: gridId, editing, setEditing } = useGridContext4("TableCellEditor", __gridScope);
1932
549
  const suppressNextBlur = useRef2(false);
1933
550
  const { themeMode } = useThemeContext();
1934
- const [_validationError, setValidationError] = useState2(null);
551
+ const [_validationError, setValidationError] = useState3(null);
552
+ const [_validationVariant, setValidationVariant] = useState3("error");
1935
553
  const fieldProjection = useMemo4(() => {
1936
554
  if (!model || !editing) {
1937
555
  return;
1938
556
  }
1939
557
  const { col } = parseCellIndex2(editing.index);
1940
- const field = model.projection.view.fields[col];
558
+ const field = model.projection.fields[col];
1941
559
  const fieldProjection2 = model.projection.getFieldProjection(field.id);
1942
- invariant3(fieldProjection2, void 0, {
1943
- F: __dxlog_file4,
1944
- L: 116,
560
+ invariant2(fieldProjection2, void 0, {
561
+ F: __dxlog_file2,
562
+ L: 135,
1945
563
  S: void 0,
1946
564
  A: [
1947
565
  "fieldProjection",
@@ -1953,20 +571,53 @@ var TableCellEditor = ({ model, modals, onEnter, onFocus, onQuery, __gridScope }
1953
571
  model,
1954
572
  editing
1955
573
  ]);
574
+ useEffect3(() => {
575
+ if (!model || !editing || !fieldProjection) {
576
+ setValidationError(null);
577
+ return;
578
+ }
579
+ const cell = parseCellIndex2(editing.index);
580
+ const { row, col } = cell;
581
+ if (model.isDraftCell(cell)) {
582
+ const field = model.projection.fields[col];
583
+ const hasValidationError = model.hasDraftRowValidationError(row, field.path);
584
+ if (hasValidationError) {
585
+ const draftRows = model.draftRows.value;
586
+ if (row >= 0 && row < draftRows.length) {
587
+ const draftRow = draftRows[row];
588
+ const validationError = draftRow.validationErrors?.find((error) => error.path === field.path);
589
+ if (validationError) {
590
+ setValidationError(validationError.message);
591
+ setValidationVariant("warning");
592
+ }
593
+ }
594
+ } else {
595
+ setValidationError(null);
596
+ }
597
+ } else {
598
+ setValidationError(null);
599
+ }
600
+ }, [
601
+ model,
602
+ editing,
603
+ fieldProjection
604
+ ]);
1956
605
  const handleEnter = useCallback4(async (value) => {
1957
606
  if (!model || !editing) {
1958
607
  return;
1959
608
  }
1960
609
  const cell = parseCellIndex2(editing.index);
1961
- const result = await model.validateCellData(cell, value);
1962
- if (result.valid) {
610
+ const validationResult = await model.validateCellData(cell, value);
611
+ if (validationResult.valid) {
1963
612
  setValidationError(null);
1964
613
  model.setCellData(cell, value);
1965
614
  onEnter?.(cell);
1966
615
  onFocus?.();
1967
616
  setEditing(null);
617
+ onSave?.();
1968
618
  } else {
1969
- setValidationError(result.error);
619
+ setValidationError(validationResult.error);
620
+ setValidationVariant("error");
1970
621
  }
1971
622
  }, [
1972
623
  model,
@@ -1997,16 +648,19 @@ var TableCellEditor = ({ model, modals, onEnter, onFocus, onQuery, __gridScope }
1997
648
  setValidationError(null);
1998
649
  model.setCellData(cell, value);
1999
650
  setEditing(null);
651
+ onSave?.();
2000
652
  onEnter?.(cell);
2001
653
  if (event && onFocus) {
2002
654
  onFocus(determineNavigationAxis(event), determineNavigationDelta(event));
2003
655
  }
2004
656
  } else {
2005
657
  setValidationError(result.error);
658
+ setValidationVariant("error");
2006
659
  }
2007
660
  } else {
2008
661
  setValidationError(null);
2009
662
  setEditing(null);
663
+ onSave?.();
2010
664
  if (event && onFocus) {
2011
665
  onFocus(determineNavigationAxis(event), determineNavigationDelta(event));
2012
666
  }
@@ -2017,7 +671,8 @@ var TableCellEditor = ({ model, modals, onEnter, onFocus, onQuery, __gridScope }
2017
671
  onFocus,
2018
672
  onEnter,
2019
673
  fieldProjection,
2020
- setEditing
674
+ setEditing,
675
+ onSave
2021
676
  ]);
2022
677
  const extension = useMemo4(() => {
2023
678
  if (!fieldProjection) {
@@ -2032,15 +687,15 @@ var TableCellEditor = ({ model, modals, onEnter, onFocus, onQuery, __gridScope }
2032
687
  })
2033
688
  ];
2034
689
  const format = fieldProjection.props.format;
2035
- if (format === FormatEnum5.SingleSelect || format === FormatEnum5.MultiSelect) {
690
+ if (format === FormatEnum.SingleSelect || format === FormatEnum.MultiSelect) {
2036
691
  extension2.push(createMarkdownExtensions({
2037
692
  themeMode
2038
693
  }));
2039
694
  const options = fieldProjection.props.options || [];
2040
- const mode = format === FormatEnum5.SingleSelect ? "single-select" : "multi-select";
2041
- extension2.push(tagPickerExtension({
695
+ const mode = format === FormatEnum.SingleSelect ? "single-select" : "multi-select";
696
+ extension2.push(tagPicker({
2042
697
  mode,
2043
- inGrid: true,
698
+ keymap: false,
2044
699
  onSearch: (text, selectedIds) => {
2045
700
  return options.filter((option) => selectedIds.indexOf(option.id) === -1 && (text.length === 0 || option.title.toLowerCase().includes(text.toLowerCase()))).map((option) => ({
2046
701
  id: option.id,
@@ -2064,7 +719,7 @@ var TableCellEditor = ({ model, modals, onEnter, onFocus, onQuery, __gridScope }
2064
719
  }
2065
720
  if (onQuery) {
2066
721
  switch (fieldProjection.props.format) {
2067
- case FormatEnum5.Ref: {
722
+ case FormatEnum.Ref: {
2068
723
  extension2.push([
2069
724
  completion({
2070
725
  onQuery: (text) => onQuery(fieldProjection, text),
@@ -2104,14 +759,14 @@ var TableCellEditor = ({ model, modals, onEnter, onFocus, onQuery, __gridScope }
2104
759
  if (model && editing) {
2105
760
  const cell = parseCellIndex2(editing.index);
2106
761
  const { col } = cell;
2107
- const field = model.projection.view.fields[col];
762
+ const field = model.projection.fields[col];
2108
763
  const fieldProjection2 = model.projection.getFieldProjection(field.id);
2109
- if (fieldProjection2?.props.format === FormatEnum5.SingleSelect || fieldProjection2?.props.format === FormatEnum5.MultiSelect) {
764
+ if (fieldProjection2?.props.format === FormatEnum.SingleSelect || fieldProjection2?.props.format === FormatEnum.MultiSelect) {
2110
765
  const value2 = model.getCellData(cell);
2111
766
  if (value2 !== void 0) {
2112
767
  const options = fieldProjection2.props.options || [];
2113
- if (fieldProjection2.props.format === FormatEnum5.MultiSelect && Array.isArray(value2)) {
2114
- const tagItems = value2.map((id) => {
768
+ if (fieldProjection2.props.format === FormatEnum.MultiSelect) {
769
+ const tagItems = value2.split(",").map((id) => {
2115
770
  const option = options.find((o) => o.id === id);
2116
771
  if (option) {
2117
772
  return {
@@ -2148,11 +803,13 @@ var TableCellEditor = ({ model, modals, onEnter, onFocus, onQuery, __gridScope }
2148
803
  ]);
2149
804
  return /* @__PURE__ */ React7.createElement(React7.Fragment, null, /* @__PURE__ */ React7.createElement(CellValidationMessage, {
2150
805
  validationError: _validationError,
806
+ variant: _validationVariant,
2151
807
  __gridScope
2152
808
  }), /* @__PURE__ */ React7.createElement(GridCellEditor, {
2153
809
  extension,
2154
810
  getCellContent,
2155
- onBlur: handleBlur
811
+ onBlur: handleBlur,
812
+ slots: editorSlots
2156
813
  }));
2157
814
  } finally {
2158
815
  _effect.f();
@@ -2183,14 +840,21 @@ var determineNavigationDelta = ({ key, shift }) => {
2183
840
  return shift ? -1 : 1;
2184
841
  };
2185
842
 
2186
- // packages/ui/react-ui-table/src/components/Table/Table.tsx
2187
- var __dxlog_file5 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-table/src/components/Table/Table.tsx";
2188
- var TableRoot = ({ children, role }) => {
843
+ // src/components/Table/Table.tsx
844
+ var __dxlog_file3 = "/__w/dxos/dxos/packages/ui/react-ui-table/src/components/Table/Table.tsx";
845
+ var TableRoot = ({ children, role = "article" }) => {
2189
846
  var _effect = _useSignals8();
2190
847
  try {
2191
848
  return /* @__PURE__ */ React8.createElement("div", {
2192
849
  role: "none",
2193
- className: mx2("relative !border-separator", role === "section" ? "attention-surface overflow-hidden [&_.dx-grid]:max-is-[--dx-grid-content-inline-size]" : "flex flex-col [&_.dx-grid]:grow [&_.dx-grid]:max-is-[--dx-grid-content-inline-size] [&_.dx-grid]:bs-0 [&_.dx-grid]:max-bs-[--dx-grid-content-block-size]")
850
+ className: mx("relative !border-separator [&_.dx-grid]:max-is-[--dx-grid-content-inline-size] [&_.dx-grid]:max-bs-[--dx-grid-content-block-size]", role === "card--popover" && "popover-card-height", role === "section" && "attention-surface", role === "card--intrinsic" && "[&_.dx-grid]:bs-[--dx-grid-content-block-size]", [
851
+ "card--popover",
852
+ "section",
853
+ "card--extrinsic"
854
+ ].includes(role) && "overflow-hidden", [
855
+ "article",
856
+ "slide"
857
+ ].includes(role) && "flex flex-col [&_.dx-grid]:grow [&_.dx-grid]:bs-0")
2194
858
  }, children);
2195
859
  } finally {
2196
860
  _effect.f();
@@ -2199,24 +863,27 @@ var TableRoot = ({ children, role }) => {
2199
863
  var TableMain = /* @__PURE__ */ forwardRef(({ model, presentation, ignoreAttention, schema, client, onRowClick }, forwardedRef) => {
2200
864
  var _effect = _useSignals8();
2201
865
  try {
2202
- const [dxGrid, setDxGrid] = useState3(null);
866
+ const [dxGrid, setDxGrid] = useState4(null);
2203
867
  const { hasAttention } = useAttention(model?.id ?? "table");
2204
868
  const { t } = useTranslation3(translationKey);
2205
869
  const modals = useMemo5(() => new ModalController(), []);
870
+ const draftRowCount = model?.getDraftRowCount() ?? 0;
2206
871
  const frozen = useMemo5(() => {
2207
872
  const noActionColumn = model?.features.dataEditable === false && model?.features.schemaEditable === false && model.rowActions.length === 0;
2208
873
  return {
2209
874
  frozenRowsStart: 1,
875
+ frozenRowsEnd: draftRowCount,
2210
876
  frozenColsStart: model?.features.selection.enabled ? 1 : 0,
2211
877
  frozenColsEnd: noActionColumn ? 0 : 1
2212
878
  };
2213
879
  }, [
2214
- model
880
+ model,
881
+ draftRowCount
2215
882
  ]);
2216
883
  const getCells = useCallback5((range, plane) => presentation?.getCells(range, plane) ?? {}, [
2217
884
  presentation
2218
885
  ]);
2219
- useEffect3(() => {
886
+ useEffect4(() => {
2220
887
  if (!presentation || !dxGrid) {
2221
888
  return;
2222
889
  }
@@ -2233,7 +900,7 @@ var TableMain = /* @__PURE__ */ forwardRef(({ model, presentation, ignoreAttenti
2233
900
  return {
2234
901
  update: (cell) => {
2235
902
  if (cell) {
2236
- dxGrid.updateIfWithinBounds(cell);
903
+ dxGrid.updateIfWithinBounds(cell, true);
2237
904
  } else {
2238
905
  dxGrid.updateCells(true);
2239
906
  dxGrid.requestUpdate();
@@ -2245,7 +912,7 @@ var TableMain = /* @__PURE__ */ forwardRef(({ model, presentation, ignoreAttenti
2245
912
  dxGrid
2246
913
  ]);
2247
914
  const handleGridClick = useCallback5((event) => {
2248
- const rowIndex = safeParseInt(event.target.ariaRowIndex ?? "");
915
+ const rowIndex = safeParseInt(event.target.closest("[aria-rowindex]")?.ariaRowIndex ?? "");
2249
916
  if (rowIndex != null) {
2250
917
  if (onRowClick) {
2251
918
  const row = model?.getRowAt(rowIndex);
@@ -2284,6 +951,17 @@ var TableMain = /* @__PURE__ */ forwardRef(({ model, presentation, ignoreAttenti
2284
951
  model?.sorting?.toggleSort(data.fieldId);
2285
952
  break;
2286
953
  }
954
+ case "saveDraftRow": {
955
+ if (model) {
956
+ const didCommitSuccessfully = model.commitDraftRow(data.rowIndex);
957
+ if (dxGrid && didCommitSuccessfully) {
958
+ requestAnimationFrame(() => {
959
+ dxGrid.scrollToEndRow();
960
+ });
961
+ }
962
+ }
963
+ break;
964
+ }
2287
965
  }
2288
966
  return;
2289
967
  }
@@ -2317,7 +995,8 @@ var TableMain = /* @__PURE__ */ forwardRef(({ model, presentation, ignoreAttenti
2317
995
  }
2318
996
  }, [
2319
997
  model,
2320
- modals
998
+ modals,
999
+ dxGrid
2321
1000
  ]);
2322
1001
  const handleFocus = useCallback5((increment, delta) => {
2323
1002
  if (dxGrid) {
@@ -2331,7 +1010,7 @@ var TableMain = /* @__PURE__ */ forwardRef(({ model, presentation, ignoreAttenti
2331
1010
  return;
2332
1011
  }
2333
1012
  if (model && cell.row === model.getRowCount() - 1) {
2334
- model.insertRow(cell.row);
1013
+ model.insertRow();
2335
1014
  if (dxGrid) {
2336
1015
  requestAnimationFrame(() => {
2337
1016
  dxGrid?.scrollToRow(cell.row + 1);
@@ -2388,10 +1067,10 @@ var TableMain = /* @__PURE__ */ forwardRef(({ model, presentation, ignoreAttenti
2388
1067
  ]);
2389
1068
  const handleQuery = useCallback5(async ({ field, props }, text) => {
2390
1069
  if (model && props.referenceSchema && field.referencePath) {
2391
- const space = model.space;
2392
- invariant4(space, void 0, {
2393
- F: __dxlog_file5,
2394
- L: 311,
1070
+ const space = getSpace2(model.view);
1071
+ invariant3(space, void 0, {
1072
+ F: __dxlog_file3,
1073
+ L: 325,
2395
1074
  S: void 0,
2396
1075
  A: [
2397
1076
  "space",
@@ -2408,7 +1087,7 @@ var TableMain = /* @__PURE__ */ forwardRef(({ model, presentation, ignoreAttenti
2408
1087
  if (schema2) {
2409
1088
  const { objects } = await space.db.query(Filter.type(schema2)).run();
2410
1089
  const options = objects.map((obj) => {
2411
- const value = getValue4(obj, field.referencePath);
1090
+ const value = getValue(obj, field.referencePath);
2412
1091
  if (!value || typeof value !== "string") {
2413
1092
  return void 0;
2414
1093
  }
@@ -2434,6 +1113,11 @@ var TableMain = /* @__PURE__ */ forwardRef(({ model, presentation, ignoreAttenti
2434
1113
  client,
2435
1114
  t
2436
1115
  ]);
1116
+ const handleSave = useCallback5(() => {
1117
+ dxGrid?.updateCells(true);
1118
+ }, [
1119
+ dxGrid
1120
+ ]);
2437
1121
  if (!model || !modals) {
2438
1122
  return /* @__PURE__ */ React8.createElement("span", {
2439
1123
  role: "none",
@@ -2448,14 +1132,14 @@ var TableMain = /* @__PURE__ */ forwardRef(({ model, presentation, ignoreAttenti
2448
1132
  schema,
2449
1133
  onEnter: handleEnter,
2450
1134
  onFocus: handleFocus,
2451
- onQuery: handleQuery
1135
+ onQuery: handleQuery,
1136
+ onSave: handleSave
2452
1137
  }), /* @__PURE__ */ React8.createElement(Grid.Content, {
2453
- className: mx2("[--dx-grid-base:var(--baseSurface)]", gridSeparatorInlineEnd, gridSeparatorBlockEnd),
1138
+ className: mx("[--dx-grid-base:var(--baseSurface)]", gridSeparatorInlineEnd, gridSeparatorBlockEnd),
2454
1139
  frozen,
2455
- // getCells={getCells}
2456
1140
  columns: model.columnMeta.value,
2457
1141
  limitRows: model.getRowCount() ?? 0,
2458
- limitColumns: model.view?.fields?.length ?? 0,
1142
+ limitColumns: model.projection.fields.length,
2459
1143
  overscroll: "trap",
2460
1144
  onAxisResize: handleAxisResize,
2461
1145
  onClick: handleGridClick,
@@ -2485,116 +1169,33 @@ var Table = {
2485
1169
  Main: TableMain
2486
1170
  };
2487
1171
 
2488
- // packages/ui/react-ui-table/src/components/Table/DynamicTable.tsx
2489
- import { useSignals as _useSignals10 } from "@preact-signals/safe-react/tracking";
1172
+ // src/components/Table/DynamicTable.tsx
1173
+ import { useSignals as _useSignals9 } from "@preact-signals/safe-react/tracking";
2490
1174
  import React9, { useRef as useRef3, useMemo as useMemo6, useCallback as useCallback6 } from "react";
2491
1175
  import { useDefaultValue } from "@dxos/react-ui";
2492
- import { mx as mx3 } from "@dxos/react-ui-theme";
2493
-
2494
- // packages/ui/react-ui-table/src/hooks/useTableModel.ts
2495
- import { useSignals as _useSignals9 } from "@preact-signals/safe-react/tracking";
2496
- import { effect as effect3 } from "@preact/signals-core";
2497
- import orderBy2 from "lodash.orderby";
2498
- import { useEffect as useEffect4, useState as useState4 } from "react";
2499
- import { fullyQualifiedId, getSpace } from "@dxos/react-client/echo";
2500
- import { useSelectionActions } from "@dxos/react-ui-attention";
2501
- import { isNonNullable } from "@dxos/util";
2502
- var useTableModel = ({ table, projection, rows, rowActions, features, onSelectionChanged, onRowAction, ...props }) => {
1176
+ import { mx as mx2 } from "@dxos/react-ui-theme";
1177
+ var DynamicTable = ({ classNames, name = "example.com/dynamic-table", rows, properties, jsonSchema: _jsonSchema, schema, rowActions, onRowClick, onRowAction, ...props }) => {
2503
1178
  var _effect = _useSignals9();
2504
1179
  try {
2505
- const [model, setModel] = useState4();
2506
- useEffect4(() => {
2507
- if (!table || !projection) {
2508
- return;
2509
- }
2510
- let model2;
2511
- const t = setTimeout(async () => {
2512
- model2 = new TableModel({
2513
- id: fullyQualifiedId(table),
2514
- space: getSpace(table),
2515
- view: table.view?.target,
2516
- projection,
2517
- features,
2518
- rowActions,
2519
- onRowAction,
2520
- ...props
2521
- });
2522
- await model2.open();
2523
- setModel(model2);
2524
- });
2525
- return () => {
2526
- clearTimeout(t);
2527
- void model2?.close();
2528
- };
2529
- }, [
2530
- table,
2531
- projection,
2532
- table?.view?.target,
2533
- features,
2534
- rowActions
2535
- ]);
2536
- useEffect4(() => {
2537
- if (rows) {
2538
- const sortedRows = orderBy2(rows, [
2539
- (row) => String(row.id)
2540
- ], [
2541
- "asc"
2542
- ]);
2543
- model?.setRows(sortedRows);
2544
- }
2545
- }, [
2546
- model,
2547
- rows
2548
- ]);
2549
- const { multiSelect, clear } = useSelectionActions([
2550
- table?.id,
2551
- table?.view?.target?.query.typename
2552
- ].filter(isNonNullable));
2553
- useEffect4(() => {
2554
- if (!model) {
2555
- return;
2556
- }
2557
- const unsubscribe = effect3(() => {
2558
- const selectedItems = [
2559
- ...model.selection.selection.value
2560
- ];
2561
- multiSelect(selectedItems);
2562
- onSelectionChanged?.(selectedItems);
2563
- });
2564
- return () => {
2565
- clear();
2566
- unsubscribe();
2567
- };
2568
- }, [
2569
- model,
2570
- onSelectionChanged
2571
- ]);
2572
- return model;
2573
- } finally {
2574
- _effect.f();
2575
- }
2576
- };
2577
-
2578
- // packages/ui/react-ui-table/src/components/Table/DynamicTable.tsx
2579
- var DynamicTable = ({ classNames, name = "example.com/dynamic-table", rows, properties, jsonSchema, schema, rowActions, onRowClick, onRowAction, ...props }) => {
2580
- var _effect = _useSignals10();
2581
- try {
2582
- const { table, projection } = useMemo6(() => {
2583
- const props2 = getBaseSchema({
2584
- typename: name,
2585
- properties,
2586
- jsonSchema,
2587
- schema
2588
- });
2589
- return makeDynamicTable({
2590
- ...props2,
2591
- properties
2592
- });
2593
- }, [
1180
+ const { typename, jsonSchema } = useMemo6(() => getBaseSchema({
1181
+ typename: name,
1182
+ properties,
1183
+ jsonSchema: _jsonSchema,
1184
+ schema
1185
+ }), [
2594
1186
  name,
2595
1187
  properties,
2596
- schema,
2597
- jsonSchema
1188
+ _jsonSchema,
1189
+ schema
1190
+ ]);
1191
+ const { projection, view } = useMemo6(() => makeDynamicTable({
1192
+ typename,
1193
+ jsonSchema,
1194
+ properties
1195
+ }), [
1196
+ typename,
1197
+ jsonSchema,
1198
+ properties
2598
1199
  ]);
2599
1200
  const tableRef = useRef3(null);
2600
1201
  const handleCellUpdate = useCallback6((cell) => {
@@ -2610,8 +1211,9 @@ var DynamicTable = ({ classNames, name = "example.com/dynamic-table", rows, prop
2610
1211
  dataEditable: false
2611
1212
  }));
2612
1213
  const model = useTableModel({
2613
- table,
2614
1214
  rows,
1215
+ view,
1216
+ schema: jsonSchema,
2615
1217
  projection,
2616
1218
  features,
2617
1219
  rowActions,
@@ -2628,7 +1230,7 @@ var DynamicTable = ({ classNames, name = "example.com/dynamic-table", rows, prop
2628
1230
  ]);
2629
1231
  return /* @__PURE__ */ React9.createElement("div", {
2630
1232
  role: "none",
2631
- className: mx3("is-full bs-full grow grid", classNames)
1233
+ className: mx2("is-full bs-full grow grid", classNames)
2632
1234
  }, /* @__PURE__ */ React9.createElement("div", {
2633
1235
  role: "none",
2634
1236
  className: "grid min-bs-0 overflow-hidden"
@@ -2644,11 +1246,11 @@ var DynamicTable = ({ classNames, name = "example.com/dynamic-table", rows, prop
2644
1246
  }
2645
1247
  };
2646
1248
 
2647
- // packages/ui/react-ui-table/src/components/TableToolbar/TableToolbar.tsx
2648
- import { useSignals as _useSignals11 } from "@preact-signals/safe-react/tracking";
1249
+ // src/components/TableToolbar/TableToolbar.tsx
1250
+ import { useSignals as _useSignals10 } from "@preact-signals/safe-react/tracking";
2649
1251
  import { Rx } from "@effect-rx/rx-react";
2650
1252
  import React10, { useMemo as useMemo7 } from "react";
2651
- import { live as live3 } from "@dxos/live-object";
1253
+ import { live as live2 } from "@dxos/live-object";
2652
1254
  import { createGapSeparator, createMenuAction, MenuProvider, ToolbarMenu, useMenuActions } from "@dxos/react-ui-menu";
2653
1255
  import { rxFromSignal } from "@dxos/react-ui-menu";
2654
1256
  var createTableToolbarActions = ({ state, onAdd, onSave, customActions }) => Rx.make((get) => {
@@ -2697,9 +1299,9 @@ var createTableToolbarActions = ({ state, onAdd, onSave, customActions }) => Rx.
2697
1299
  };
2698
1300
  });
2699
1301
  var TableToolbar = ({ classNames, viewDirty, attendableId, onAdd, onSave, customActions }) => {
2700
- var _effect = _useSignals11();
1302
+ var _effect = _useSignals10();
2701
1303
  try {
2702
- const state = useMemo7(() => live3({
1304
+ const state = useMemo7(() => live2({
2703
1305
  viewDirty
2704
1306
  }), []);
2705
1307
  const actionsCreator = useMemo7(() => createTableToolbarActions({
@@ -2734,18 +1336,17 @@ export {
2734
1336
  Table,
2735
1337
  TableModel,
2736
1338
  TablePresentation,
2737
- TableSchema,
2738
1339
  TableToolbar,
2739
- TableType,
2740
1340
  cellClassesForRowSelection,
1341
+ createTable,
2741
1342
  getBaseSchema,
2742
- initializeTable,
2743
1343
  makeDynamicTable,
2744
1344
  narrowSchema,
2745
1345
  tableButtons,
2746
1346
  tableControls,
2747
1347
  touch,
2748
- translations_default as translations,
1348
+ translations,
1349
+ useAddRow,
2749
1350
  useTableModel
2750
1351
  };
2751
1352
  //# sourceMappingURL=index.mjs.map