@dxos/react-ui-table 0.7.2 → 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,4 +1,57 @@
1
- import { ref, S } from '@dxos/echo-schema';
1
+ import { ref, ObjectId, S } from '@dxos/echo-schema';
2
+ export declare const TableSchema: S.Struct<{
3
+ id: S.SchemaClass<string, string, never> & {
4
+ random(): ObjectId;
5
+ };
6
+ name: S.optional<typeof S.String>;
7
+ view: S.optional<ref<{
8
+ name: string;
9
+ schema?: import("@dxos/echo-schema").JsonSchemaType | undefined;
10
+ query: import("@dxos/echo-schema").QueryType;
11
+ fields: {
12
+ referencePath?: import("@dxos/echo-schema").JsonPath | undefined;
13
+ id: string;
14
+ path: import("@dxos/echo-schema").JsonPath;
15
+ visible?: boolean | undefined;
16
+ size?: number | undefined;
17
+ }[];
18
+ } & {
19
+ id: string;
20
+ }>>;
21
+ threads: S.optional<S.Array$<ref<{
22
+ name?: string | undefined;
23
+ anchor?: string | undefined;
24
+ status?: "active" | "staged" | "resolved" | undefined;
25
+ messages: import("@dxos/echo-schema").Ref<{
26
+ text: string;
27
+ timestamp: string;
28
+ state?: import("@dxos/plugin-space").MessageState | undefined;
29
+ sender: {
30
+ name?: string | undefined;
31
+ contact?: import("@dxos/echo-schema").Ref<{
32
+ name?: string | undefined;
33
+ identifiers: {
34
+ readonly value: string;
35
+ readonly type: string;
36
+ }[];
37
+ } & {
38
+ id: string;
39
+ }>;
40
+ identityKey?: string | undefined;
41
+ email?: string | undefined;
42
+ };
43
+ parts?: import("@dxos/echo-schema").Ref<import("@dxos/echo-schema").Expando>[] | undefined;
44
+ properties?: {
45
+ [x: string]: any;
46
+ } | undefined;
47
+ context?: import("@dxos/echo-schema").Ref<import("@dxos/echo-schema").Expando>;
48
+ } & {
49
+ id: string;
50
+ }>[];
51
+ } & {
52
+ id: string;
53
+ }>>>;
54
+ }>;
2
55
  declare const TableType_base: import("@dxos/echo-schema").AbstractTypedObject<{
3
56
  name?: string | undefined;
4
57
  id: string;
@@ -52,7 +105,9 @@ declare const TableType_base: import("@dxos/echo-schema").AbstractTypedObject<{
52
105
  } & {
53
106
  id: string;
54
107
  }, S.Struct.Encoded<{
55
- readonly id: typeof S.String;
108
+ readonly id: S.SchemaClass<string, string, never> & {
109
+ random(): ObjectId;
110
+ };
56
111
  readonly name: S.optional<typeof S.String>;
57
112
  readonly view: S.optional<ref<{
58
113
  name: string;
@@ -1 +1 @@
1
- {"version":3,"file":"table.d.ts","sourceRoot":"","sources":["../../../../src/types/table.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,GAAG,EAAE,CAAC,EAAe,MAAM,mBAAmB,CAAC;;;;;;;;;yBAkBiB,CAAC;;;mBAAmF,CAAC;gBAAmC,CAAC;;;;;;;;;;;;iBAAonF,CAAC;;oBAA8D,CAAC;uBAAyC,CAAC;wBAAwD,CAAC;;;;;;;;2BAAsP,CAAC;qBAAuC,CAAC;;iBAA8C,CAAC;sBAA4E,CAAC;;;mBAAwE,CAAC;;;;;;;;;;;;;;;;;yBAAp3G,CAAC;;;mBAAmF,CAAC;gBAAmC,CAAC;;;;;;;;;;;;iBAAonF,CAAC;;oBAA8D,CAAC;uBAAyC,CAAC;wBAAwD,CAAC;;;;;;;;2BAAsP,CAAC;qBAAuC,CAAC;;iBAA8C,CAAC;sBAA4E,CAAC;;;mBAAwE,CAAC;;;;;;;;AAJ77G,qBAAa,SAAU,SAAQ,cAGT;CAAG"}
1
+ {"version":3,"file":"table.d.ts","sourceRoot":"","sources":["../../../../src/types/table.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,GAAG,EAAE,QAAQ,EAAE,CAAC,EAAe,MAAM,mBAAmB,CAAC;AAIlE,eAAO,MAAM,WAAW;;;;;;;;;;yBAcD,CAAC;;;mBAAmF,CAAC;gBAAmC,CAAC;;;;;;;;;;;;iBAAglF,CAAC;;oBAA8D,CAAC;uBAAyC,CAAC;wBAAwD,CAAC;;;;;;;;2BAAsP,CAAC;qBAAuC,CAAC;;iBAA8C,CAAC;sBAA4E,CAAC;;;mBAAwE,CAAC;;;;;;;EARr2G,CAAC;;;;;;;;;yBAQoB,CAAC;;;mBAAmF,CAAC;gBAAmC,CAAC;;;;;;;;;;;;iBAAglF,CAAC;;oBAA8D,CAAC;uBAAyC,CAAC;wBAAwD,CAAC;;;;;;;;2BAAsP,CAAC;qBAAuC,CAAC;;iBAA8C,CAAC;sBAA4E,CAAC;;;mBAAwE,CAAC;;;;;;;;;;;;;;;;;;;yBAAh1G,CAAC;;;mBAAmF,CAAC;gBAAmC,CAAC;;;;;;;;;;;;iBAAglF,CAAC;;oBAA8D,CAAC;uBAAyC,CAAC;wBAAwD,CAAC;;;;;;;;2BAAsP,CAAC;qBAAuC,CAAC;;iBAA8C,CAAC;sBAA4E,CAAC;;;mBAAwE,CAAC;;;;;;;;AAJv2G,qBAAa,SAAU,SAAQ,cAGT;CAAG"}
@@ -1,4 +1,3 @@
1
- export * from './grid';
2
1
  export * from './signals';
3
2
  export * from './table';
4
3
  export * from './table-buttons';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/util/index.ts"],"names":[],"mappings":"AAIA,cAAc,QAAQ,CAAC;AACvB,cAAc,WAAW,CAAC;AAC1B,cAAc,SAAS,CAAC;AACxB,cAAc,iBAAiB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/util/index.ts"],"names":[],"mappings":"AAIA,cAAc,WAAW,CAAC;AAC1B,cAAc,SAAS,CAAC;AACxB,cAAc,iBAAiB,CAAC"}
@@ -1,4 +1,12 @@
1
1
  export declare const tableButtons: {
2
+ readonly referencedCell: {
3
+ readonly attr: string;
4
+ readonly icon: string;
5
+ readonly render: ({ targetId, schemaId }: {
6
+ targetId: string;
7
+ schemaId: string;
8
+ }) => string;
9
+ };
2
10
  readonly columnSettings: {
3
11
  readonly attr: string;
4
12
  readonly icon: string;
@@ -1 +1 @@
1
- {"version":3,"file":"table-buttons.d.ts","sourceRoot":"","sources":["../../../../src/util/table-buttons.ts"],"names":[],"mappings":"AAiCA,eAAO,MAAM,YAAY;;;;uCAIC;YAAE,OAAO,EAAE,MAAM,CAAA;SAAE;;;;;wCAMlB;YAAE,QAAQ,EAAE,MAAM,CAAA;SAAE;;;;;yCAMpB;YAAE,QAAQ,CAAC,EAAE,OAAO,CAAA;SAAE;;CAGvC,CAAC"}
1
+ {"version":3,"file":"table-buttons.d.ts","sourceRoot":"","sources":["../../../../src/util/table-buttons.ts"],"names":[],"mappings":"AAwCA,eAAO,MAAM,YAAY;;;;kDAIY;YAAE,QAAQ,EAAE,MAAM,CAAC;YAAC,QAAQ,EAAE,MAAM,CAAA;SAAE;;;;;uCAUjD;YAAE,OAAO,EAAE,MAAM,CAAA;SAAE;;;;;wCAMlB;YAAE,QAAQ,EAAE,MAAM,CAAA;SAAE;;;;;yCAMpB;YAAE,QAAQ,CAAC,EAAE,OAAO,CAAA;SAAE;;CAGvC,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dxos/react-ui-table",
3
- "version": "0.7.2",
3
+ "version": "0.7.3-main.2dd075e",
4
4
  "description": "A table component.",
5
5
  "homepage": "https://dxos.org",
6
6
  "bugs": "https://github.com/dxos/dxos/issues",
@@ -53,25 +53,26 @@
53
53
  "@tanstack/react-virtual": "^3.9.0",
54
54
  "date-fns": "^3.3.1",
55
55
  "lodash.orderby": "^4.6.0",
56
- "@dxos/debug": "0.7.2",
57
- "@dxos/context": "0.7.2",
58
- "@dxos/echo-schema": "0.7.2",
59
- "@dxos/invariant": "0.7.2",
60
- "@dxos/keys": "0.7.2",
61
- "@dxos/lit-grid": "0.7.2",
62
- "@dxos/log": "0.7.2",
63
- "@dxos/plugin-search": "0.7.2",
64
- "@dxos/react-client": "0.7.2",
65
- "@dxos/plugin-space": "0.7.2",
66
- "@dxos/react-ui-attention": "0.7.2",
67
- "@dxos/react-ui-form": "0.7.2",
68
- "@dxos/react-ui-grid": "0.7.2",
69
- "@dxos/react-ui-searchlist": "0.7.2",
70
- "@dxos/react-ui-stack": "0.7.2",
71
- "@dxos/react-ui-types": "0.7.2",
72
- "@dxos/react-ui-syntax-highlighter": "0.7.2",
73
- "@dxos/util": "0.7.2",
74
- "@dxos/schema": "0.7.2"
56
+ "@dxos/debug": "0.7.3-main.2dd075e",
57
+ "@dxos/invariant": "0.7.3-main.2dd075e",
58
+ "@dxos/echo-schema": "0.7.3-main.2dd075e",
59
+ "@dxos/keys": "0.7.3-main.2dd075e",
60
+ "@dxos/context": "0.7.3-main.2dd075e",
61
+ "@dxos/live-object": "0.7.3-main.2dd075e",
62
+ "@dxos/lit-grid": "0.7.3-main.2dd075e",
63
+ "@dxos/plugin-search": "0.7.3-main.2dd075e",
64
+ "@dxos/log": "0.7.3-main.2dd075e",
65
+ "@dxos/react-client": "0.7.3-main.2dd075e",
66
+ "@dxos/plugin-space": "0.7.3-main.2dd075e",
67
+ "@dxos/react-ui-form": "0.7.3-main.2dd075e",
68
+ "@dxos/react-ui-attention": "0.7.3-main.2dd075e",
69
+ "@dxos/react-ui-grid": "0.7.3-main.2dd075e",
70
+ "@dxos/react-ui-searchlist": "0.7.3-main.2dd075e",
71
+ "@dxos/react-ui-stack": "0.7.3-main.2dd075e",
72
+ "@dxos/react-ui-syntax-highlighter": "0.7.3-main.2dd075e",
73
+ "@dxos/react-ui-types": "0.7.3-main.2dd075e",
74
+ "@dxos/schema": "0.7.3-main.2dd075e",
75
+ "@dxos/util": "0.7.3-main.2dd075e"
75
76
  },
76
77
  "devDependencies": {
77
78
  "@phosphor-icons/react": "^2.1.5",
@@ -82,19 +83,19 @@
82
83
  "react": "~18.2.0",
83
84
  "react-dom": "~18.2.0",
84
85
  "vite": "5.4.7",
85
- "@dxos/echo-signals": "0.7.2",
86
- "@dxos/random": "0.7.2",
87
- "@dxos/react-ui": "0.7.2",
88
- "@dxos/react-ui-theme": "0.7.2",
89
- "@dxos/storybook-utils": "0.7.2",
90
- "@dxos/test-utils": "0.7.2"
86
+ "@dxos/random": "0.7.3-main.2dd075e",
87
+ "@dxos/storybook-utils": "0.7.3-main.2dd075e",
88
+ "@dxos/echo-signals": "0.7.3-main.2dd075e",
89
+ "@dxos/react-ui": "0.7.3-main.2dd075e",
90
+ "@dxos/test-utils": "0.7.3-main.2dd075e",
91
+ "@dxos/react-ui-theme": "0.7.3-main.2dd075e"
91
92
  },
92
93
  "peerDependencies": {
93
94
  "@phosphor-icons/react": "^2.1.5",
94
95
  "react": "~18.2.0",
95
96
  "react-dom": "~18.2.0",
96
- "@dxos/react-ui": "0.7.2",
97
- "@dxos/react-ui-theme": "0.7.2"
97
+ "@dxos/react-ui": "0.7.3-main.2dd075e",
98
+ "@dxos/react-ui-theme": "0.7.3-main.2dd075e"
98
99
  },
99
100
  "publishConfig": {
100
101
  "access": "public"
@@ -8,8 +8,8 @@ import { Plugs, PlugsConnected } from '@phosphor-icons/react';
8
8
  import { type StoryObj } from '@storybook/react';
9
9
  import React, { useCallback, useEffect, useMemo, useState } from 'react';
10
10
 
11
- import { create } from '@dxos/echo-schema';
12
11
  import { PublicKey } from '@dxos/keys';
12
+ import { create } from '@dxos/live-object';
13
13
  import { log } from '@dxos/log';
14
14
  import { faker } from '@dxos/random';
15
15
  import { Button } from '@dxos/react-ui';
@@ -14,7 +14,6 @@ type ColumnActionsMenuProps = { model?: TableModel };
14
14
  export const ColumnActionsMenu = ({ model }: ColumnActionsMenuProps) => {
15
15
  const { t } = useTranslation(translationKey);
16
16
  const state = model?.modalController.state.value;
17
-
18
17
  if (!model || state?.type !== 'column') {
19
18
  return null;
20
19
  }
@@ -11,9 +11,9 @@ import { type FieldType } from '@dxos/schema';
11
11
 
12
12
  import { type TableModel } from '../../model';
13
13
 
14
- type ColumnSettingsProps = { model?: TableModel };
14
+ type ColumnSettingsProps = { model?: TableModel; onNewColumn: () => void };
15
15
 
16
- export const ColumnSettings = ({ model }: ColumnSettingsProps) => {
16
+ export const ColumnSettings = ({ model, onNewColumn }: ColumnSettingsProps) => {
17
17
  const [newField, setNewField] = useState<FieldType>();
18
18
  const state = model?.modalController.state.value;
19
19
 
@@ -22,6 +22,9 @@ export const ColumnSettings = ({ model }: ColumnSettingsProps) => {
22
22
  useEffect(() => {
23
23
  if (state?.type === 'columnSettings' && state.mode.type === 'create' && model?.projection) {
24
24
  setNewField(model.projection.createFieldProjection());
25
+ requestAnimationFrame(() => {
26
+ onNewColumn();
27
+ });
25
28
  } else {
26
29
  setNewField(undefined);
27
30
  }
@@ -39,7 +42,7 @@ export const ColumnSettings = ({ model }: ColumnSettingsProps) => {
39
42
 
40
43
  const field = existingField ?? newField;
41
44
 
42
- const handleClose = useCallback(() => {
45
+ const handleSave = useCallback(() => {
43
46
  model?.modalController.close();
44
47
  }, [model?.modalController]);
45
48
 
@@ -64,7 +67,7 @@ export const ColumnSettings = ({ model }: ColumnSettingsProps) => {
64
67
  projection={model.projection}
65
68
  field={field}
66
69
  registry={space?.db.schemaRegistry}
67
- onClose={handleClose}
70
+ onSave={handleSave}
68
71
  onCancel={handleCancel}
69
72
  />
70
73
  </DropdownMenu.Viewport>
@@ -0,0 +1,83 @@
1
+ //
2
+ // Copyright 2024 DXOS.org
3
+ //
4
+
5
+ import React, { useCallback, useMemo } from 'react';
6
+
7
+ import { S } from '@dxos/echo-schema';
8
+ import { create, getSpace } from '@dxos/react-client/echo';
9
+ import { Popover } from '@dxos/react-ui';
10
+ import { Form } from '@dxos/react-ui-form';
11
+ import { type GridScopedProps, useGridContext } from '@dxos/react-ui-grid';
12
+
13
+ import { type TableModel } from '../../model';
14
+
15
+ export type CreateRefPanelProps = { model?: TableModel };
16
+
17
+ // TODO(burdon): Factor out Space dependency (to plugin?)
18
+ export const CreateRefPanel = ({ model, __gridScope }: GridScopedProps<CreateRefPanelProps>) => {
19
+ const { id: gridId } = useGridContext('TableCellEditor', __gridScope);
20
+ const space = getSpace(model?.table);
21
+ const state = model?.modalController.state.value;
22
+ const schema = useMemo<S.Schema<any> | undefined>(() => {
23
+ if (!space || state?.type !== 'createRefPanel') {
24
+ return;
25
+ }
26
+
27
+ // TODO(burdon): Factor out.
28
+ const schema: S.Schema<any> | undefined = space.db.schemaRegistry.getSchema(state.typename)?.schema;
29
+ if (schema) {
30
+ const omit = S.omit<any, any, ['id']>('id');
31
+ return omit(schema);
32
+ }
33
+ }, [space, state]);
34
+
35
+ const handleSave = useCallback(
36
+ (values: any) => {
37
+ if (!model || !space || state?.type !== 'createRefPanel') {
38
+ return;
39
+ }
40
+
41
+ const schema: S.Schema<any> | undefined = space.db.schemaRegistry.getSchema(state.typename)?.schema;
42
+ if (schema) {
43
+ const obj = space.db.add(create(schema, values));
44
+ state.onCreate?.(obj);
45
+ }
46
+
47
+ void model.modalController.close();
48
+ },
49
+ [model?.modalController, space, state],
50
+ );
51
+
52
+ const handleCancel = useCallback(() => {
53
+ if (model) {
54
+ model.modalController.close();
55
+ }
56
+ }, [model?.modalController]);
57
+
58
+ if (!model?.table?.view || !model.projection) {
59
+ return null;
60
+ }
61
+
62
+ return (
63
+ <Popover.Root
64
+ modal={false}
65
+ open={state?.type === 'createRefPanel' && !!schema}
66
+ onOpenChange={(nextOpen) => {
67
+ if (model && !nextOpen) {
68
+ return model.modalController.close();
69
+ }
70
+ }}
71
+ >
72
+ <Popover.VirtualTrigger virtualRef={model.modalController.trigger} />
73
+ <Popover.Portal>
74
+ <Popover.Content classNames='md:is-64' data-grid={gridId}>
75
+ {state?.type === 'createRefPanel' && schema && (
76
+ <Form schema={schema} values={state.initialValues ?? {}} onSave={handleSave} onCancel={handleCancel} />
77
+ )}
78
+ <Popover.Arrow />
79
+ </Popover.Content>
80
+ </Popover.Portal>
81
+ </Popover.Root>
82
+ );
83
+ };
@@ -0,0 +1,52 @@
1
+ //
2
+ // Copyright 2024 DXOS.org
3
+ //
4
+
5
+ import React from 'react';
6
+
7
+ import { getSpace, type Space } from '@dxos/react-client/echo';
8
+ import { Popover } from '@dxos/react-ui';
9
+ import { Form } from '@dxos/react-ui-form';
10
+
11
+ import { type TableModel } from '../../model';
12
+
13
+ type RefPanelProps = { model?: TableModel };
14
+
15
+ const getRefTargetObj = (space?: Space, id?: string) => {
16
+ if (space && id) {
17
+ return space?.db.getObjectById(id);
18
+ } else {
19
+ return undefined;
20
+ }
21
+ };
22
+
23
+ export const RefPanel = ({ model }: RefPanelProps) => {
24
+ const state = model?.modalController.state.value;
25
+ const space = getSpace(model?.table);
26
+ const targetObj = getRefTargetObj(space, state?.type === 'refPanel' ? state.targetId : undefined);
27
+ const schema = space && state?.type === 'refPanel' ? space.db.schemaRegistry.getSchema(state.typename) : undefined;
28
+
29
+ if (!model?.table?.view || !model.projection) {
30
+ return null;
31
+ }
32
+
33
+ return (
34
+ <Popover.Root
35
+ modal={false}
36
+ open={state?.type === 'refPanel' && !!targetObj && !!schema}
37
+ onOpenChange={(nextOpen) => {
38
+ if (model && !nextOpen) {
39
+ return model.modalController.close();
40
+ }
41
+ }}
42
+ >
43
+ <Popover.VirtualTrigger virtualRef={model.modalController.trigger} />
44
+ <Popover.Portal>
45
+ <Popover.Content classNames='md:is-64'>
46
+ {targetObj && schema && <Form readonly values={targetObj} schema={schema} />}
47
+ <Popover.Arrow />
48
+ </Popover.Content>
49
+ </Popover.Portal>
50
+ </Popover.Root>
51
+ );
52
+ };
@@ -13,9 +13,8 @@ type RowActionsMenuProps = { model: TableModel };
13
13
 
14
14
  export const RowActionsMenu = ({ model }: RowActionsMenuProps) => {
15
15
  const { t } = useTranslation(translationKey);
16
- const state = model.modalController.state.value;
17
16
  const hasSelection = model.selection.hasSelection.value;
18
-
17
+ const state = model.modalController.state.value;
19
18
  if (state?.type !== 'row') {
20
19
  return null;
21
20
  }
@@ -44,7 +44,7 @@ const DefaultStory = () => {
44
44
  const table = tables[0];
45
45
  invariant(table.view);
46
46
  setTable(table);
47
- setSchema(space.db.schemaRegistry.getSchema(table.view.query.type));
47
+ setSchema(space.db.schemaRegistry.getSchema(table.view.query.typename));
48
48
  }
49
49
  }, [tables]);
50
50
 
@@ -54,7 +54,7 @@ const DefaultStory = () => {
54
54
  }
55
55
  }, [schema, table?.view]);
56
56
 
57
- const objects = useQuery(space, schema ? Filter.schema(schema) : () => false, undefined, [schema]);
57
+ const objects = useQuery(space, schema ? Filter.schema(schema) : Filter.nothing());
58
58
  const filteredObjects = useGlobalFilteredObjects(objects);
59
59
 
60
60
  const handleInsertRow = useCallback(() => {
@@ -14,17 +14,20 @@ import React, {
14
14
  import { getValue } from '@dxos/echo-schema';
15
15
  import { invariant } from '@dxos/invariant';
16
16
  import { Filter, getSpace, fullyQualifiedId } from '@dxos/react-client/echo';
17
+ import { useTranslation } from '@dxos/react-ui';
17
18
  import { useAttention } from '@dxos/react-ui-attention';
18
- import { type DxGridElement, Grid, type GridContentProps, closestCell } from '@dxos/react-ui-grid';
19
+ import { type DxGridElement, Grid, type GridContentProps, closestCell, type DxGridPosition } from '@dxos/react-ui-grid';
19
20
  import { mx } from '@dxos/react-ui-theme';
20
21
  import { isNotFalsy } from '@dxos/util';
21
22
 
22
23
  import { ColumnActionsMenu } from './ColumnActionsMenu';
23
24
  import { ColumnSettings } from './ColumnSettings';
25
+ import { CreateRefPanel } from './CreateRefPanel';
26
+ import { RefPanel } from './RefPanel';
24
27
  import { RowActionsMenu } from './RowActionsMenu';
25
28
  import { type TableModel } from '../../model';
26
- import { type GridCell } from '../../util';
27
- import { TableCellEditor, type TableCellEditorProps } from '../TableCellEditor';
29
+ import { translationKey } from '../../translations';
30
+ import { createOption, TableCellEditor, type TableCellEditorProps } from '../TableCellEditor';
28
31
 
29
32
  // NOTE(Zan): These fragments add border to inline-end and block-end of the grid using pseudo-elements.
30
33
  // These are offset by 1px to avoid double borders in planks.
@@ -62,7 +65,7 @@ const TableRoot = ({ children, role }: TableRootProps) => {
62
65
  //
63
66
 
64
67
  export type TableController = {
65
- update?: (cell?: GridCell) => void;
68
+ update?: (cell?: DxGridPosition) => void;
66
69
  };
67
70
 
68
71
  export type TableMainProps = {
@@ -72,8 +75,8 @@ export type TableMainProps = {
72
75
 
73
76
  const TableMain = forwardRef<TableController, TableMainProps>(({ model, ignoreAttention }, forwardedRef) => {
74
77
  const [dxGrid, setDxGrid] = useState<DxGridElement | null>(null);
75
-
76
78
  const { hasAttention } = useAttention(model?.table ? fullyQualifiedId(model.table) : 'table');
79
+ const { t } = useTranslation(translationKey);
77
80
 
78
81
  /**
79
82
  * Provides an external controller that can be called to repaint the table.
@@ -99,18 +102,29 @@ const TableMain = forwardRef<TableController, TableMainProps>(({ model, ignoreAt
99
102
  [model, dxGrid],
100
103
  );
101
104
 
102
- const handleFocus: TableCellEditorProps['onFocus'] = (increment, delta) => {
103
- dxGrid?.refocus(increment, delta);
104
- };
105
+ const handleFocus = useCallback<NonNullable<TableCellEditorProps['onFocus']>>(
106
+ (increment, delta) => {
107
+ if (dxGrid) {
108
+ dxGrid.refocus(increment, delta);
109
+ }
110
+ },
111
+ [dxGrid],
112
+ );
105
113
 
106
114
  const handleEnter = useCallback<NonNullable<TableCellEditorProps['onEnter']>>(
107
115
  (cell) => {
108
116
  // TODO(burdon): Insert row only if bottom row isn't completely blank already.
109
117
  if (model && cell.row === model.getRowCount() - 1) {
110
118
  model.insertRow(cell.row);
119
+ if (dxGrid) {
120
+ requestAnimationFrame(() => {
121
+ dxGrid?.scrollToRow(cell.row + 1);
122
+ dxGrid?.refocus('row', 1);
123
+ });
124
+ }
111
125
  }
112
126
  },
113
- [model],
127
+ [model, dxGrid],
114
128
  );
115
129
 
116
130
  const handleKeyDown = useCallback<NonNullable<GridContentProps['onKeyDown']>>(
@@ -150,17 +164,24 @@ const TableMain = forwardRef<TableController, TableMainProps>(({ model, ignoreAt
150
164
  [hasAttention, ignoreAttention],
151
165
  );
152
166
 
167
+ const handleNewColumn = useCallback(() => {
168
+ const columns = model?.getColumnCount();
169
+ if (dxGrid && columns) {
170
+ dxGrid.scrollToColumn(columns - 1);
171
+ }
172
+ }, [model, dxGrid]);
173
+
153
174
  // TODO(burdon): Factor out?
175
+ // TODO(burdon): Generalize to handle other value types (e.g., enums).
154
176
  const handleQuery = useCallback<NonNullable<TableCellEditorProps['onQuery']>>(
155
- async ({ field, props }, _text) => {
177
+ async ({ field, props }, text) => {
156
178
  if (model && props.referenceSchema && field.referencePath) {
157
179
  const space = getSpace(model.table);
158
180
  invariant(space);
159
181
  const schema = space.db.schemaRegistry.getSchema(props.referenceSchema);
160
182
  if (schema) {
161
- // TODO(burdon): Cache/filter.
162
183
  const { objects } = await space.db.query(Filter.schema(schema)).run();
163
- return objects
184
+ const options = objects
164
185
  .map((obj) => {
165
186
  const value = getValue(obj, field.referencePath!);
166
187
  if (!value || typeof value !== 'string') {
@@ -173,6 +194,14 @@ const TableMain = forwardRef<TableController, TableMainProps>(({ model, ignoreAt
173
194
  };
174
195
  })
175
196
  .filter(isNotFalsy);
197
+
198
+ return [
199
+ ...options,
200
+ {
201
+ label: t('create new object label', { text }),
202
+ data: createOption(text),
203
+ },
204
+ ];
176
205
  }
177
206
  }
178
207
 
@@ -186,29 +215,27 @@ const TableMain = forwardRef<TableController, TableMainProps>(({ model, ignoreAt
186
215
  }
187
216
 
188
217
  return (
189
- <>
190
- <Grid.Root id={model.table.id ?? 'table-grid'}>
191
- <TableCellEditor model={model} onEnter={handleEnter} onFocus={handleFocus} onQuery={handleQuery} />
192
-
193
- <Grid.Content
194
- onWheelCapture={handleWheel}
195
- className={mx('[--dx-grid-base:var(--surface-bg)]', inlineEndLine, blockEndLine)}
196
- frozen={frozen}
197
- columns={model.columnMeta.value}
198
- limitRows={model.getRowCount() ?? 0}
199
- limitColumns={model.table.view?.fields?.length ?? 0}
200
- onAxisResize={handleAxisResize}
201
- onClick={model?.handleGridClick}
202
- onKeyDown={handleKeyDown}
203
- overscroll='trap'
204
- ref={setDxGrid}
205
- />
206
- </Grid.Root>
207
-
218
+ <Grid.Root id={model.table.id ?? 'table-grid'}>
219
+ <TableCellEditor model={model} onEnter={handleEnter} onFocus={handleFocus} onQuery={handleQuery} />
220
+ <Grid.Content
221
+ onWheelCapture={handleWheel}
222
+ className={mx('[--dx-grid-base:var(--surface-bg)]', inlineEndLine, blockEndLine)}
223
+ frozen={frozen}
224
+ columns={model.columnMeta.value}
225
+ limitRows={model.getRowCount() ?? 0}
226
+ limitColumns={model.table.view?.fields?.length ?? 0}
227
+ onAxisResize={handleAxisResize}
228
+ onClick={model?.handleGridClick}
229
+ onKeyDown={handleKeyDown}
230
+ overscroll='trap'
231
+ ref={setDxGrid}
232
+ />
208
233
  <RowActionsMenu model={model} />
209
234
  <ColumnActionsMenu model={model} />
210
- <ColumnSettings model={model} />
211
- </>
235
+ <ColumnSettings model={model} onNewColumn={handleNewColumn} />
236
+ <RefPanel model={model} />
237
+ <CreateRefPanel model={model} />
238
+ </Grid.Root>
212
239
  );
213
240
  });
214
241
 
@@ -37,7 +37,7 @@ const DefaultStory = ({ editing }: StoryProps) => {
37
37
  const table = tables[0];
38
38
  invariant(table.view);
39
39
  setTable(table);
40
- setSchema(space.db.schemaRegistry.getSchema(table.view.query.type));
40
+ setSchema(space.db.schemaRegistry.getSchema(table.view.query.typename));
41
41
  }
42
42
  }, [tables]);
43
43
 
@@ -107,7 +107,7 @@ type Story = StoryObj<StoryProps>;
107
107
  export const Default: Story = {
108
108
  args: {
109
109
  editing: {
110
- index: '0,3',
110
+ index: 'grid,0,3',
111
111
  initialContent: 'Test',
112
112
  },
113
113
  },