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