@dxos/react-ui-table 0.6.12-staging.e11e696 → 0.6.13-main.09887cd

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 (59) hide show
  1. package/dist/lib/browser/index.mjs +40 -124
  2. package/dist/lib/browser/index.mjs.map +4 -4
  3. package/dist/lib/browser/meta.json +1 -1
  4. package/dist/types/src/components/ColumnMenu/ColumnMenu.d.ts +6 -3
  5. package/dist/types/src/components/ColumnMenu/ColumnMenu.d.ts.map +1 -1
  6. package/dist/types/src/components/ColumnMenu/ColumnMenu.stories.d.ts +3 -3
  7. package/dist/types/src/components/ColumnMenu/ColumnMenu.stories.d.ts.map +1 -1
  8. package/dist/types/src/components/ColumnMenu/ColumnSettings.d.ts +15 -0
  9. package/dist/types/src/components/ColumnMenu/ColumnSettings.d.ts.map +1 -0
  10. package/dist/types/src/components/ColumnMenu/ColumnSettings.stories.d.ts +84 -0
  11. package/dist/types/src/components/ColumnMenu/ColumnSettings.stories.d.ts.map +1 -0
  12. package/dist/types/src/components/ColumnMenu/index.d.ts +1 -1
  13. package/dist/types/src/components/ColumnMenu/index.d.ts.map +1 -1
  14. package/dist/types/src/components/Table/Table.d.ts.map +1 -1
  15. package/dist/types/src/components/Table/Table.stories.d.ts +21 -9
  16. package/dist/types/src/components/Table/Table.stories.d.ts.map +1 -1
  17. package/dist/types/src/components/Table/TableContext.d.ts +2 -4
  18. package/dist/types/src/components/Table/TableContext.d.ts.map +1 -1
  19. package/dist/types/src/components/Table/index.d.ts +2 -1
  20. package/dist/types/src/components/Table/index.d.ts.map +1 -1
  21. package/dist/types/src/helpers.d.ts +1 -1
  22. package/dist/types/src/helpers.d.ts.map +1 -1
  23. package/dist/types/src/schema/{SchemaToTable.stories.d.ts → Schema.stories.d.ts} +2 -3
  24. package/dist/types/src/schema/Schema.stories.d.ts.map +1 -0
  25. package/dist/types/src/schema/{schemaToColumns.d.ts → column-utils.d.ts} +1 -1
  26. package/dist/types/src/schema/column-utils.d.ts.map +1 -0
  27. package/dist/types/src/schema/index.d.ts +1 -1
  28. package/dist/types/src/schema/index.d.ts.map +1 -1
  29. package/dist/types/src/schema/types.d.ts +10 -4
  30. package/dist/types/src/schema/types.d.ts.map +1 -1
  31. package/package.json +18 -15
  32. package/src/components/ColumnMenu/ColumnMenu.stories.tsx +13 -12
  33. package/src/components/ColumnMenu/ColumnMenu.tsx +8 -5
  34. package/src/components/ColumnMenu/{ColumnSettingsForm.stories.tsx → ColumnSettings.stories.tsx} +27 -23
  35. package/src/components/ColumnMenu/{ColumnSettingsForm.tsx → ColumnSettings.tsx} +43 -43
  36. package/src/components/ColumnMenu/index.ts +1 -1
  37. package/src/components/Table/Table.stories.tsx +97 -85
  38. package/src/components/Table/Table.tsx +5 -6
  39. package/src/components/Table/TableContext.tsx +13 -7
  40. package/src/components/Table/index.ts +2 -1
  41. package/src/components/Table/props.ts +4 -4
  42. package/src/helpers.tsx +4 -6
  43. package/src/schema/{SchemaToTable.stories.tsx → Schema.stories.tsx} +10 -22
  44. package/src/schema/{schemaToColumns.ts → column-utils.ts} +8 -8
  45. package/src/schema/index.ts +1 -1
  46. package/src/schema/types.ts +14 -6
  47. package/src/translations.ts +1 -1
  48. package/dist/types/src/components/ColumnMenu/ColumnSettingsForm.d.ts +0 -12
  49. package/dist/types/src/components/ColumnMenu/ColumnSettingsForm.d.ts.map +0 -1
  50. package/dist/types/src/components/ColumnMenu/ColumnSettingsForm.stories.d.ts +0 -63
  51. package/dist/types/src/components/ColumnMenu/ColumnSettingsForm.stories.d.ts.map +0 -1
  52. package/dist/types/src/schema/SchemaToTable.stories.d.ts.map +0 -1
  53. package/dist/types/src/schema/schema.d.ts +0 -5
  54. package/dist/types/src/schema/schema.d.ts.map +0 -1
  55. package/dist/types/src/schema/schema.test.d.ts +0 -2
  56. package/dist/types/src/schema/schema.test.d.ts.map +0 -1
  57. package/dist/types/src/schema/schemaToColumns.d.ts.map +0 -1
  58. package/src/schema/schema.test.ts +0 -146
  59. package/src/schema/schema.ts +0 -92
@@ -7,11 +7,12 @@ import '@dxos-theme';
7
7
  import { type SortDirection } from '@tanstack/react-table';
8
8
  import React, { useState } from 'react';
9
9
 
10
+ import { FieldValueType } from '@dxos/schema';
10
11
  import { withTheme } from '@dxos/storybook-utils';
11
12
 
12
13
  import { ColumnMenu } from './ColumnMenu';
13
- import { type ColumnSettingsFormProps } from './ColumnSettingsForm';
14
- import { type ColumnProps } from '../../schema';
14
+ import { type ColumnSettingsProps } from './ColumnSettings';
15
+ import { type ColumnDef } from '../../schema';
15
16
 
16
17
  export default {
17
18
  title: 'react-ui-table/ColumnMenu',
@@ -19,27 +20,27 @@ export default {
19
20
  decorators: [withTheme],
20
21
  };
21
22
 
22
- const defs: Pick<ColumnSettingsFormProps, 'tableDef' | 'tablesToReference'> = {
23
+ const defs: Pick<ColumnSettingsProps, 'tableDef' | 'tablesToReference'> = {
23
24
  tableDef: {
24
25
  id: '1',
25
26
  name: 'table 1',
26
- columns: [{ id: 'col-1', prop: 'one-foo', type: 'string' }],
27
+ columns: [{ id: 'col-1', prop: 'one', type: FieldValueType.String }],
27
28
  },
28
29
  tablesToReference: [
29
30
  {
30
31
  id: '1',
31
32
  name: 'table 1',
32
- columns: [{ id: 'col-1', prop: 'one-foo', type: 'string' }],
33
+ columns: [{ id: 'col-1', prop: 'one', type: FieldValueType.String }],
33
34
  },
34
35
  {
35
36
  id: '2',
36
37
  name: 'table 2',
37
- columns: [{ id: 'col-1', prop: 'two-foo', type: 'string' }],
38
+ columns: [{ id: 'col-1', prop: 'two', type: FieldValueType.String }],
38
39
  },
39
40
  ],
40
41
  };
41
42
 
42
- const funcs: Pick<ColumnSettingsFormProps, 'onUpdate' | 'onDelete'> = {
43
+ const functions: Pick<ColumnSettingsProps, 'onUpdate' | 'onDelete'> = {
43
44
  onUpdate: (...args: any) => console.log('onUpdate args', args),
44
45
  onDelete: (...args: any) => console.log('onDelete args', args),
45
46
  };
@@ -49,10 +50,10 @@ export const Default = {
49
50
  column: {
50
51
  id: 'test',
51
52
  label: 'test',
52
- } as ColumnProps,
53
+ } as ColumnDef,
53
54
 
54
55
  ...defs,
55
- ...funcs,
56
+ ...functions,
56
57
 
57
58
  context: {
58
59
  header: {
@@ -89,11 +90,13 @@ export const ReactiveSort = {
89
90
  column: {
90
91
  id: 'test',
91
92
  label: 'test',
92
- } as ColumnProps,
93
+ } as ColumnDef,
93
94
  context: {
94
95
  header: {
95
96
  column: {
96
97
  getCanSort: () => true,
98
+ getIsSorted: () => sort,
99
+ clearSorting: () => setSort(false),
97
100
  toggleSorting: (desc?: boolean) => {
98
101
  if (desc === undefined) {
99
102
  setSort(false);
@@ -103,8 +106,6 @@ export const ReactiveSort = {
103
106
  setSort('asc');
104
107
  }
105
108
  },
106
- getIsSorted: () => sort,
107
- clearSorting: () => setSort(false),
108
109
  getToggleSortingHandler: () => () => {
109
110
  if (sort === 'asc') {
110
111
  setSort('desc');
@@ -9,22 +9,25 @@ import React, { useRef, useState, useCallback } from 'react';
9
9
  import { Button, Popover, DropdownMenu } from '@dxos/react-ui';
10
10
  import { getSize, mx } from '@dxos/react-ui-theme';
11
11
 
12
- import { ColumnSettingsForm } from './ColumnSettingsForm';
12
+ import { ColumnSettings } from './ColumnSettings';
13
13
  import { useSortColumn } from '../../hooks';
14
- import { type TableDef, type ColumnProps } from '../../schema';
14
+ import { type TableDef, type ColumnDef } from '../../schema';
15
15
 
16
16
  export type ColumnMenuProps<TData extends RowData, TValue> = {
17
17
  context: HeaderContext<TData, TValue>;
18
18
  tablesToReference: TableDef[];
19
19
  tableDef: TableDef;
20
- column: ColumnProps;
20
+ column: ColumnDef;
21
21
  columnOrderable: boolean;
22
22
  columnPosition: 'start' | 'end' | undefined;
23
23
  onColumnReorder: (columnId: string, direction: 'left' | 'right') => void;
24
- onUpdate?: (id: string, column: ColumnProps) => void;
24
+ onUpdate?: (id: string, column: ColumnDef) => void;
25
25
  onDelete?: (id: string) => void;
26
26
  };
27
27
 
28
+ /**
29
+ * @deprecated
30
+ */
28
31
  export const ColumnMenu = <TData extends RowData, TValue>({
29
32
  column,
30
33
  columnOrderable,
@@ -138,7 +141,7 @@ export const ColumnMenu = <TData extends RowData, TValue>({
138
141
  <Popover.Portal>
139
142
  <Popover.Content>
140
143
  <Popover.Viewport>
141
- <ColumnSettingsForm {...props} column={column} onClose={() => setIsColumnSettingsOpen(false)} />
144
+ <ColumnSettings {...props} column={column} onClose={() => setIsColumnSettingsOpen(false)} />
142
145
  </Popover.Viewport>
143
146
  <Popover.Arrow />
144
147
  </Popover.Content>
@@ -3,25 +3,38 @@
3
3
  //
4
4
 
5
5
  import '@dxos-theme';
6
+
6
7
  import React from 'react';
7
8
 
8
- import { withTheme } from '@dxos/storybook-utils';
9
+ import { FieldValueType } from '@dxos/schema';
10
+ import { withTheme, withLayout } from '@dxos/storybook-utils';
9
11
 
10
- import { ColumnSettingsForm, type ColumnSettingsFormProps } from './ColumnSettingsForm';
12
+ import { ColumnSettings, type ColumnSettingsProps } from './ColumnSettings';
11
13
  import { type TableDef } from '../../schema';
14
+ import translations from '../../translations';
15
+
16
+ const Story = (props: ColumnSettingsProps) => (
17
+ <div className='flex w-[240px] m-2 p-2 border border-separator rounded'>
18
+ <ColumnSettings {...props} />
19
+ </div>
20
+ );
12
21
 
13
22
  export default {
14
- title: 'react-ui-table/ColumnSettingsForm',
15
- component: ColumnSettingsForm,
16
- decorators: [withTheme],
23
+ title: 'react-ui-table/ColumnSettings',
24
+ component: ColumnSettings,
25
+ decorators: [withTheme, withLayout()],
26
+ parameters: {
27
+ translations,
28
+ },
29
+ render: Story,
17
30
  };
18
31
 
19
32
  const sampleTableDef: TableDef = {
20
33
  id: '1',
21
34
  name: 'Sample Table',
22
35
  columns: [
23
- { id: 'col-1', prop: 'name', type: 'string', label: 'Name' },
24
- { id: 'col-2', prop: 'age', type: 'number', label: 'Age', digits: 0 },
36
+ { id: 'col-1', prop: 'name', type: FieldValueType.String, label: 'Name' },
37
+ { id: 'col-2', prop: 'age', type: FieldValueType.Number, label: 'Age', digits: 0 },
25
38
  ],
26
39
  };
27
40
 
@@ -31,17 +44,17 @@ const sampleTablesToReference: TableDef[] = [
31
44
  id: '2',
32
45
  name: 'Reference Table',
33
46
  columns: [
34
- { id: 'ref-col-1', prop: 'id', type: 'string', label: 'ID' },
35
- { id: 'ref-col-2', prop: 'description', type: 'string', label: 'Description' },
47
+ { id: 'ref-col-1', prop: 'id', type: FieldValueType.String, label: 'ID' },
48
+ { id: 'ref-col-2', prop: 'description', type: FieldValueType.String, label: 'Description' },
36
49
  ],
37
50
  },
38
51
  ];
39
52
 
40
- const defaultArgs: ColumnSettingsFormProps = {
53
+ const defaultArgs: ColumnSettingsProps = {
41
54
  column: {
42
55
  id: 'col-1',
43
56
  prop: 'name',
44
- type: 'string',
57
+ type: FieldValueType.String,
45
58
  label: 'Name',
46
59
  },
47
60
  tableDef: sampleTableDef,
@@ -61,7 +74,7 @@ export const NumberColumn = {
61
74
  column: {
62
75
  id: 'col-2',
63
76
  prop: 'age',
64
- type: 'number',
77
+ type: FieldValueType.Number,
65
78
  label: 'Age',
66
79
  digits: 0,
67
80
  },
@@ -74,7 +87,7 @@ export const ReferenceColumn = {
74
87
  column: {
75
88
  id: 'col-3',
76
89
  prop: 'reference',
77
- type: 'ref',
90
+ type: FieldValueType.Ref,
78
91
  label: 'Reference',
79
92
  refTable: '2',
80
93
  refProp: 'ref-col-1',
@@ -88,17 +101,8 @@ export const NewColumn = {
88
101
  column: {
89
102
  id: 'new-col',
90
103
  prop: '',
91
- type: 'string',
104
+ type: FieldValueType.String,
92
105
  label: '',
93
106
  },
94
107
  },
95
108
  };
96
-
97
- const Template = (args: ColumnSettingsFormProps) => (
98
- <div className='p-4 max-is-64'>
99
- <ColumnSettingsForm {...args} />
100
- </div>
101
- );
102
-
103
- export const Interactive = Template.bind({});
104
- (Interactive as any).args = defaultArgs;
@@ -5,28 +5,35 @@
5
5
  import React, { useRef, useState } from 'react';
6
6
 
7
7
  import { Button, Input, Select, useTranslation } from '@dxos/react-ui';
8
+ import { FieldValueTypes, type FieldValueType } from '@dxos/schema';
8
9
  import { safeParseInt } from '@dxos/util';
9
10
 
10
- import { type TableDef, type ColumnProps, type ColumnType } from '../../schema';
11
+ import { type TableDef, type ColumnDef } from '../../schema';
11
12
  import { translationKey } from '../../translations';
12
13
 
13
- export type ColumnSettingsFormProps = {
14
- column: ColumnProps;
14
+ export type ColumnSettingsProps = {
15
+ column: ColumnDef;
15
16
  tableDef: TableDef;
17
+ // TODO(burdon): Rename.
16
18
  tablesToReference: TableDef[];
17
- onUpdate?: ((id: string, column: ColumnProps) => void) | undefined;
18
- onDelete?: ((id: string) => void) | undefined;
19
+ onUpdate?: (id: string, column: ColumnDef) => void;
20
+ onDelete?: (id: string) => void;
19
21
  onClose?: () => void;
20
22
  };
21
23
 
22
- export const ColumnSettingsForm = ({
24
+ /**
25
+ * @deprecated
26
+ */
27
+ export const ColumnSettings = ({
23
28
  column,
24
29
  tableDef,
25
30
  tablesToReference,
26
31
  onUpdate,
27
32
  onDelete,
28
33
  onClose,
29
- }: ColumnSettingsFormProps) => {
34
+ }: ColumnSettingsProps) => {
35
+ const { t } = useTranslation(translationKey);
36
+ const propRef = useRef<HTMLInputElement>(null);
30
37
  const [formState, setFormState] = useState({
31
38
  prop: column.id,
32
39
  refTable: column.refTable,
@@ -36,9 +43,6 @@ export const ColumnSettingsForm = ({
36
43
  digits: String(column.digits ?? '0'),
37
44
  });
38
45
 
39
- const propRef = useRef<HTMLInputElement>(null);
40
- const { t } = useTranslation(translationKey);
41
-
42
46
  const handleSave = () => {
43
47
  const { prop, refTable, refProp, type, label, digits } = formState;
44
48
 
@@ -63,7 +67,7 @@ export const ColumnSettingsForm = ({
63
67
  id: prop, // TODO(burdon): Make unique.
64
68
  prop,
65
69
  label,
66
- type: type as ColumnProps['type'],
70
+ type: type as FieldValueType,
67
71
  refTable,
68
72
  refProp,
69
73
  digits: safeParseInt(digits),
@@ -76,9 +80,10 @@ export const ColumnSettingsForm = ({
76
80
  onClose?.();
77
81
  };
78
82
 
83
+ // TODO(burdon): Standardize dialog/popup.
79
84
  return (
80
- <div className='p-1 space-y-2'>
81
- <div className='space-y-1'>
85
+ <div className='flex flex-col w-full gap-4'>
86
+ <div className='flex flex-col gap-2'>
82
87
  <Input.Root>
83
88
  <Input.Label>{t('column label label')}</Input.Label>
84
89
  <Input.TextInput
@@ -89,8 +94,7 @@ export const ColumnSettingsForm = ({
89
94
  data-testid='table.column-settings.label'
90
95
  />
91
96
  </Input.Root>
92
- </div>
93
- <div className='space-y-1'>
97
+
94
98
  <Input.Root>
95
99
  <Input.Label>{t('property key label')}</Input.Label>
96
100
  <Input.TextInput
@@ -102,8 +106,7 @@ export const ColumnSettingsForm = ({
102
106
  }
103
107
  />
104
108
  </Input.Root>
105
- </div>
106
- <div className='space-y-1'>
109
+
107
110
  <Input.Root>
108
111
  <Input.Label>{t('column type label')}</Input.Label>
109
112
  <Select.Root
@@ -114,7 +117,7 @@ export const ColumnSettingsForm = ({
114
117
  <Select.Portal>
115
118
  <Select.Content>
116
119
  <Select.Viewport>
117
- {(['number', 'boolean', 'string', 'ref'] as ColumnType[]).map((type) => (
120
+ {FieldValueTypes.map((type) => (
118
121
  <Select.Option key={type} value={type}>
119
122
  {t(`${type} column type label`)}
120
123
  </Select.Option>
@@ -124,9 +127,8 @@ export const ColumnSettingsForm = ({
124
127
  </Select.Portal>
125
128
  </Select.Root>
126
129
  </Input.Root>
127
- </div>
128
- {formState.type === 'number' && (
129
- <div className='space-y-1'>
130
+
131
+ {formState.type === 'number' && (
130
132
  <Input.Root>
131
133
  <Input.Label>{t('digits label')}</Input.Label>
132
134
  <Input.TextInput
@@ -134,12 +136,10 @@ export const ColumnSettingsForm = ({
134
136
  onChange={(event) => setFormState((prevState) => ({ ...prevState, digits: event.target.value }))}
135
137
  />
136
138
  </Input.Root>
137
- </div>
138
- )}
139
+ )}
139
140
 
140
- {formState.type === 'ref' && (
141
- <>
142
- <div className='space-y-1'>
141
+ {formState.type === 'ref' && (
142
+ <>
143
143
  <Input.Root>
144
144
  <Input.Label>Table</Input.Label>
145
145
  <Select.Root
@@ -162,9 +162,8 @@ export const ColumnSettingsForm = ({
162
162
  </Select.Portal>
163
163
  </Select.Root>
164
164
  </Input.Root>
165
- </div>
166
- {formState.refTable && (
167
- <div className='space-y-1'>
165
+
166
+ {formState.refTable && (
168
167
  <Input.Root>
169
168
  <Input.Label>Table property</Input.Label>
170
169
  <Select.Root
@@ -187,20 +186,21 @@ export const ColumnSettingsForm = ({
187
186
  </Select.Portal>
188
187
  </Select.Root>
189
188
  </Input.Root>
190
- </div>
191
- )}
192
- </>
193
- )}
194
-
195
- <div role='none' className='h-1' />
196
-
197
- <div className='flex flex-row justify-end gap-1'>
198
- <Button onClick={handleDelete} data-testid='table.column-settings.delete'>
199
- {t('delete label')}
200
- </Button>
201
- <Button variant='primary' onClick={handleSave} data-testid='table.column-settings.save'>
202
- {t('save label')}
203
- </Button>
189
+ )}
190
+ </>
191
+ )}
192
+ </div>
193
+
194
+ <div>
195
+ {/* TODO(burdon): Change delete to cancel. Delete should be menu item. */}
196
+ <div className='flex flex-row justify-end gap-1'>
197
+ <Button onClick={handleDelete} data-testid='table.column-settings.delete'>
198
+ {t('delete label')}
199
+ </Button>
200
+ <Button variant='primary' onClick={handleSave} data-testid='table.column-settings.save'>
201
+ {t('save label')}
202
+ </Button>
203
+ </div>
204
204
  </div>
205
205
  </div>
206
206
  );
@@ -3,4 +3,4 @@
3
3
  //
4
4
 
5
5
  export * from './ColumnMenu';
6
- export * from './ColumnSettingsForm';
6
+ export * from './ColumnSettings';
@@ -8,11 +8,11 @@ import { Plugs, PlugsConnected } from '@phosphor-icons/react';
8
8
  import React, { useCallback, useEffect, useMemo, useState } from 'react';
9
9
 
10
10
  import { create } from '@dxos/echo-schema';
11
- import { registerSignalsRuntime } from '@dxos/echo-signals/react';
12
11
  import { PublicKey } from '@dxos/keys';
12
+ import { log } from '@dxos/log';
13
13
  import { faker } from '@dxos/random';
14
14
  import { Button, DensityProvider } from '@dxos/react-ui';
15
- import { withTheme } from '@dxos/storybook-utils';
15
+ import { withSignals, withTheme } from '@dxos/storybook-utils';
16
16
  import { range } from '@dxos/util';
17
17
 
18
18
  import { Table } from './Table';
@@ -406,105 +406,117 @@ export const TenThousandRows = {
406
406
  },
407
407
  };
408
408
 
409
- registerSignalsRuntime();
410
- const state = create({ items: createItems(10) });
409
+ // TODO(burdon): Warning: Encountered two children with the same key.
411
410
 
412
- export const RealTimeUpdates = {
413
- args: {
414
- periodicMutations: true,
415
- mutationInterval: 1000,
416
- periodicDeletions: false,
417
- deletionInterval: 5000,
418
- periodicInsertions: false,
419
- insertionInterval: 3000,
420
- },
421
- argTypes: {
422
- mutationInterval: { control: 'number' },
423
- periodicDeletions: { control: 'boolean' },
424
- deletionInterval: { control: 'number' },
425
- periodicInsertions: { control: 'boolean' },
426
- insertionInterval: { control: 'number' },
427
- },
428
- render: ({
429
- periodicMutations,
430
- mutationInterval,
431
- periodicDeletions,
432
- deletionInterval,
433
- periodicInsertions,
434
- insertionInterval,
435
- }: any) => {
436
- useEffect(() => {
437
- if (!periodicMutations) {
411
+ type StoryProps = {
412
+ periodicMutations: boolean;
413
+ mutationInterval: number;
414
+ periodicDeletions: boolean;
415
+ deletionInterval: number;
416
+ periodicInsertions: boolean;
417
+ insertionInterval: number;
418
+ };
419
+
420
+ const Story = ({
421
+ periodicMutations,
422
+ mutationInterval,
423
+ periodicDeletions,
424
+ deletionInterval,
425
+ periodicInsertions,
426
+ insertionInterval,
427
+ }: StoryProps) => {
428
+ const [state] = useState(() => create({ items: createItems(10) }));
429
+
430
+ useEffect(() => {
431
+ if (!periodicMutations) {
432
+ return;
433
+ }
434
+
435
+ const i = setInterval(() => {
436
+ if (state.items.length === 0) {
438
437
  return;
439
438
  }
440
439
 
441
- const interval = setInterval(() => {
442
- if (state.items.length === 0) {
443
- return;
444
- }
440
+ const idx = Math.floor(Math.random() * state.items.length);
441
+ log('mutating', { idx });
442
+ state.items[idx].name = faker.commerce.productName();
443
+ state.items[idx].count = Math.floor(Math.random() * 1000);
444
+ state.items[idx].started = new Date();
445
+ }, mutationInterval);
445
446
 
446
- const randomIndex = Math.floor(Math.random() * state.items.length);
447
- console.log('Mutating row', randomIndex);
448
- state.items[randomIndex].name = faker.commerce.productName();
449
- state.items[randomIndex].count = Math.floor(Math.random() * 1000);
450
- state.items[randomIndex].started = new Date();
451
- }, mutationInterval);
447
+ return () => clearInterval(i);
448
+ }, [periodicMutations, mutationInterval, state.items]);
452
449
 
453
- return () => clearInterval(interval);
454
- }, [periodicMutations, mutationInterval, state.items]);
450
+ useEffect(() => {
451
+ if (!periodicInsertions) {
452
+ return;
453
+ }
455
454
 
456
- useEffect(() => {
457
- if (!periodicInsertions) {
458
- return;
459
- }
455
+ const i = setInterval(() => {
456
+ log('inserting...');
457
+ state.items.push(createItems(1)[0]);
458
+ }, insertionInterval);
460
459
 
461
- const interval = setInterval(() => {
462
- console.log('Inserting...');
463
- state.items.push(createItems(1)[0]);
464
- }, insertionInterval);
460
+ return () => clearInterval(i);
461
+ }, [periodicInsertions, insertionInterval, state.items]);
465
462
 
466
- return () => clearInterval(interval);
467
- }, [periodicInsertions, insertionInterval, state.items]);
463
+ useEffect(() => {
464
+ if (!periodicDeletions) {
465
+ return;
466
+ }
468
467
 
469
- useEffect(() => {
470
- if (!periodicDeletions) {
468
+ const i = setInterval(() => {
469
+ if (state.items.length === 0) {
471
470
  return;
472
471
  }
473
472
 
474
- const interval = setInterval(() => {
475
- if (state.items.length === 0) {
476
- return;
477
- }
478
-
479
- console.log('Deleting');
473
+ log('deleting...');
474
+ const randomIndex = Math.floor(Math.random() * state.items.length);
475
+ state.items.splice(randomIndex, 1);
476
+ }, deletionInterval);
480
477
 
481
- // Randomly delete a row from state.items
482
- const randomIndex = Math.floor(Math.random() * state.items.length);
483
- state.items.splice(randomIndex, 1);
484
- }, deletionInterval);
478
+ return () => clearInterval(i);
479
+ }, [periodicDeletions, deletionInterval, state.items]);
485
480
 
486
- return () => clearInterval(interval);
487
- }, [periodicDeletions, deletionInterval, state.items]);
481
+ const onUpdate = useCallback((...args: any[]) => {}, []);
482
+ const columns = useMemo(() => makeColumns(onUpdate), []);
488
483
 
489
- const onUpdate = useCallback((...args: any[]) => {}, []);
490
- const columns = useMemo(() => makeColumns(onUpdate), []);
484
+ return (
485
+ <Table.Root>
486
+ <Table.Viewport classNames='fixed inset-0'>
487
+ <Table.Main<Item>
488
+ role='grid'
489
+ rowsSelectable='multi'
490
+ keyAccessor={(row) => row.publicKey.toHex()}
491
+ columns={columns}
492
+ data={state.items}
493
+ fullWidth
494
+ stickyHeader
495
+ border
496
+ pinLastRow
497
+ />
498
+ </Table.Viewport>
499
+ </Table.Root>
500
+ );
501
+ };
491
502
 
492
- return (
493
- <Table.Root>
494
- <Table.Viewport classNames='fixed inset-0'>
495
- <Table.Main<Item>
496
- role='grid'
497
- rowsSelectable='multi'
498
- keyAccessor={(row) => row.publicKey.toHex()}
499
- columns={columns}
500
- data={state.items}
501
- fullWidth
502
- stickyHeader
503
- border
504
- pinLastRow
505
- />
506
- </Table.Viewport>
507
- </Table.Root>
508
- );
503
+ export const RealTimeUpdates = {
504
+ argTypes: {
505
+ periodicMutations: { control: 'boolean' },
506
+ mutationInterval: { control: 'number' },
507
+ periodicDeletions: { control: 'boolean' },
508
+ deletionInterval: { control: 'number' },
509
+ periodicInsertions: { control: 'boolean' },
510
+ insertionInterval: { control: 'number' },
509
511
  },
512
+ args: {
513
+ periodicMutations: true,
514
+ mutationInterval: 1000,
515
+ periodicDeletions: false,
516
+ deletionInterval: 5000,
517
+ periodicInsertions: false,
518
+ insertionInterval: 3000,
519
+ } satisfies StoryProps,
520
+ decorators: [withSignals],
521
+ render: Story,
510
522
  };
@@ -16,13 +16,13 @@ import {
16
16
  } from '@tanstack/react-table';
17
17
  import React, {
18
18
  type ComponentPropsWithoutRef,
19
+ type ReactNode,
19
20
  Fragment,
21
+ memo,
20
22
  useCallback,
21
23
  useEffect,
22
24
  useState,
23
25
  useContext,
24
- type ReactNode,
25
- memo,
26
26
  } from 'react';
27
27
 
28
28
  import { DensityProvider, type ThemedClassName, useDefaultValue } from '@dxos/react-ui';
@@ -55,7 +55,6 @@ const TableViewport = ({ children, classNames, asChild, ...props }: TableViewpor
55
55
  const { scrollContextRef } = useContext(TableRootContext);
56
56
 
57
57
  const classes = mx(classNames, 'overflow-auto');
58
-
59
58
  return asChild ? (
60
59
  <Slot ref={scrollContextRef} className={classes} {...props}>
61
60
  {children}
@@ -70,13 +69,13 @@ const TableViewport = ({ children, classNames, asChild, ...props }: TableViewpor
70
69
  export const TablePrimitive = <TData extends RowData>(props: TableProps<TData>) => {
71
70
  const {
72
71
  role,
73
- onColumnResize,
74
- columnVisibility,
75
72
  header = true,
76
73
  rowsSelectable,
77
74
  debug,
78
- onDataSelectionChange,
79
75
  pinLastRow,
76
+ columnVisibility,
77
+ onColumnResize,
78
+ onDataSelectionChange,
80
79
  } = props;
81
80
 
82
81
  const columns = useDefaultValue(props.columns, () => []);