@dxos/react-ui-table 0.7.5-main.9d26e3a → 0.7.5-main.e9bb01b

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 (70) hide show
  1. package/dist/lib/browser/{chunk-AT7O4RAD.mjs → chunk-T7CTRLHA.mjs} +2 -2
  2. package/dist/lib/browser/{chunk-AT7O4RAD.mjs.map → chunk-T7CTRLHA.mjs.map} +1 -1
  3. package/dist/lib/browser/index.mjs +446 -282
  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 +1 -1
  7. package/dist/lib/node/{chunk-YSBXNBDJ.cjs → chunk-XQRKYO7Q.cjs} +6 -6
  8. package/dist/lib/node/chunk-XQRKYO7Q.cjs.map +7 -0
  9. package/dist/lib/node/index.cjs +438 -268
  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 +3 -3
  13. package/dist/lib/node/types/index.cjs.map +1 -1
  14. package/dist/lib/node-esm/{chunk-6OH2NHUX.mjs → chunk-6HE6MLBK.mjs} +2 -2
  15. package/dist/lib/node-esm/{chunk-6OH2NHUX.mjs.map → chunk-6HE6MLBK.mjs.map} +1 -1
  16. package/dist/lib/node-esm/index.mjs +446 -282
  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 +1 -1
  20. package/dist/types/src/components/Table/Table.d.ts.map +1 -1
  21. package/dist/types/src/components/Table/Table.stories.d.ts +1 -4
  22. package/dist/types/src/components/Table/Table.stories.d.ts.map +1 -1
  23. package/dist/types/src/components/TableToolbar/TableToolbar.d.ts +18 -0
  24. package/dist/types/src/components/TableToolbar/TableToolbar.d.ts.map +1 -0
  25. package/dist/types/src/components/TableToolbar/index.d.ts +2 -0
  26. package/dist/types/src/components/TableToolbar/index.d.ts.map +1 -0
  27. package/dist/types/src/components/index.d.ts +1 -1
  28. package/dist/types/src/components/index.d.ts.map +1 -1
  29. package/dist/types/src/components/testing.d.ts +1 -1
  30. package/dist/types/src/model/table-model.d.ts +11 -19
  31. package/dist/types/src/model/table-model.d.ts.map +1 -1
  32. package/dist/types/src/model/table-presentation.d.ts.map +1 -1
  33. package/dist/types/src/model/table-sorting.d.ts +53 -0
  34. package/dist/types/src/model/table-sorting.d.ts.map +1 -0
  35. package/dist/types/src/translations.d.ts +2 -1
  36. package/dist/types/src/translations.d.ts.map +1 -1
  37. package/dist/types/src/types/table.d.ts +3 -3
  38. package/dist/types/src/types/table.d.ts.map +1 -1
  39. package/dist/types/src/util/table-buttons.d.ts +15 -1
  40. package/dist/types/src/util/table-buttons.d.ts.map +1 -1
  41. package/dist/types/src/util/table.d.ts +2 -1
  42. package/dist/types/src/util/table.d.ts.map +1 -1
  43. package/dist/types/tsconfig.tsbuildinfo +1 -1
  44. package/package.json +35 -34
  45. package/src/_deprecated/schema/Schema.stories.tsx +1 -1
  46. package/src/components/Table/ColumnActionsMenu.tsx +4 -4
  47. package/src/components/Table/Table.stories.tsx +52 -40
  48. package/src/components/Table/Table.tsx +4 -0
  49. package/src/components/TableToolbar/TableToolbar.tsx +72 -0
  50. package/src/components/{Toolbar → TableToolbar}/index.ts +1 -1
  51. package/src/components/index.ts +1 -1
  52. package/src/model/table-model.test.ts +0 -5
  53. package/src/model/table-model.ts +40 -98
  54. package/src/model/table-presentation.ts +25 -4
  55. package/src/model/table-sorting.ts +215 -0
  56. package/src/playwright/smoke.spec.ts +18 -11
  57. package/src/translations.ts +2 -1
  58. package/src/types/table.ts +1 -1
  59. package/src/util/table-buttons.ts +33 -3
  60. package/src/util/table-controls.ts +2 -2
  61. package/src/util/table.ts +78 -52
  62. package/dist/lib/node/chunk-YSBXNBDJ.cjs.map +0 -7
  63. package/dist/types/src/components/Toolbar/Toolbar.d.ts +0 -21
  64. package/dist/types/src/components/Toolbar/Toolbar.d.ts.map +0 -1
  65. package/dist/types/src/components/Toolbar/common.d.ts +0 -14
  66. package/dist/types/src/components/Toolbar/common.d.ts.map +0 -1
  67. package/dist/types/src/components/Toolbar/index.d.ts +0 -2
  68. package/dist/types/src/components/Toolbar/index.d.ts.map +0 -1
  69. package/src/components/Toolbar/Toolbar.tsx +0 -87
  70. package/src/components/Toolbar/common.tsx +0 -71
@@ -2,20 +2,22 @@
2
2
  // Copyright 2024 DXOS.org
3
3
  //
4
4
 
5
- export type TableButton = 'columnSettings' | 'rowMenu' | 'newColumn' | 'referencedCell';
5
+ export type TableButton = 'columnSettings' | 'rowMenu' | 'newColumn' | 'referencedCell' | 'sort';
6
6
 
7
7
  export const BUTTON_IDENTIFIERS: { [K in TableButton]: string } = {
8
8
  columnSettings: 'data-table-column-settings-button',
9
9
  newColumn: 'data-table-new-column-button',
10
10
  referencedCell: 'data-table-ref-cell-button',
11
11
  rowMenu: 'data-table-row-menu-button',
12
+ sort: 'data-table-sort-button',
12
13
  } as const;
13
14
 
14
15
  type ButtonData =
15
16
  | { type: 'columnSettings'; fieldId: string }
16
17
  | { type: 'newColumn'; disabled?: boolean }
17
18
  | { type: 'referencedCell'; schemaId: string; targetId: string }
18
- | { type: 'rowMenu'; rowIndex: number };
19
+ | { type: 'rowMenu'; rowIndex: number }
20
+ | { type: 'sort'; fieldId: string; direction?: 'asc' | 'desc' };
19
21
 
20
22
  const createButton = ({
21
23
  attr,
@@ -23,18 +25,21 @@ const createButton = ({
23
25
  disabled = false,
24
26
  icon,
25
27
  testId,
28
+ type = 'primary',
26
29
  }: {
27
30
  attr: string;
28
31
  data: Record<string, string>;
29
32
  disabled?: boolean;
30
33
  icon: string;
31
34
  testId: string;
35
+ type?: 'primary' | 'secondary';
32
36
  }) => {
33
37
  const dataAttrs = Object.entries(data)
34
38
  .map(([k, v]) => `${k}="${v}"`)
35
39
  .join(' ');
36
40
 
37
- return `<button ${attr} data-testid="${testId}" class="ch-button is-6 pli-0.5 min-bs-0 absolute inset-block-1 inline-end-2" ${dataAttrs} ${disabled ? 'disabled' : ''}><svg><use href="/icons.svg#${icon}"/></svg></button>`;
41
+ const positionClass = type === 'primary' ? 'inline-end-2' : 'inline-end-9';
42
+ 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><use href="/icons.svg#${icon}"/></svg></button>`;
38
43
  };
39
44
 
40
45
  const addColumnButton = {
@@ -111,9 +116,34 @@ const rowMenuButton = {
111
116
  }),
112
117
  } as const;
113
118
 
119
+ const sortButton = {
120
+ attr: BUTTON_IDENTIFIERS.sort,
121
+ icon: 'ph--sort-ascending--regular',
122
+ render: ({ fieldId, direction }: Omit<Extract<ButtonData, { type: 'sort' }>, 'type'>) => {
123
+ return createButton({
124
+ attr: BUTTON_IDENTIFIERS.sort,
125
+ icon: direction === 'desc' ? 'ph--sort-descending--regular' : 'ph--sort-ascending--regular',
126
+ data: {
127
+ 'data-field-id': fieldId,
128
+ 'data-direction': direction ?? '',
129
+ },
130
+ testId: 'table-sort-button',
131
+ // TODO(ZaymonFC): All buttons should be rendered into an absolutely positioned flex container.
132
+ // This is a bit hacky.
133
+ type: 'secondary',
134
+ });
135
+ },
136
+ getData: (el: HTMLElement): Extract<ButtonData, { type: 'sort' }> => ({
137
+ type: 'sort',
138
+ fieldId: el.getAttribute('data-field-id')!,
139
+ direction: el.getAttribute('data-direction') as 'asc' | 'desc' | undefined,
140
+ }),
141
+ } as const;
142
+
114
143
  export const tableButtons = {
115
144
  addColumn: addColumnButton,
116
145
  columnSettings: columnSettingsButton,
117
146
  referencedCell: referencedCellButton,
118
147
  rowMenu: rowMenuButton,
148
+ sort: sortButton,
119
149
  } as const;
@@ -23,8 +23,8 @@ export const CONTROL_IDENTIFIERS = {
23
23
  } as const;
24
24
 
25
25
  const BASE_CLASSES = {
26
- checkbox: 'absolute inset-block-[.375rem] inline-end-[.375rem] ch-checkbox',
27
- switch: 'absolute inset-block-[.25rem] inline-end-[.25rem] ch-checkbox--switch',
26
+ checkbox: 'absolute inset-block-[.375rem] inline-end-[.375rem] dx-checkbox',
27
+ switch: 'absolute inset-block-[.25rem] inline-end-[.25rem] dx-checkbox--switch',
28
28
  } as const;
29
29
 
30
30
  const renderAttributes = (data: Record<string, string>) => {
package/src/util/table.ts CHANGED
@@ -13,10 +13,9 @@ import {
13
13
  TypedObject,
14
14
  TypeEnum,
15
15
  } from '@dxos/echo-schema';
16
- import { log } from '@dxos/log';
17
16
  import { PublicKey } from '@dxos/react-client';
18
17
  import { create, makeRef, type Space } from '@dxos/react-client/echo';
19
- import { createFieldId, createView, ViewProjection } from '@dxos/schema';
18
+ import { createFieldId, createView, getSchemaProperties, ViewProjection } from '@dxos/schema';
20
19
 
21
20
  import { type TableType } from '../types';
22
21
 
@@ -24,70 +23,97 @@ type InitialiseTableProps = {
24
23
  space: Space;
25
24
  table: TableType;
26
25
  initialRow?: boolean;
26
+ initialSchema?: string;
27
27
  };
28
28
 
29
+ // TODO(ZaymonFC): Clean up the branching in this file.
30
+
29
31
  // TODO(burdon): Pass in type.
30
32
  // TODO(burdon): User should determine typename.
31
33
  export const initializeTable = async ({
32
34
  space,
33
35
  table,
34
36
  initialRow = true,
37
+ initialSchema,
35
38
  }: InitialiseTableProps): Promise<EchoSchema> => {
36
- log('initializeTable', { table });
39
+ if (initialSchema) {
40
+ const schema = await space.db.schemaRegistry.query({ typename: initialSchema }).firstOrUndefined();
37
41
 
38
- const ContactSchema = TypedObject({
39
- typename: `example.com/type/${PublicKey.random().truncate()}`,
40
- version: '0.1.0',
41
- })({
42
- name: S.optional(S.String).annotations({
43
- [AST.TitleAnnotationId]: 'Name',
44
- }),
45
- active: S.optional(S.Boolean),
46
- email: S.optional(Format.Email),
47
- salary: S.optional(Format.Currency()).annotations({
48
- [AST.TitleAnnotationId]: 'Salary',
49
- }), // TODO(burdon): Should default to prop name?
50
- });
42
+ if (!schema) {
43
+ throw new Error(`Schema not found: ${initialSchema}`);
44
+ }
51
45
 
52
- const [contactSchema] = await space.db.schemaRegistry.register([ContactSchema]);
46
+ // We need to get the schema properties here. For now, only simple types and refs, not compound types
47
+ // are going to be supported.
48
+ const fields = getSchemaProperties(schema.ast)
49
+ .filter((prop) => prop.type !== 'object' || prop.format === FormatEnum.Ref)
50
+ .map((prop) => prop.name);
53
51
 
54
- table.view = makeRef(
55
- createView({
56
- name: 'Test',
57
- typename: contactSchema.typename,
58
- jsonSchema: contactSchema.jsonSchema,
59
- fields: ['name', 'active', 'email', 'salary'],
60
- }),
61
- );
52
+ table.view = makeRef(
53
+ createView({
54
+ // TODO(ZaymonFC): Don't hardcode name?
55
+ name: 'View',
56
+ typename: schema.typename,
57
+ jsonSchema: schema.jsonSchema,
58
+ fields,
59
+ }),
60
+ );
62
61
 
63
- const projection = new ViewProjection(contactSchema, table.view.target!);
64
- projection.setFieldProjection({
65
- field: {
66
- id: table.view.target!.fields.find((f) => f.path === 'salary')!.id,
67
- path: 'salary' as JsonPath,
68
- size: 150,
69
- },
70
- });
62
+ return schema;
63
+ } else {
64
+ const ContactSchema = TypedObject({
65
+ typename: `example.com/type/${PublicKey.random().truncate()}`,
66
+ version: '0.1.0',
67
+ })({
68
+ name: S.optional(S.String).annotations({
69
+ [AST.TitleAnnotationId]: 'Name',
70
+ }),
71
+ active: S.optional(S.Boolean),
72
+ email: S.optional(Format.Email),
73
+ salary: S.optional(Format.Currency()).annotations({
74
+ [AST.TitleAnnotationId]: 'Salary',
75
+ }), // TODO(burdon): Should default to prop name?
76
+ });
71
77
 
72
- projection.setFieldProjection({
73
- field: {
74
- id: createFieldId(),
75
- path: 'manager' as JsonPath,
76
- referencePath: 'name' as JsonPath,
77
- },
78
- props: {
79
- property: 'manager' as JsonProp,
80
- type: TypeEnum.Ref,
81
- format: FormatEnum.Ref,
82
- referenceSchema: contactSchema.typename,
83
- title: 'Manager',
84
- },
85
- });
78
+ const [contactSchema] = await space.db.schemaRegistry.register([ContactSchema]);
86
79
 
87
- if (initialRow) {
88
- // TODO(burdon): Last (first) row should not be in db and should be managed by the model.
89
- space.db.add(create(contactSchema, {}));
90
- }
80
+ table.view = makeRef(
81
+ createView({
82
+ name: 'View',
83
+ typename: contactSchema.typename,
84
+ jsonSchema: contactSchema.jsonSchema,
85
+ fields: ['name', 'active', 'email', 'salary'],
86
+ }),
87
+ );
88
+
89
+ const projection = new ViewProjection(contactSchema, table.view.target!);
90
+ projection.setFieldProjection({
91
+ field: {
92
+ id: table.view.target!.fields.find((f) => f.path === 'salary')!.id,
93
+ path: 'salary' as JsonPath,
94
+ size: 150,
95
+ },
96
+ });
91
97
 
92
- return contactSchema;
98
+ projection.setFieldProjection({
99
+ field: {
100
+ id: createFieldId(),
101
+ path: 'manager' as JsonPath,
102
+ referencePath: 'name' as JsonPath,
103
+ },
104
+ props: {
105
+ property: 'manager' as JsonProp,
106
+ type: TypeEnum.Ref,
107
+ format: FormatEnum.Ref,
108
+ referenceSchema: contactSchema.typename,
109
+ title: 'Manager',
110
+ },
111
+ });
112
+ if (initialRow) {
113
+ // TODO(burdon): Last (first) row should not be in db and should be managed by the model.
114
+ space.db.add(create(contactSchema, {}));
115
+ }
116
+
117
+ return contactSchema;
118
+ }
93
119
  };
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../../../src/types/table.ts"],
4
- "sourcesContent": ["//\n// Copyright 2024 DXOS.org\n//\n\nimport { Ref, ObjectId, S, TypedObject } from '@dxos/echo-schema';\nimport { ThreadType } from '@dxos/plugin-space';\nimport { ViewType } from '@dxos/schema';\n\nexport const TableSchema = S.Struct({\n id: ObjectId, // TODO(burdon): Where should this be?\n name: S.optional(S.String),\n view: S.optional(Ref(ViewType)),\n // TODO(burdon): Should not import from plugin. Either factor out type or use reverse deps when supported.\n threads: S.optional(S.Array(Ref(ThreadType))),\n});\n\n// type TableType = S.Schema.Type<typeof TableSchema>;\n\nexport class TableType extends TypedObject({\n typename: 'dxos.org/type/Table',\n version: '0.1.0',\n})(TableSchema.fields) {}\n"],
5
- "mappings": ";;;;;;;;;;;;;;;;;;;;;;;;AAIA,yBAA8C;AAC9C,0BAA2B;AAC3B,oBAAyB;AAElB,IAAMA,cAAcC,qBAAEC,OAAO;EAClCC,IAAIC;EACJC,MAAMJ,qBAAEK,SAASL,qBAAEM,MAAM;EACzBC,MAAMP,qBAAEK,aAASG,wBAAIC,sBAAAA,CAAAA;;EAErBC,SAASV,qBAAEK,SAASL,qBAAEW,UAAMH,wBAAII,8BAAAA,CAAAA,CAAAA;AAClC,CAAA;AAIO,IAAMC,YAAN,kBAAwBC,gCAAY;EACzCC,UAAU;EACVC,SAAS;AACX,CAAA,EAAGjB,YAAYkB,MAAM,EAAA;AAAG;",
6
- "names": ["TableSchema", "S", "Struct", "id", "ObjectId", "name", "optional", "String", "view", "Ref", "ViewType", "threads", "Array", "ThreadType", "TableType", "TypedObject", "typename", "version", "fields"]
7
- }
@@ -1,21 +0,0 @@
1
- import React, { type PropsWithChildren } from 'react';
2
- import { type ThemedClassName } from '@dxos/react-ui';
3
- export type ToolbarAction = {
4
- type: 'add-row';
5
- } | {
6
- type: 'comment';
7
- };
8
- export type ToolbarActionType = ToolbarAction['type'];
9
- export type ToolbarActionHandler = (action: ToolbarAction) => void;
10
- export type ToolbarProps = ThemedClassName<PropsWithChildren<{
11
- onAction?: ToolbarActionHandler;
12
- }>>;
13
- declare const useToolbarContext: (consumerName: string) => ToolbarProps;
14
- export declare const Toolbar: {
15
- Root: ({ classNames, children, onAction }: ToolbarProps) => React.JSX.Element;
16
- Editing: () => React.JSX.Element;
17
- Actions: () => React.JSX.Element;
18
- Separator: () => React.JSX.Element;
19
- };
20
- export { useToolbarContext };
21
- //# sourceMappingURL=Toolbar.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"Toolbar.d.ts","sourceRoot":"","sources":["../../../../../src/components/Toolbar/Toolbar.tsx"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,EAAE,KAAK,iBAAiB,EAAE,MAAM,OAAO,CAAC;AAEtD,OAAO,EAA6B,KAAK,eAAe,EAAkB,MAAM,gBAAgB,CAAC;AAUjG,MAAM,MAAM,aAAa,GAAG;IAAE,IAAI,EAAE,SAAS,CAAA;CAAE,GAAG;IAAE,IAAI,EAAE,SAAS,CAAA;CAAE,CAAC;AAEtE,MAAM,MAAM,iBAAiB,GAAG,aAAa,CAAC,MAAM,CAAC,CAAC;AAEtD,MAAM,MAAM,oBAAoB,GAAG,CAAC,MAAM,EAAE,aAAa,KAAK,IAAI,CAAC;AAEnE,MAAM,MAAM,YAAY,GAAG,eAAe,CACxC,iBAAiB,CAAC;IAChB,QAAQ,CAAC,EAAE,oBAAoB,CAAC;CACjC,CAAC,CACH,CAAC;AAEF,QAAA,MAA+B,iBAAiB,wCAA0C,CAAC;AAkD3F,eAAO,MAAM,OAAO;+CAhDqC,YAAY;;;;CAqDpE,CAAC;AAEF,OAAO,EAAE,iBAAiB,EAAE,CAAC"}
@@ -1,14 +0,0 @@
1
- import React from 'react';
2
- import { type IconProps, type ToolbarButtonProps as NaturalToolbarButtonProps, type ToolbarToggleGroupItemProps as NaturalToolbarToggleGroupItemProps } from '@dxos/react-ui';
3
- export declare const buttonStyles = "min-bs-0 p-2";
4
- export declare const tooltipProps: {
5
- side: "top";
6
- classNames: string;
7
- };
8
- export declare const ToolbarSeparator: () => React.JSX.Element;
9
- type ToolbarButtonProps = NaturalToolbarButtonProps & Pick<IconProps, 'icon'>;
10
- export declare const ToolbarButton: ({ icon, children, ...props }: ToolbarButtonProps) => React.JSX.Element;
11
- export type ToolbarToggleButtonProps = NaturalToolbarToggleGroupItemProps & Pick<IconProps, 'icon'>;
12
- export declare const ToolbarToggleButton: ({ icon, children, ...props }: ToolbarToggleButtonProps) => React.JSX.Element;
13
- export {};
14
- //# sourceMappingURL=common.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"common.d.ts","sourceRoot":"","sources":["../../../../../src/components/Toolbar/common.tsx"],"names":[],"mappings":"AAIA,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,OAAO,EAEL,KAAK,SAAS,EAGd,KAAK,kBAAkB,IAAI,yBAAyB,EACpD,KAAK,2BAA2B,IAAI,kCAAkC,EACvE,MAAM,gBAAgB,CAAC;AAIxB,eAAO,MAAM,YAAY,iBAAiB,CAAC;AAC3C,eAAO,MAAM,YAAY;;;CAA+C,CAAC;AAEzE,eAAO,MAAM,gBAAgB,yBAAkD,CAAC;AAMhF,KAAK,kBAAkB,GAAG,yBAAyB,GAAG,IAAI,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC;AAE9E,eAAO,MAAM,aAAa,iCAAkC,kBAAkB,sBAiB7E,CAAC;AAMF,MAAM,MAAM,wBAAwB,GAAG,kCAAkC,GAAG,IAAI,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC;AAEpG,eAAO,MAAM,mBAAmB,iCAAkC,wBAAwB,sBAiBzF,CAAC"}
@@ -1,2 +0,0 @@
1
- export * from './Toolbar';
2
- //# sourceMappingURL=index.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/components/Toolbar/index.ts"],"names":[],"mappings":"AAIA,cAAc,WAAW,CAAC"}
@@ -1,87 +0,0 @@
1
- //
2
- // Copyright 2024 DXOS.org
3
- //
4
-
5
- import { createContext } from '@radix-ui/react-context';
6
- import React, { type PropsWithChildren } from 'react';
7
-
8
- import { Toolbar as NaturalToolbar, type ThemedClassName, useTranslation } from '@dxos/react-ui';
9
-
10
- import { ToolbarButton, ToolbarSeparator } from './common';
11
- import { translationKey } from '../../translations';
12
-
13
- //
14
- // Root
15
- //
16
-
17
- // TODO(Zan): This should become a union later.
18
- export type ToolbarAction = { type: 'add-row' } | { type: 'comment' };
19
-
20
- export type ToolbarActionType = ToolbarAction['type'];
21
-
22
- export type ToolbarActionHandler = (action: ToolbarAction) => void;
23
-
24
- export type ToolbarProps = ThemedClassName<
25
- PropsWithChildren<{
26
- onAction?: ToolbarActionHandler;
27
- }>
28
- >;
29
-
30
- const [ToolbarContextProvider, useToolbarContext] = createContext<ToolbarProps>('Toolbar');
31
-
32
- const ToolbarRoot = ({ classNames, children, onAction }: ToolbarProps) => {
33
- return (
34
- <ToolbarContextProvider onAction={onAction}>
35
- <NaturalToolbar.Root
36
- classNames={['is-full shrink-0 overflow-x-auto overflow-y-hidden p-1 attention-surface', classNames]}
37
- >
38
- {children}
39
- </NaturalToolbar.Root>
40
- </ToolbarContextProvider>
41
- );
42
- };
43
-
44
- const Editing = () => {
45
- const { onAction } = useToolbarContext('Editing');
46
- const { t } = useTranslation(translationKey);
47
-
48
- return (
49
- <>
50
- <ToolbarButton
51
- value='add-row'
52
- icon='ph--plus--regular'
53
- data-testid='table.toolbar.add-row'
54
- onClick={() => onAction?.({ type: 'add-row' })}
55
- >
56
- {t('add row')}
57
- </ToolbarButton>
58
- </>
59
- );
60
- };
61
-
62
- const Actions = () => {
63
- const { onAction } = useToolbarContext('Actions');
64
- const { t } = useTranslation(translationKey);
65
-
66
- return (
67
- <>
68
- <ToolbarButton
69
- value='comment'
70
- icon='ph--chat-text--regular'
71
- data-testid='table.toolbar.comment'
72
- onClick={() => onAction?.({ type: 'comment' })}
73
- >
74
- {t('create comment')}
75
- </ToolbarButton>
76
- </>
77
- );
78
- };
79
-
80
- export const Toolbar = {
81
- Root: ToolbarRoot,
82
- Editing,
83
- Actions,
84
- Separator: ToolbarSeparator,
85
- };
86
-
87
- export { useToolbarContext };
@@ -1,71 +0,0 @@
1
- //
2
- // Copyright 2024 DXOS.org
3
- //
4
-
5
- import React from 'react';
6
-
7
- import {
8
- Icon,
9
- type IconProps,
10
- Toolbar as NaturalToolbar,
11
- Tooltip,
12
- type ToolbarButtonProps as NaturalToolbarButtonProps,
13
- type ToolbarToggleGroupItemProps as NaturalToolbarToggleGroupItemProps,
14
- } from '@dxos/react-ui';
15
-
16
- // TODO(burdon): Factor out into new package (react-ui-toolbar) in common with react-ui-editor, etc.
17
-
18
- export const buttonStyles = 'min-bs-0 p-2';
19
- export const tooltipProps = { side: 'top' as const, classNames: 'z-10' };
20
-
21
- export const ToolbarSeparator = () => <div role='separator' className='grow' />;
22
-
23
- //
24
- // ToolbarButton
25
- //
26
-
27
- type ToolbarButtonProps = NaturalToolbarButtonProps & Pick<IconProps, 'icon'>;
28
-
29
- export const ToolbarButton = ({ icon, children, ...props }: ToolbarButtonProps) => {
30
- return (
31
- <Tooltip.Root>
32
- <Tooltip.Trigger asChild>
33
- <NaturalToolbar.Button variant='ghost' {...props} classNames={buttonStyles}>
34
- <Icon icon={icon} size={5} />
35
- <span className='sr-only'>{children}</span>
36
- </NaturalToolbar.Button>
37
- </Tooltip.Trigger>
38
- <Tooltip.Portal>
39
- <Tooltip.Content {...tooltipProps}>
40
- {children}
41
- <Tooltip.Arrow />
42
- </Tooltip.Content>
43
- </Tooltip.Portal>
44
- </Tooltip.Root>
45
- );
46
- };
47
-
48
- //
49
- // ToolbarToggleButton
50
- //
51
-
52
- export type ToolbarToggleButtonProps = NaturalToolbarToggleGroupItemProps & Pick<IconProps, 'icon'>;
53
-
54
- export const ToolbarToggleButton = ({ icon, children, ...props }: ToolbarToggleButtonProps) => {
55
- return (
56
- <Tooltip.Root>
57
- <Tooltip.Trigger asChild>
58
- <NaturalToolbar.ToggleGroupItem variant='ghost' {...props} classNames={buttonStyles}>
59
- <Icon icon={icon} size={5} />
60
- <span className='sr-only'>{children}</span>
61
- </NaturalToolbar.ToggleGroupItem>
62
- </Tooltip.Trigger>
63
- <Tooltip.Portal>
64
- <Tooltip.Content {...tooltipProps}>
65
- {children}
66
- <Tooltip.Arrow />
67
- </Tooltip.Content>
68
- </Tooltip.Portal>
69
- </Tooltip.Root>
70
- );
71
- };