@dxos/react-ui-table 0.7.2-staging.6d26b2a → 0.7.3-main.2dd075e

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 (75) hide show
  1. package/dist/lib/browser/{chunk-EWGUNGJC.mjs → chunk-IYCSJDMB.mjs} +5 -3
  2. package/dist/lib/browser/chunk-IYCSJDMB.mjs.map +7 -0
  3. package/dist/lib/browser/index.mjs +461 -237
  4. package/dist/lib/browser/index.mjs.map +4 -4
  5. package/dist/lib/browser/meta.json +1 -1
  6. package/dist/lib/browser/types/index.mjs +3 -1
  7. package/dist/lib/node/{chunk-A2N7XWW6.cjs → chunk-MHBMVCFZ.cjs} +8 -5
  8. package/dist/lib/node/chunk-MHBMVCFZ.cjs.map +7 -0
  9. package/dist/lib/node/index.cjs +471 -253
  10. package/dist/lib/node/index.cjs.map +4 -4
  11. package/dist/lib/node/meta.json +1 -1
  12. package/dist/lib/node/types/index.cjs +4 -2
  13. package/dist/lib/node/types/index.cjs.map +2 -2
  14. package/dist/lib/node-esm/{chunk-SABDOZ6I.mjs → chunk-BMWGPXPL.mjs} +5 -3
  15. package/dist/lib/node-esm/chunk-BMWGPXPL.mjs.map +7 -0
  16. package/dist/lib/node-esm/index.mjs +461 -237
  17. package/dist/lib/node-esm/index.mjs.map +4 -4
  18. package/dist/lib/node-esm/meta.json +1 -1
  19. package/dist/lib/node-esm/types/index.mjs +3 -1
  20. package/dist/types/src/_deprecated/components/Table/Table.stories.d.ts.map +1 -1
  21. package/dist/types/src/components/Table/ColumnActionsMenu.d.ts.map +1 -1
  22. package/dist/types/src/components/Table/ColumnSettings.d.ts +2 -1
  23. package/dist/types/src/components/Table/ColumnSettings.d.ts.map +1 -1
  24. package/dist/types/src/components/Table/CreateRefPanel.d.ts +8 -0
  25. package/dist/types/src/components/Table/CreateRefPanel.d.ts.map +1 -0
  26. package/dist/types/src/components/Table/RefPanel.d.ts +8 -0
  27. package/dist/types/src/components/Table/RefPanel.d.ts.map +1 -0
  28. package/dist/types/src/components/Table/RowActionsMenu.d.ts.map +1 -1
  29. package/dist/types/src/components/Table/Table.d.ts +2 -2
  30. package/dist/types/src/components/Table/Table.d.ts.map +1 -1
  31. package/dist/types/src/components/TableCellEditor/TableCellEditor.d.ts +16 -7
  32. package/dist/types/src/components/TableCellEditor/TableCellEditor.d.ts.map +1 -1
  33. package/dist/types/src/components/TableCellEditor/extension.d.ts +2 -1
  34. package/dist/types/src/components/TableCellEditor/extension.d.ts.map +1 -1
  35. package/dist/types/src/components/testing.d.ts +1 -1
  36. package/dist/types/src/components/testing.d.ts.map +1 -1
  37. package/dist/types/src/model/modal-controller.d.ts +11 -0
  38. package/dist/types/src/model/modal-controller.d.ts.map +1 -1
  39. package/dist/types/src/model/table-model.d.ts +4 -5
  40. package/dist/types/src/model/table-model.d.ts.map +1 -1
  41. package/dist/types/src/translations.d.ts +1 -0
  42. package/dist/types/src/translations.d.ts.map +1 -1
  43. package/dist/types/src/types/table.d.ts +57 -2
  44. package/dist/types/src/types/table.d.ts.map +1 -1
  45. package/dist/types/src/util/index.d.ts +0 -1
  46. package/dist/types/src/util/index.d.ts.map +1 -1
  47. package/dist/types/src/util/table-buttons.d.ts +8 -0
  48. package/dist/types/src/util/table-buttons.d.ts.map +1 -1
  49. package/package.json +29 -28
  50. package/src/_deprecated/components/Table/Table.stories.tsx +1 -1
  51. package/src/components/Table/ColumnActionsMenu.tsx +0 -1
  52. package/src/components/Table/ColumnSettings.tsx +7 -4
  53. package/src/components/Table/CreateRefPanel.tsx +83 -0
  54. package/src/components/Table/RefPanel.tsx +52 -0
  55. package/src/components/Table/RowActionsMenu.tsx +1 -2
  56. package/src/components/Table/Table.stories.tsx +2 -2
  57. package/src/components/Table/Table.tsx +60 -33
  58. package/src/components/TableCellEditor/TableCellEditor.stories.tsx +2 -2
  59. package/src/components/TableCellEditor/TableCellEditor.tsx +72 -23
  60. package/src/components/TableCellEditor/extension.ts +3 -4
  61. package/src/components/testing.ts +2 -1
  62. package/src/model/modal-controller.ts +43 -0
  63. package/src/model/table-model.test.ts +5 -3
  64. package/src/model/table-model.ts +34 -22
  65. package/src/playwright/smoke.spec.ts +0 -4
  66. package/src/translations.ts +1 -0
  67. package/src/types/table.ts +5 -5
  68. package/src/util/index.ts +0 -1
  69. package/src/util/table-buttons.ts +18 -1
  70. package/dist/lib/browser/chunk-EWGUNGJC.mjs.map +0 -7
  71. package/dist/lib/node/chunk-A2N7XWW6.cjs.map +0 -7
  72. package/dist/lib/node-esm/chunk-SABDOZ6I.mjs.map +0 -7
  73. package/dist/types/src/util/grid.d.ts +0 -14
  74. package/dist/types/src/util/grid.d.ts.map +0 -1
  75. package/src/util/grid.ts +0 -23
@@ -1,6 +1,7 @@
1
1
  import {
2
+ TableSchema,
2
3
  TableType
3
- } from "./chunk-EWGUNGJC.mjs";
4
+ } from "./chunk-IYCSJDMB.mjs";
4
5
 
5
6
  // packages/ui/react-ui-table/src/translations.ts
6
7
  var translationKey = "table";
@@ -26,17 +27,19 @@ var translations_default = [
26
27
  "delete row label": "Delete row",
27
28
  "bulk delete row label": "Delete selected rows",
28
29
  "column deleted label": "Column deleted",
29
- "new column button label": "Create column"
30
+ "new column button label": "Create column",
31
+ "create new object label": "Create new object \u201C{{text}}\u201D"
30
32
  }
31
33
  }
32
34
  }
33
35
  ];
34
36
 
35
37
  // packages/ui/react-ui-table/src/components/Table/Table.tsx
36
- import React5, { forwardRef, useCallback as useCallback3, useImperativeHandle, useState as useState2 } from "react";
38
+ import React7, { forwardRef, useCallback as useCallback4, useImperativeHandle, useState as useState2 } from "react";
37
39
  import { getValue } from "@dxos/echo-schema";
38
40
  import { invariant as invariant2 } from "@dxos/invariant";
39
- import { Filter, getSpace as getSpace2, fullyQualifiedId } from "@dxos/react-client/echo";
41
+ import { Filter, getSpace as getSpace4, fullyQualifiedId } from "@dxos/react-client/echo";
42
+ import { useTranslation as useTranslation3 } from "@dxos/react-ui";
40
43
  import { useAttention } from "@dxos/react-ui-attention";
41
44
  import { Grid, closestCell } from "@dxos/react-ui-grid";
42
45
  import { mx } from "@dxos/react-ui-theme";
@@ -82,13 +85,16 @@ import React2, { useCallback, useEffect, useMemo, useState } from "react";
82
85
  import { getSpace } from "@dxos/react-client/echo";
83
86
  import { DropdownMenu as DropdownMenu2 } from "@dxos/react-ui";
84
87
  import { FieldEditor } from "@dxos/react-ui-form";
85
- var ColumnSettings = ({ model }) => {
88
+ var ColumnSettings = ({ model, onNewColumn }) => {
86
89
  const [newField, setNewField] = useState();
87
90
  const state = model?.modalController.state.value;
88
91
  const space = getSpace(model?.table);
89
92
  useEffect(() => {
90
93
  if (state?.type === "columnSettings" && state.mode.type === "create" && model?.projection) {
91
94
  setNewField(model.projection.createFieldProjection());
95
+ requestAnimationFrame(() => {
96
+ onNewColumn();
97
+ });
92
98
  } else {
93
99
  setNewField(void 0);
94
100
  }
@@ -109,7 +115,7 @@ var ColumnSettings = ({ model }) => {
109
115
  state
110
116
  ]);
111
117
  const field = existingField ?? newField;
112
- const handleClose = useCallback(() => {
118
+ const handleSave = useCallback(() => {
113
119
  model?.modalController.close();
114
120
  }, [
115
121
  model?.modalController
@@ -138,43 +144,152 @@ var ColumnSettings = ({ model }) => {
138
144
  projection: model.projection,
139
145
  field,
140
146
  registry: space?.db.schemaRegistry,
141
- onClose: handleClose,
147
+ onSave: handleSave,
142
148
  onCancel: handleCancel
143
149
  })), /* @__PURE__ */ React2.createElement(DropdownMenu2.Arrow, null))));
144
150
  };
145
151
 
152
+ // packages/ui/react-ui-table/src/components/Table/CreateRefPanel.tsx
153
+ import React3, { useCallback as useCallback2, useMemo as useMemo2 } from "react";
154
+ import { S } from "@dxos/echo-schema";
155
+ import { create, getSpace as getSpace2 } from "@dxos/react-client/echo";
156
+ import { Popover } from "@dxos/react-ui";
157
+ import { Form } from "@dxos/react-ui-form";
158
+ import { useGridContext } from "@dxos/react-ui-grid";
159
+ var CreateRefPanel = ({ model, __gridScope }) => {
160
+ const { id: gridId } = useGridContext("TableCellEditor", __gridScope);
161
+ const space = getSpace2(model?.table);
162
+ const state = model?.modalController.state.value;
163
+ const schema = useMemo2(() => {
164
+ if (!space || state?.type !== "createRefPanel") {
165
+ return;
166
+ }
167
+ const schema2 = space.db.schemaRegistry.getSchema(state.typename)?.schema;
168
+ if (schema2) {
169
+ const omit = S.omit("id");
170
+ return omit(schema2);
171
+ }
172
+ }, [
173
+ space,
174
+ state
175
+ ]);
176
+ const handleSave = useCallback2((values) => {
177
+ if (!model || !space || state?.type !== "createRefPanel") {
178
+ return;
179
+ }
180
+ const schema2 = space.db.schemaRegistry.getSchema(state.typename)?.schema;
181
+ if (schema2) {
182
+ const obj = space.db.add(create(schema2, values));
183
+ state.onCreate?.(obj);
184
+ }
185
+ void model.modalController.close();
186
+ }, [
187
+ model?.modalController,
188
+ space,
189
+ state
190
+ ]);
191
+ const handleCancel = useCallback2(() => {
192
+ if (model) {
193
+ model.modalController.close();
194
+ }
195
+ }, [
196
+ model?.modalController
197
+ ]);
198
+ if (!model?.table?.view || !model.projection) {
199
+ return null;
200
+ }
201
+ return /* @__PURE__ */ React3.createElement(Popover.Root, {
202
+ modal: false,
203
+ open: state?.type === "createRefPanel" && !!schema,
204
+ onOpenChange: (nextOpen) => {
205
+ if (model && !nextOpen) {
206
+ return model.modalController.close();
207
+ }
208
+ }
209
+ }, /* @__PURE__ */ React3.createElement(Popover.VirtualTrigger, {
210
+ virtualRef: model.modalController.trigger
211
+ }), /* @__PURE__ */ React3.createElement(Popover.Portal, null, /* @__PURE__ */ React3.createElement(Popover.Content, {
212
+ classNames: "md:is-64",
213
+ "data-grid": gridId
214
+ }, state?.type === "createRefPanel" && schema && /* @__PURE__ */ React3.createElement(Form, {
215
+ schema,
216
+ values: state.initialValues ?? {},
217
+ onSave: handleSave,
218
+ onCancel: handleCancel
219
+ }), /* @__PURE__ */ React3.createElement(Popover.Arrow, null))));
220
+ };
221
+
222
+ // packages/ui/react-ui-table/src/components/Table/RefPanel.tsx
223
+ import React4 from "react";
224
+ import { getSpace as getSpace3 } from "@dxos/react-client/echo";
225
+ import { Popover as Popover2 } from "@dxos/react-ui";
226
+ import { Form as Form2 } from "@dxos/react-ui-form";
227
+ var getRefTargetObj = (space, id) => {
228
+ if (space && id) {
229
+ return space?.db.getObjectById(id);
230
+ } else {
231
+ return void 0;
232
+ }
233
+ };
234
+ var RefPanel = ({ model }) => {
235
+ const state = model?.modalController.state.value;
236
+ const space = getSpace3(model?.table);
237
+ const targetObj = getRefTargetObj(space, state?.type === "refPanel" ? state.targetId : void 0);
238
+ const schema = space && state?.type === "refPanel" ? space.db.schemaRegistry.getSchema(state.typename) : void 0;
239
+ if (!model?.table?.view || !model.projection) {
240
+ return null;
241
+ }
242
+ return /* @__PURE__ */ React4.createElement(Popover2.Root, {
243
+ modal: false,
244
+ open: state?.type === "refPanel" && !!targetObj && !!schema,
245
+ onOpenChange: (nextOpen) => {
246
+ if (model && !nextOpen) {
247
+ return model.modalController.close();
248
+ }
249
+ }
250
+ }, /* @__PURE__ */ React4.createElement(Popover2.VirtualTrigger, {
251
+ virtualRef: model.modalController.trigger
252
+ }), /* @__PURE__ */ React4.createElement(Popover2.Portal, null, /* @__PURE__ */ React4.createElement(Popover2.Content, {
253
+ classNames: "md:is-64"
254
+ }, targetObj && schema && /* @__PURE__ */ React4.createElement(Form2, {
255
+ readonly: true,
256
+ values: targetObj,
257
+ schema
258
+ }), /* @__PURE__ */ React4.createElement(Popover2.Arrow, null))));
259
+ };
260
+
146
261
  // packages/ui/react-ui-table/src/components/Table/RowActionsMenu.tsx
147
- import React3 from "react";
262
+ import React5 from "react";
148
263
  import { DropdownMenu as DropdownMenu3, useTranslation as useTranslation2 } from "@dxos/react-ui";
149
264
  var RowActionsMenu = ({ model }) => {
150
265
  const { t } = useTranslation2(translationKey);
151
- const state = model.modalController.state.value;
152
266
  const hasSelection = model.selection.hasSelection.value;
267
+ const state = model.modalController.state.value;
153
268
  if (state?.type !== "row") {
154
269
  return null;
155
270
  }
156
- return /* @__PURE__ */ React3.createElement(DropdownMenu3.Root, {
271
+ return /* @__PURE__ */ React5.createElement(DropdownMenu3.Root, {
157
272
  modal: false,
158
273
  open: true,
159
274
  onOpenChange: model.modalController.close
160
- }, /* @__PURE__ */ React3.createElement(DropdownMenu3.VirtualTrigger, {
275
+ }, /* @__PURE__ */ React5.createElement(DropdownMenu3.VirtualTrigger, {
161
276
  virtualRef: model.modalController.trigger
162
- }), /* @__PURE__ */ React3.createElement(DropdownMenu3.Content, null, /* @__PURE__ */ React3.createElement(DropdownMenu3.Viewport, null, /* @__PURE__ */ React3.createElement(DropdownMenu3.Item, {
277
+ }), /* @__PURE__ */ React5.createElement(DropdownMenu3.Content, null, /* @__PURE__ */ React5.createElement(DropdownMenu3.Viewport, null, /* @__PURE__ */ React5.createElement(DropdownMenu3.Item, {
163
278
  "data-testid": "row-menu-delete",
164
279
  onClick: () => model.deleteRow(state.rowIndex)
165
- }, t(hasSelection ? "bulk delete row label" : "delete row label"))), /* @__PURE__ */ React3.createElement(DropdownMenu3.Arrow, null)));
280
+ }, t(hasSelection ? "bulk delete row label" : "delete row label"))), /* @__PURE__ */ React5.createElement(DropdownMenu3.Arrow, null)));
166
281
  };
167
282
 
168
283
  // packages/ui/react-ui-table/src/components/TableCellEditor/TableCellEditor.tsx
169
- import React4, { useCallback as useCallback2, useMemo as useMemo2 } from "react";
170
- import { FormatEnum as FormatEnum2 } from "@dxos/echo-schema";
284
+ import React6, { useCallback as useCallback3, useMemo as useMemo3, useRef } from "react";
285
+ import { FormatEnum } from "@dxos/echo-schema";
171
286
  import { invariant } from "@dxos/invariant";
172
- import { editorKeys, GridCellEditor, useGridContext } from "@dxos/react-ui-grid";
287
+ import { cellQuery, editorKeys, parseCellIndex, useGridContext as useGridContext2, GridCellEditor } from "@dxos/react-ui-grid";
173
288
 
174
289
  // packages/ui/react-ui-table/src/components/TableCellEditor/extension.ts
175
290
  import { autocompletion, pickedCompletion } from "@codemirror/autocomplete";
176
291
  import { EditorView } from "@codemirror/view";
177
- var completion = ({ onQuery, onMatch }) => {
292
+ var completion = ({ debug, onQuery, onMatch }) => {
178
293
  return [
179
294
  EditorView.theme({
180
295
  ".cm-completionDialog": {
@@ -184,6 +299,7 @@ var completion = ({ onQuery, onMatch }) => {
184
299
  autocompletion({
185
300
  icons: false,
186
301
  activateOnTyping: true,
302
+ closeOnBlur: !debug,
187
303
  override: [
188
304
  async (context) => {
189
305
  const text = context.state.doc.toString();
@@ -209,147 +325,27 @@ var completion = ({ onQuery, onMatch }) => {
209
325
  ];
210
326
  };
211
327
 
212
- // packages/ui/react-ui-table/src/util/grid.ts
213
- var fromGridCell = ({ col, row }) => {
214
- return `${col},${row}`;
215
- };
216
- var toGridCell = (cell) => {
217
- const [col, row] = cell.split(",").map(Number);
218
- return {
219
- row,
220
- col
221
- };
222
- };
223
-
224
- // packages/ui/react-ui-table/src/util/signals.ts
225
- var touch = (value) => value;
226
-
227
- // packages/ui/react-ui-table/src/util/table.ts
228
- import { AST, Format, FormatEnum, S, TypedObject, TypeEnum } from "@dxos/echo-schema";
229
- import { log } from "@dxos/log";
230
- import { PublicKey } from "@dxos/react-client";
231
- import { create } from "@dxos/react-client/echo";
232
- import { createFieldId, createView, ViewProjection } from "@dxos/schema";
233
- var __dxlog_file = "/home/runner/work/dxos/dxos/packages/ui/react-ui-table/src/util/table.ts";
234
- var initializeTable = ({ space, table, initialRow = true }) => {
235
- log.info("initializeTable", {
236
- table
237
- }, {
238
- F: __dxlog_file,
239
- L: 32,
240
- S: void 0,
241
- C: (f, a) => f(...a)
242
- });
243
- const ContactSchema = TypedObject({
244
- typename: `example.com/type/${PublicKey.random().truncate()}`,
245
- version: "0.1.0"
246
- })({
247
- name: S.optional(S.String).annotations({
248
- [AST.TitleAnnotationId]: "Name"
249
- }),
250
- email: S.optional(Format.Email),
251
- salary: S.optional(Format.Currency()).annotations({
252
- [AST.TitleAnnotationId]: "Salary"
253
- })
254
- });
255
- const contactSchema = space.db.schemaRegistry.addSchema(ContactSchema);
256
- table.view = createView({
257
- name: "Test",
258
- typename: contactSchema.typename,
259
- jsonSchema: contactSchema.jsonSchema,
260
- fields: [
261
- "name",
262
- "email",
263
- "salary"
264
- ]
265
- });
266
- const projection = new ViewProjection(contactSchema, table.view);
267
- projection.setFieldProjection({
268
- field: {
269
- id: table.view.fields[2].id,
270
- path: "salary",
271
- size: 150
272
- }
273
- });
274
- projection.setFieldProjection({
275
- field: {
276
- id: createFieldId(),
277
- path: "manager",
278
- referencePath: "name"
279
- },
280
- props: {
281
- property: "manager",
282
- type: TypeEnum.Ref,
283
- format: FormatEnum.Ref,
284
- referenceSchema: contactSchema.typename,
285
- title: "Manager"
286
- }
287
- });
288
- if (initialRow) {
289
- space.db.add(create(contactSchema, {}));
290
- }
291
- return contactSchema;
292
- };
293
-
294
- // packages/ui/react-ui-table/src/util/table-buttons.ts
295
- var TABLE_ATTRS = {
296
- columnSettings: "data-table-column-settings-button",
297
- rowMenu: "data-table-row-menu-button",
298
- newColumn: "data-table-new-column-button"
299
- };
300
- var ICONS = {
301
- columnSettings: "ph--caret-down--regular",
302
- rowMenu: "ph--dots-three--regular",
303
- newColumn: "ph--plus--regular"
304
- };
305
- var createButtonHtml = ({ button, value = "", disabled = false, testId }) => {
306
- const buttonClasses = "ch-button is-6 pli-0.5 min-bs-0 absolute inset-block-1 inline-end-2";
307
- return `<button class="${buttonClasses}" ${TABLE_ATTRS[button]}="${value}" data-testid="${testId}" ${disabled ? "disabled" : ""}><svg><use href="/icons.svg#${ICONS[button]}"/></svg></button>`;
308
- };
309
- var tableButtons = {
310
- columnSettings: {
311
- attr: TABLE_ATTRS.columnSettings,
312
- icon: ICONS.columnSettings,
313
- render: ({ fieldId }) => createButtonHtml({
314
- button: "columnSettings",
315
- value: fieldId,
316
- testId: "table-column-settings-button"
317
- })
318
- },
319
- rowMenu: {
320
- attr: TABLE_ATTRS.rowMenu,
321
- icon: ICONS.rowMenu,
322
- render: ({ rowIndex }) => createButtonHtml({
323
- button: "rowMenu",
324
- value: rowIndex.toString(),
325
- testId: "table-row-menu-button"
326
- })
327
- },
328
- addColumn: {
329
- attr: TABLE_ATTRS.newColumn,
330
- icon: ICONS.newColumn,
331
- render: ({ disabled } = {}) => createButtonHtml({
332
- button: "newColumn",
333
- disabled,
334
- testId: "table-new-column-button"
335
- })
336
- }
337
- };
338
-
339
328
  // packages/ui/react-ui-table/src/components/TableCellEditor/TableCellEditor.tsx
340
- var __dxlog_file2 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-table/src/components/TableCellEditor/TableCellEditor.tsx";
329
+ var __dxlog_file = "/home/runner/work/dxos/dxos/packages/ui/react-ui-table/src/components/TableCellEditor/TableCellEditor.tsx";
330
+ var newValue = Symbol.for("newValue");
331
+ var createOption = (text) => ({
332
+ [newValue]: true,
333
+ text
334
+ });
335
+ var isCreateOption = (data) => typeof data === "object" && data[newValue];
341
336
  var TableCellEditor = ({ model, onEnter, onFocus, onQuery, __gridScope }) => {
342
- const { editing } = useGridContext("TableCellEditor", __gridScope);
343
- const fieldProjection = useMemo2(() => {
337
+ const { id: gridId, editing, setEditing } = useGridContext2("TableCellEditor", __gridScope);
338
+ const suppressNextBlur = useRef(false);
339
+ const fieldProjection = useMemo3(() => {
344
340
  if (!model || !editing) {
345
341
  return;
346
342
  }
347
- const { col } = toGridCell(editing.index);
343
+ const { col } = parseCellIndex(editing.index);
348
344
  const field = model.projection.view.fields[col];
349
345
  const fieldProjection2 = model.projection.getFieldProjection(field.id);
350
346
  invariant(fieldProjection2, void 0, {
351
- F: __dxlog_file2,
352
- L: 49,
347
+ F: __dxlog_file,
348
+ L: 65,
353
349
  S: void 0,
354
350
  A: [
355
351
  "fieldProjection",
@@ -361,29 +357,28 @@ var TableCellEditor = ({ model, onEnter, onFocus, onQuery, __gridScope }) => {
361
357
  model,
362
358
  editing
363
359
  ]);
364
- const handleClose = useCallback2((value, event) => {
365
- if (!model || !editing || !fieldProjection) {
360
+ const handleEnter = useCallback3((value) => {
361
+ if (!model || !editing) {
366
362
  return;
367
363
  }
368
- const cell = toGridCell(editing.index);
364
+ const cell = parseCellIndex(editing.index);
365
+ model.setCellData(cell, value);
369
366
  onEnter?.(cell);
370
- if (event && onFocus) {
371
- onFocus(determineNavigationAxis(event), determineNavigationDelta(event));
372
- }
367
+ onFocus?.();
368
+ setEditing(null);
373
369
  }, [
374
370
  model,
375
- editing,
376
- onFocus,
377
- onEnter,
378
- fieldProjection,
379
- determineNavigationAxis,
380
- determineNavigationDelta
371
+ editing
381
372
  ]);
382
- const handleBlur = useCallback2((value) => {
373
+ const handleBlur = useCallback3((value) => {
383
374
  if (!model || !editing) {
384
375
  return;
385
376
  }
386
- const cell = toGridCell(editing.index);
377
+ if (suppressNextBlur.current) {
378
+ suppressNextBlur.current = false;
379
+ return;
380
+ }
381
+ const cell = parseCellIndex(editing.index);
387
382
  if (value !== void 0) {
388
383
  model.setCellData(cell, value);
389
384
  }
@@ -391,7 +386,25 @@ var TableCellEditor = ({ model, onEnter, onFocus, onQuery, __gridScope }) => {
391
386
  model,
392
387
  editing
393
388
  ]);
394
- const extension = useMemo2(() => {
389
+ const handleClose = useCallback3((value, event) => {
390
+ if (!model || !editing || !fieldProjection) {
391
+ return;
392
+ }
393
+ const cell = parseCellIndex(editing.index);
394
+ onEnter?.(cell);
395
+ if (event && onFocus) {
396
+ onFocus(determineNavigationAxis(event), determineNavigationDelta(event));
397
+ }
398
+ }, [
399
+ model,
400
+ editing,
401
+ onFocus,
402
+ onEnter,
403
+ fieldProjection,
404
+ determineNavigationAxis,
405
+ determineNavigationDelta
406
+ ]);
407
+ const extension = useMemo3(() => {
395
408
  if (!fieldProjection) {
396
409
  return [];
397
410
  }
@@ -405,16 +418,25 @@ var TableCellEditor = ({ model, onEnter, onFocus, onQuery, __gridScope }) => {
405
418
  ];
406
419
  if (onQuery) {
407
420
  switch (fieldProjection.props.format) {
408
- case FormatEnum2.Ref: {
421
+ case FormatEnum.Ref: {
409
422
  extension2.push([
410
423
  completion({
411
424
  onQuery: (text) => onQuery(fieldProjection, text),
412
425
  onMatch: (data) => {
413
426
  if (model && editing) {
414
- const cell = toGridCell(editing.index);
415
- model.setCellData(cell, data);
416
- onEnter?.(cell);
417
- onFocus?.();
427
+ if (isCreateOption(data)) {
428
+ const { field, props } = fieldProjection;
429
+ if (props.referenceSchema) {
430
+ suppressNextBlur.current = true;
431
+ model.modalController.openCreateRef(props.referenceSchema, document.querySelector(cellQuery(editing.index, gridId)), {
432
+ [field.referencePath]: data.text
433
+ }, (data2) => {
434
+ handleEnter(data2);
435
+ });
436
+ }
437
+ } else {
438
+ handleEnter(data);
439
+ }
418
440
  }
419
441
  }
420
442
  })
@@ -430,16 +452,16 @@ var TableCellEditor = ({ model, onEnter, onFocus, onQuery, __gridScope }) => {
430
452
  fieldProjection,
431
453
  handleClose
432
454
  ]);
433
- const getCellContent = useCallback2(() => {
455
+ const getCellContent = useCallback3(() => {
434
456
  if (model && editing) {
435
- const value = model.getCellData(toGridCell(editing.index));
457
+ const value = model.getCellData(parseCellIndex(editing.index));
436
458
  return value !== void 0 ? String(value) : "";
437
459
  }
438
460
  }, [
439
461
  model,
440
462
  editing
441
463
  ]);
442
- return /* @__PURE__ */ React4.createElement(GridCellEditor, {
464
+ return /* @__PURE__ */ React6.createElement(GridCellEditor, {
443
465
  extension,
444
466
  getCellContent,
445
467
  onBlur: handleBlur
@@ -471,7 +493,7 @@ var determineNavigationDelta = ({ key, shift }) => {
471
493
  };
472
494
 
473
495
  // packages/ui/react-ui-table/src/components/Table/Table.tsx
474
- var __dxlog_file3 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-table/src/components/Table/Table.tsx";
496
+ var __dxlog_file2 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-table/src/components/Table/Table.tsx";
475
497
  var inlineEndLine = "[&>.dx-grid]:relative [&>.dx-grid]:after:absolute [&>.dx-grid]:after:inset-block-0 [&>.dx-grid]:after:-inline-end-px [&>.dx-grid]:after:is-px [&>.dx-grid]:after:bg-separator";
476
498
  var blockEndLine = "[&>.dx-grid]:before:absolute [&>.dx-grid]:before:inset-inline-0 [&>.dx-grid]:before:-block-end-px [&>.dx-grid]:before:bs-px [&>.dx-grid]:before:bg-separator";
477
499
  var frozen = {
@@ -480,7 +502,7 @@ var frozen = {
480
502
  frozenColsEnd: 1
481
503
  };
482
504
  var TableRoot = ({ children, role }) => {
483
- return /* @__PURE__ */ React5.createElement("div", {
505
+ return /* @__PURE__ */ React7.createElement("div", {
484
506
  role: "none",
485
507
  className: mx("relative border-bs !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]")
486
508
  }, children);
@@ -488,6 +510,7 @@ var TableRoot = ({ children, role }) => {
488
510
  var TableMain = /* @__PURE__ */ forwardRef(({ model, ignoreAttention }, forwardedRef) => {
489
511
  const [dxGrid, setDxGrid] = useState2(null);
490
512
  const { hasAttention } = useAttention(model?.table ? fullyQualifiedId(model.table) : "table");
513
+ const { t } = useTranslation3(translationKey);
491
514
  useImperativeHandle(forwardedRef, () => {
492
515
  if (!model || !dxGrid) {
493
516
  return {};
@@ -506,17 +529,28 @@ var TableMain = /* @__PURE__ */ forwardRef(({ model, ignoreAttention }, forwarde
506
529
  model,
507
530
  dxGrid
508
531
  ]);
509
- const handleFocus = (increment, delta) => {
510
- dxGrid?.refocus(increment, delta);
511
- };
512
- const handleEnter = useCallback3((cell) => {
532
+ const handleFocus = useCallback4((increment, delta) => {
533
+ if (dxGrid) {
534
+ dxGrid.refocus(increment, delta);
535
+ }
536
+ }, [
537
+ dxGrid
538
+ ]);
539
+ const handleEnter = useCallback4((cell) => {
513
540
  if (model && cell.row === model.getRowCount() - 1) {
514
541
  model.insertRow(cell.row);
542
+ if (dxGrid) {
543
+ requestAnimationFrame(() => {
544
+ dxGrid?.scrollToRow(cell.row + 1);
545
+ dxGrid?.refocus("row", 1);
546
+ });
547
+ }
515
548
  }
516
549
  }, [
517
- model
550
+ model,
551
+ dxGrid
518
552
  ]);
519
- const handleKeyDown = useCallback3((event) => {
553
+ const handleKeyDown = useCallback4((event) => {
520
554
  const cell = closestCell(event.target);
521
555
  if (!model || !cell) {
522
556
  return;
@@ -531,7 +565,7 @@ var TableMain = /* @__PURE__ */ forwardRef(({ model, ignoreAttention }, forwarde
531
565
  }, [
532
566
  model
533
567
  ]);
534
- const handleAxisResize = useCallback3((event) => {
568
+ const handleAxisResize = useCallback4((event) => {
535
569
  if (event.axis === "col") {
536
570
  const columnIndex = parseInt(event.index, 10);
537
571
  model?.setColumnWidth(columnIndex, event.size);
@@ -539,7 +573,7 @@ var TableMain = /* @__PURE__ */ forwardRef(({ model, ignoreAttention }, forwarde
539
573
  }, [
540
574
  model
541
575
  ]);
542
- const handleWheel = useCallback3((event) => {
576
+ const handleWheel = useCallback4((event) => {
543
577
  if (!ignoreAttention && !hasAttention) {
544
578
  event.stopPropagation();
545
579
  }
@@ -547,12 +581,21 @@ var TableMain = /* @__PURE__ */ forwardRef(({ model, ignoreAttention }, forwarde
547
581
  hasAttention,
548
582
  ignoreAttention
549
583
  ]);
550
- const handleQuery = useCallback3(async ({ field, props }, _text) => {
584
+ const handleNewColumn = useCallback4(() => {
585
+ const columns = model?.getColumnCount();
586
+ if (dxGrid && columns) {
587
+ dxGrid.scrollToColumn(columns - 1);
588
+ }
589
+ }, [
590
+ model,
591
+ dxGrid
592
+ ]);
593
+ const handleQuery = useCallback4(async ({ field, props }, text) => {
551
594
  if (model && props.referenceSchema && field.referencePath) {
552
- const space = getSpace2(model.table);
595
+ const space = getSpace4(model.table);
553
596
  invariant2(space, void 0, {
554
- F: __dxlog_file3,
555
- L: 158,
597
+ F: __dxlog_file2,
598
+ L: 180,
556
599
  S: void 0,
557
600
  A: [
558
601
  "space",
@@ -562,7 +605,7 @@ var TableMain = /* @__PURE__ */ forwardRef(({ model, ignoreAttention }, forwarde
562
605
  const schema = space.db.schemaRegistry.getSchema(props.referenceSchema);
563
606
  if (schema) {
564
607
  const { objects } = await space.db.query(Filter.schema(schema)).run();
565
- return objects.map((obj) => {
608
+ const options = objects.map((obj) => {
566
609
  const value = getValue(obj, field.referencePath);
567
610
  if (!value || typeof value !== "string") {
568
611
  return void 0;
@@ -572,6 +615,15 @@ var TableMain = /* @__PURE__ */ forwardRef(({ model, ignoreAttention }, forwarde
572
615
  data: obj
573
616
  };
574
617
  }).filter(isNotFalsy);
618
+ return [
619
+ ...options,
620
+ {
621
+ label: t("create new object label", {
622
+ text
623
+ }),
624
+ data: createOption(text)
625
+ }
626
+ ];
575
627
  }
576
628
  }
577
629
  return [];
@@ -579,19 +631,19 @@ var TableMain = /* @__PURE__ */ forwardRef(({ model, ignoreAttention }, forwarde
579
631
  model
580
632
  ]);
581
633
  if (!model) {
582
- return /* @__PURE__ */ React5.createElement("span", {
634
+ return /* @__PURE__ */ React7.createElement("span", {
583
635
  role: "none",
584
636
  className: "attention-surface"
585
637
  });
586
638
  }
587
- return /* @__PURE__ */ React5.createElement(React5.Fragment, null, /* @__PURE__ */ React5.createElement(Grid.Root, {
639
+ return /* @__PURE__ */ React7.createElement(Grid.Root, {
588
640
  id: model.table.id ?? "table-grid"
589
- }, /* @__PURE__ */ React5.createElement(TableCellEditor, {
641
+ }, /* @__PURE__ */ React7.createElement(TableCellEditor, {
590
642
  model,
591
643
  onEnter: handleEnter,
592
644
  onFocus: handleFocus,
593
645
  onQuery: handleQuery
594
- }), /* @__PURE__ */ React5.createElement(Grid.Content, {
646
+ }), /* @__PURE__ */ React7.createElement(Grid.Content, {
595
647
  onWheelCapture: handleWheel,
596
648
  className: mx("[--dx-grid-base:var(--surface-bg)]", inlineEndLine, blockEndLine),
597
649
  frozen,
@@ -603,11 +655,16 @@ var TableMain = /* @__PURE__ */ forwardRef(({ model, ignoreAttention }, forwarde
603
655
  onKeyDown: handleKeyDown,
604
656
  overscroll: "trap",
605
657
  ref: setDxGrid
606
- })), /* @__PURE__ */ React5.createElement(RowActionsMenu, {
658
+ }), /* @__PURE__ */ React7.createElement(RowActionsMenu, {
659
+ model
660
+ }), /* @__PURE__ */ React7.createElement(ColumnActionsMenu, {
607
661
  model
608
- }), /* @__PURE__ */ React5.createElement(ColumnActionsMenu, {
662
+ }), /* @__PURE__ */ React7.createElement(ColumnSettings, {
663
+ model,
664
+ onNewColumn: handleNewColumn
665
+ }), /* @__PURE__ */ React7.createElement(RefPanel, {
609
666
  model
610
- }), /* @__PURE__ */ React5.createElement(ColumnSettings, {
667
+ }), /* @__PURE__ */ React7.createElement(CreateRefPanel, {
611
668
  model
612
669
  }));
613
670
  });
@@ -618,42 +675,42 @@ var Table = {
618
675
 
619
676
  // packages/ui/react-ui-table/src/components/Toolbar/Toolbar.tsx
620
677
  import { createContext } from "@radix-ui/react-context";
621
- import React7 from "react";
622
- import { Toolbar as NaturalToolbar2, useTranslation as useTranslation3 } from "@dxos/react-ui";
678
+ import React9 from "react";
679
+ import { Toolbar as NaturalToolbar2, useTranslation as useTranslation4 } from "@dxos/react-ui";
623
680
 
624
681
  // packages/ui/react-ui-table/src/components/Toolbar/common.tsx
625
- import React6 from "react";
682
+ import React8 from "react";
626
683
  import { Icon, Toolbar as NaturalToolbar, Tooltip } from "@dxos/react-ui";
627
684
  var buttonStyles = "min-bs-0 p-2";
628
685
  var tooltipProps = {
629
686
  side: "top",
630
687
  classNames: "z-10"
631
688
  };
632
- var ToolbarSeparator = () => /* @__PURE__ */ React6.createElement("div", {
689
+ var ToolbarSeparator = () => /* @__PURE__ */ React8.createElement("div", {
633
690
  role: "separator",
634
691
  className: "grow"
635
692
  });
636
693
  var ToolbarButton = ({ icon, children, ...props }) => {
637
- return /* @__PURE__ */ React6.createElement(Tooltip.Root, null, /* @__PURE__ */ React6.createElement(Tooltip.Trigger, {
694
+ return /* @__PURE__ */ React8.createElement(Tooltip.Root, null, /* @__PURE__ */ React8.createElement(Tooltip.Trigger, {
638
695
  asChild: true
639
- }, /* @__PURE__ */ React6.createElement(NaturalToolbar.Button, {
696
+ }, /* @__PURE__ */ React8.createElement(NaturalToolbar.Button, {
640
697
  variant: "ghost",
641
698
  ...props,
642
699
  classNames: buttonStyles
643
- }, /* @__PURE__ */ React6.createElement(Icon, {
700
+ }, /* @__PURE__ */ React8.createElement(Icon, {
644
701
  icon,
645
702
  size: 5
646
- }), /* @__PURE__ */ React6.createElement("span", {
703
+ }), /* @__PURE__ */ React8.createElement("span", {
647
704
  className: "sr-only"
648
- }, children))), /* @__PURE__ */ React6.createElement(Tooltip.Portal, null, /* @__PURE__ */ React6.createElement(Tooltip.Content, tooltipProps, children, /* @__PURE__ */ React6.createElement(Tooltip.Arrow, null))));
705
+ }, children))), /* @__PURE__ */ React8.createElement(Tooltip.Portal, null, /* @__PURE__ */ React8.createElement(Tooltip.Content, tooltipProps, children, /* @__PURE__ */ React8.createElement(Tooltip.Arrow, null))));
649
706
  };
650
707
 
651
708
  // packages/ui/react-ui-table/src/components/Toolbar/Toolbar.tsx
652
709
  var [ToolbarContextProvider, useToolbarContext] = createContext("Toolbar");
653
710
  var ToolbarRoot = ({ classNames, children, onAction }) => {
654
- return /* @__PURE__ */ React7.createElement(ToolbarContextProvider, {
711
+ return /* @__PURE__ */ React9.createElement(ToolbarContextProvider, {
655
712
  onAction
656
- }, /* @__PURE__ */ React7.createElement(NaturalToolbar2.Root, {
713
+ }, /* @__PURE__ */ React9.createElement(NaturalToolbar2.Root, {
657
714
  classNames: [
658
715
  "is-full shrink-0 overflow-x-auto overflow-y-hidden p-1 attention-surface",
659
716
  classNames
@@ -662,8 +719,8 @@ var ToolbarRoot = ({ classNames, children, onAction }) => {
662
719
  };
663
720
  var Editing = () => {
664
721
  const { onAction } = useToolbarContext("Editing");
665
- const { t } = useTranslation3(translationKey);
666
- return /* @__PURE__ */ React7.createElement(React7.Fragment, null, /* @__PURE__ */ React7.createElement(ToolbarButton, {
722
+ const { t } = useTranslation4(translationKey);
723
+ return /* @__PURE__ */ React9.createElement(React9.Fragment, null, /* @__PURE__ */ React9.createElement(ToolbarButton, {
667
724
  value: "add-row",
668
725
  icon: "ph--plus--regular",
669
726
  "data-testid": "table.toolbar.add-row",
@@ -674,8 +731,8 @@ var Editing = () => {
674
731
  };
675
732
  var Actions = () => {
676
733
  const { onAction } = useToolbarContext("Actions");
677
- const { t } = useTranslation3(translationKey);
678
- return /* @__PURE__ */ React7.createElement(React7.Fragment, null, /* @__PURE__ */ React7.createElement(ToolbarButton, {
734
+ const { t } = useTranslation4(translationKey);
735
+ return /* @__PURE__ */ React9.createElement(React9.Fragment, null, /* @__PURE__ */ React9.createElement(ToolbarButton, {
679
736
  value: "comment",
680
737
  icon: "ph--chat-text--regular",
681
738
  "data-testid": "table.toolbar.comment",
@@ -702,11 +759,142 @@ import { getValue as getValue2, setValue, FormatEnum as FormatEnum3 } from "@dxo
702
759
  import { invariant as invariant3 } from "@dxos/invariant";
703
760
  import { PublicKey as PublicKey2 } from "@dxos/react-client";
704
761
  import { cellClassesForFieldType, cellClassesForRowSelection, formatForDisplay, formatForEditing, parseValue } from "@dxos/react-ui-form";
762
+ import { toPlaneCellIndex } from "@dxos/react-ui-grid";
705
763
  import { mx as mx2 } from "@dxos/react-ui-theme";
706
764
  import { VIEW_FIELD_LIMIT } from "@dxos/schema";
707
765
 
708
766
  // packages/ui/react-ui-table/src/model/modal-controller.ts
709
767
  import { signal } from "@preact/signals-core";
768
+ import { log as log2 } from "@dxos/log";
769
+
770
+ // packages/ui/react-ui-table/src/util/signals.ts
771
+ var touch = (value) => value;
772
+
773
+ // packages/ui/react-ui-table/src/util/table.ts
774
+ import { AST, Format, FormatEnum as FormatEnum2, S as S2, TypedObject, TypeEnum } from "@dxos/echo-schema";
775
+ import { log } from "@dxos/log";
776
+ import { PublicKey } from "@dxos/react-client";
777
+ import { create as create2 } from "@dxos/react-client/echo";
778
+ import { createFieldId, createView, ViewProjection } from "@dxos/schema";
779
+ var __dxlog_file3 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-table/src/util/table.ts";
780
+ var initializeTable = ({ space, table, initialRow = true }) => {
781
+ log.info("initializeTable", {
782
+ table
783
+ }, {
784
+ F: __dxlog_file3,
785
+ L: 32,
786
+ S: void 0,
787
+ C: (f, a) => f(...a)
788
+ });
789
+ const ContactSchema = TypedObject({
790
+ typename: `example.com/type/${PublicKey.random().truncate()}`,
791
+ version: "0.1.0"
792
+ })({
793
+ name: S2.optional(S2.String).annotations({
794
+ [AST.TitleAnnotationId]: "Name"
795
+ }),
796
+ email: S2.optional(Format.Email),
797
+ salary: S2.optional(Format.Currency()).annotations({
798
+ [AST.TitleAnnotationId]: "Salary"
799
+ })
800
+ });
801
+ const contactSchema = space.db.schemaRegistry.addSchema(ContactSchema);
802
+ table.view = createView({
803
+ name: "Test",
804
+ typename: contactSchema.typename,
805
+ jsonSchema: contactSchema.jsonSchema,
806
+ fields: [
807
+ "name",
808
+ "email",
809
+ "salary"
810
+ ]
811
+ });
812
+ const projection = new ViewProjection(contactSchema, table.view);
813
+ projection.setFieldProjection({
814
+ field: {
815
+ id: table.view.fields[2].id,
816
+ path: "salary",
817
+ size: 150
818
+ }
819
+ });
820
+ projection.setFieldProjection({
821
+ field: {
822
+ id: createFieldId(),
823
+ path: "manager",
824
+ referencePath: "name"
825
+ },
826
+ props: {
827
+ property: "manager",
828
+ type: TypeEnum.Ref,
829
+ format: FormatEnum2.Ref,
830
+ referenceSchema: contactSchema.typename,
831
+ title: "Manager"
832
+ }
833
+ });
834
+ if (initialRow) {
835
+ space.db.add(create2(contactSchema, {}));
836
+ }
837
+ return contactSchema;
838
+ };
839
+
840
+ // packages/ui/react-ui-table/src/util/table-buttons.ts
841
+ var TABLE_ATTRS = {
842
+ referencedCell: "data-table-ref-cell-button",
843
+ columnSettings: "data-table-column-settings-button",
844
+ rowMenu: "data-table-row-menu-button",
845
+ newColumn: "data-table-new-column-button"
846
+ };
847
+ var ICONS = {
848
+ referencedCell: "ph--link-simple-horizontal--regular",
849
+ columnSettings: "ph--caret-down--regular",
850
+ rowMenu: "ph--dots-three--regular",
851
+ newColumn: "ph--plus--regular"
852
+ };
853
+ var createButtonHtml = ({ button, value = "", disabled = false, testId }) => {
854
+ const buttonClasses = "ch-button is-6 pli-0.5 min-bs-0 absolute inset-block-1 inline-end-2";
855
+ return `<button class="${buttonClasses}" ${TABLE_ATTRS[button]}="${value}" data-testid="${testId}" ${disabled ? "disabled" : ""}><svg><use href="/icons.svg#${ICONS[button]}"/></svg></button>`;
856
+ };
857
+ var tableButtons = {
858
+ referencedCell: {
859
+ attr: TABLE_ATTRS.referencedCell,
860
+ icon: ICONS.referencedCell,
861
+ render: ({ targetId, schemaId }) => createButtonHtml({
862
+ button: "referencedCell",
863
+ value: `${schemaId}#${targetId}`,
864
+ testId: "table-ref-cell-button"
865
+ })
866
+ },
867
+ columnSettings: {
868
+ attr: TABLE_ATTRS.columnSettings,
869
+ icon: ICONS.columnSettings,
870
+ render: ({ fieldId }) => createButtonHtml({
871
+ button: "columnSettings",
872
+ value: fieldId,
873
+ testId: "table-column-settings-button"
874
+ })
875
+ },
876
+ rowMenu: {
877
+ attr: TABLE_ATTRS.rowMenu,
878
+ icon: ICONS.rowMenu,
879
+ render: ({ rowIndex }) => createButtonHtml({
880
+ button: "rowMenu",
881
+ value: rowIndex.toString(),
882
+ testId: "table-row-menu-button"
883
+ })
884
+ },
885
+ addColumn: {
886
+ attr: TABLE_ATTRS.newColumn,
887
+ icon: ICONS.newColumn,
888
+ render: ({ disabled } = {}) => createButtonHtml({
889
+ button: "newColumn",
890
+ disabled,
891
+ testId: "table-new-column-button"
892
+ })
893
+ }
894
+ };
895
+
896
+ // packages/ui/react-ui-table/src/model/modal-controller.ts
897
+ var __dxlog_file4 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-table/src/model/modal-controller.ts";
710
898
  var ModalController = class {
711
899
  constructor() {
712
900
  this._state = signal({
@@ -747,6 +935,16 @@ var ModalController = class {
747
935
  };
748
936
  return true;
749
937
  }
938
+ const refButton = target.closest(`button[${tableButtons.referencedCell.attr}]`);
939
+ if (refButton) {
940
+ this._triggerRef.current = refButton;
941
+ const [schemaId, targetId] = refButton.getAttribute(tableButtons.referencedCell.attr).split("#");
942
+ this._state.value = {
943
+ type: "refPanel",
944
+ targetId,
945
+ typename: schemaId
946
+ };
947
+ }
750
948
  return false;
751
949
  };
752
950
  this.openColumnSettings = () => {
@@ -763,6 +961,24 @@ var ModalController = class {
763
961
  });
764
962
  }
765
963
  };
964
+ this.openCreateRef = (typename, anchorCell, initialValues, onCreate) => {
965
+ if (anchorCell) {
966
+ this._triggerRef.current = anchorCell;
967
+ this._state.value = {
968
+ type: "createRefPanel",
969
+ typename,
970
+ initialValues,
971
+ onCreate
972
+ };
973
+ } else {
974
+ log2.warn("anchor cell not found while creating new ref", void 0, {
975
+ F: __dxlog_file4,
976
+ L: 119,
977
+ S: this,
978
+ C: (f, a) => f(...a)
979
+ });
980
+ }
981
+ };
766
982
  this.close = () => {
767
983
  this._state.value = {
768
984
  type: "closed"
@@ -868,7 +1084,7 @@ var tableControls = {
868
1084
  };
869
1085
 
870
1086
  // packages/ui/react-ui-table/src/model/table-model.ts
871
- var __dxlog_file4 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-table/src/model/table-model.ts";
1087
+ var __dxlog_file5 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-table/src/model/table-model.ts";
872
1088
  var TableModel = class extends Resource2 {
873
1089
  constructor({ table, projection, sorting = [], pinnedRows = {
874
1090
  top: [],
@@ -925,14 +1141,14 @@ var TableModel = class extends Resource2 {
925
1141
  }
926
1142
  };
927
1143
  this.getMainGridCells = (range) => {
928
- const values = {};
1144
+ const cells = {};
929
1145
  const fields = this._table.view?.fields ?? [];
930
1146
  const addCell = (obj, field, colIndex, displayIndex) => {
931
1147
  const { props } = this._projection.getFieldProjection(field.id);
932
- const value = {
1148
+ const cell = {
933
1149
  get value() {
934
- const value2 = getValue2(obj, field.path);
935
- if (value2 == null) {
1150
+ const value = getValue2(obj, field.path);
1151
+ if (value == null) {
936
1152
  return "";
937
1153
  }
938
1154
  switch (props.format) {
@@ -940,13 +1156,13 @@ var TableModel = class extends Resource2 {
940
1156
  if (!field.referencePath) {
941
1157
  return "";
942
1158
  }
943
- return getValue2(value2, field.referencePath);
1159
+ return getValue2(value, field.referencePath);
944
1160
  }
945
1161
  default: {
946
1162
  return formatForDisplay({
947
1163
  type: props.type,
948
1164
  format: props.format,
949
- value: value2
1165
+ value
950
1166
  });
951
1167
  }
952
1168
  }
@@ -965,13 +1181,20 @@ var TableModel = class extends Resource2 {
965
1181
  classes.push(rowSelectionClasses);
966
1182
  }
967
1183
  if (classes.length > 0) {
968
- value.className = mx2(classes.flat());
1184
+ cell.className = mx2(classes.flat());
1185
+ }
1186
+ if (cell.value && props.format === FormatEnum3.Ref && props.referenceSchema) {
1187
+ const targetObj = getValue2(obj, field.path);
1188
+ cell.accessoryHtml = tableButtons.referencedCell.render({
1189
+ targetId: targetObj.id,
1190
+ schemaId: props.referenceSchema
1191
+ });
969
1192
  }
970
- const idx = fromGridCell({
1193
+ const idx = toPlaneCellIndex({
971
1194
  col: colIndex,
972
1195
  row: displayIndex
973
1196
  });
974
- values[idx] = value;
1197
+ cells[idx] = cell;
975
1198
  };
976
1199
  for (let row = range.start.row; row <= range.end.row && row < this._sortedRows.value.length; row++) {
977
1200
  for (let col = range.start.col; col <= range.end.col && col < fields.length; col++) {
@@ -982,17 +1205,18 @@ var TableModel = class extends Resource2 {
982
1205
  addCell(this._sortedRows.value[row], field, col, row);
983
1206
  }
984
1207
  }
985
- return values;
1208
+ return cells;
986
1209
  };
987
1210
  this.getHeaderCells = (range) => {
988
- const values = {};
1211
+ const cells = {};
989
1212
  const fields = this.table.view?.fields ?? [];
990
1213
  for (let col = range.start.col; col <= range.end.col && col < fields.length; col++) {
991
1214
  const { field, props } = this._projection.getFieldProjection(fields[col].id);
992
- values[fromGridCell({
1215
+ cells[toPlaneCellIndex({
993
1216
  col,
994
1217
  row: 0
995
1218
  })] = {
1219
+ // TODO(burdon): Use same logic as form for fallback title.
996
1220
  value: props.title ?? field.path,
997
1221
  readonly: true,
998
1222
  resizeHandle: "col",
@@ -1001,14 +1225,14 @@ var TableModel = class extends Resource2 {
1001
1225
  })
1002
1226
  };
1003
1227
  }
1004
- return values;
1228
+ return cells;
1005
1229
  };
1006
1230
  this.getSelectionColumnCells = (range) => {
1007
- const values = {};
1231
+ const cells = {};
1008
1232
  for (let row = range.start.row; row <= range.end.row && row < this._rows.value.length; row++) {
1009
1233
  const isSelected = this._selection.isRowIndexSelected(row);
1010
1234
  const classes = cellClassesForRowSelection(isSelected);
1011
- values[fromGridCell({
1235
+ cells[toPlaneCellIndex({
1012
1236
  col: 0,
1013
1237
  row
1014
1238
  })] = {
@@ -1021,14 +1245,14 @@ var TableModel = class extends Resource2 {
1021
1245
  })
1022
1246
  };
1023
1247
  }
1024
- return values;
1248
+ return cells;
1025
1249
  };
1026
1250
  this.getActionColumnCells = (range) => {
1027
- const values = {};
1251
+ const cells = {};
1028
1252
  for (let row = range.start.row; row <= range.end.row && row < this._rows.value.length; row++) {
1029
1253
  const isSelected = this._selection.isRowIndexSelected(row);
1030
1254
  const classes = cellClassesForRowSelection(isSelected);
1031
- values[fromGridCell({
1255
+ cells[toPlaneCellIndex({
1032
1256
  col: 0,
1033
1257
  row
1034
1258
  })] = {
@@ -1040,11 +1264,11 @@ var TableModel = class extends Resource2 {
1040
1264
  })
1041
1265
  };
1042
1266
  }
1043
- return values;
1267
+ return cells;
1044
1268
  };
1045
1269
  this.getSelectAllCell = () => {
1046
1270
  return {
1047
- [fromGridCell({
1271
+ [toPlaneCellIndex({
1048
1272
  col: 0,
1049
1273
  row: 0
1050
1274
  })]: {
@@ -1060,7 +1284,7 @@ var TableModel = class extends Resource2 {
1060
1284
  };
1061
1285
  this.getNewColumnCell = () => {
1062
1286
  return {
1063
- [fromGridCell({
1287
+ [toPlaneCellIndex({
1064
1288
  col: 0,
1065
1289
  row: 0
1066
1290
  })]: {
@@ -1190,8 +1414,8 @@ var TableModel = class extends Resource2 {
1190
1414
  }
1191
1415
  get columnMeta() {
1192
1416
  invariant3(this._columnMeta, void 0, {
1193
- F: __dxlog_file4,
1194
- L: 124,
1417
+ F: __dxlog_file5,
1418
+ L: 126,
1195
1419
  S: this,
1196
1420
  A: [
1197
1421
  "this._columnMeta",
@@ -1297,7 +1521,8 @@ var TableModel = class extends Resource2 {
1297
1521
  this?._table?.view?.fields.forEach((field) => touch(getValue2(obj, field.path)));
1298
1522
  this._onCellUpdate?.({
1299
1523
  row,
1300
- col: start.col
1524
+ col: start.col,
1525
+ plane: "grid"
1301
1526
  });
1302
1527
  }));
1303
1528
  }
@@ -1395,12 +1620,11 @@ var useTableModel = ({ objects, table, projection, ...props }) => {
1395
1620
  };
1396
1621
  export {
1397
1622
  Table,
1623
+ TableSchema,
1398
1624
  TableType,
1399
1625
  Toolbar,
1400
- fromGridCell,
1401
1626
  initializeTable,
1402
1627
  tableButtons,
1403
- toGridCell,
1404
1628
  touch,
1405
1629
  translations_default as translations,
1406
1630
  useTableModel,