@dxos/react-ui-table 0.6.13-main.ed424a1 → 0.6.13

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 (63) hide show
  1. package/dist/lib/browser/index.mjs +127 -43
  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 +3 -6
  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/ColumnSettingsForm.d.ts +12 -0
  9. package/dist/types/src/components/ColumnMenu/ColumnSettingsForm.d.ts.map +1 -0
  10. package/dist/types/src/components/ColumnMenu/ColumnSettingsForm.stories.d.ts +63 -0
  11. package/dist/types/src/components/ColumnMenu/ColumnSettingsForm.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 +9 -21
  16. package/dist/types/src/components/Table/Table.stories.d.ts.map +1 -1
  17. package/dist/types/src/components/Table/TableContext.d.ts +4 -2
  18. package/dist/types/src/components/Table/TableContext.d.ts.map +1 -1
  19. package/dist/types/src/components/Table/TableHead.d.ts.map +1 -1
  20. package/dist/types/src/components/Table/index.d.ts +1 -2
  21. package/dist/types/src/components/Table/index.d.ts.map +1 -1
  22. package/dist/types/src/helpers.d.ts +1 -1
  23. package/dist/types/src/helpers.d.ts.map +1 -1
  24. package/dist/types/src/hooks/useRowSelection.d.ts.map +1 -1
  25. package/dist/types/src/schema/{Schema.stories.d.ts → SchemaToTable.stories.d.ts} +3 -2
  26. package/dist/types/src/schema/SchemaToTable.stories.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/schema.d.ts +5 -0
  30. package/dist/types/src/schema/schema.d.ts.map +1 -0
  31. package/dist/types/src/schema/schema.test.d.ts +2 -0
  32. package/dist/types/src/schema/schema.test.d.ts.map +1 -0
  33. package/dist/types/src/schema/{column-utils.d.ts → schemaToColumns.d.ts} +2 -2
  34. package/dist/types/src/schema/schemaToColumns.d.ts.map +1 -0
  35. package/dist/types/src/schema/types.d.ts +4 -10
  36. package/dist/types/src/schema/types.d.ts.map +1 -1
  37. package/package.json +20 -21
  38. package/src/components/ColumnMenu/ColumnMenu.stories.tsx +12 -13
  39. package/src/components/ColumnMenu/ColumnMenu.tsx +5 -8
  40. package/src/components/ColumnMenu/{ColumnSettings.stories.tsx → ColumnSettingsForm.stories.tsx} +23 -27
  41. package/src/components/ColumnMenu/{ColumnSettings.tsx → ColumnSettingsForm.tsx} +43 -44
  42. package/src/components/ColumnMenu/index.ts +1 -1
  43. package/src/components/Table/Table.stories.tsx +85 -97
  44. package/src/components/Table/Table.tsx +9 -8
  45. package/src/components/Table/TableContext.tsx +7 -13
  46. package/src/components/Table/TableHead.tsx +1 -0
  47. package/src/components/Table/index.ts +1 -2
  48. package/src/components/Table/props.ts +4 -4
  49. package/src/helpers.tsx +6 -4
  50. package/src/hooks/useRowSelection.ts +0 -1
  51. package/src/schema/{Schema.stories.tsx → SchemaToTable.stories.tsx} +23 -11
  52. package/src/schema/index.ts +1 -1
  53. package/src/schema/schema.test.ts +148 -0
  54. package/src/schema/schema.ts +93 -0
  55. package/src/schema/{column-utils.ts → schemaToColumns.ts} +9 -9
  56. package/src/schema/types.ts +6 -14
  57. package/src/translations.ts +1 -1
  58. package/dist/types/src/components/ColumnMenu/ColumnSettings.d.ts +0 -15
  59. package/dist/types/src/components/ColumnMenu/ColumnSettings.d.ts.map +0 -1
  60. package/dist/types/src/components/ColumnMenu/ColumnSettings.stories.d.ts +0 -84
  61. package/dist/types/src/components/ColumnMenu/ColumnSettings.stories.d.ts.map +0 -1
  62. package/dist/types/src/schema/Schema.stories.d.ts.map +0 -1
  63. package/dist/types/src/schema/column-utils.d.ts.map +0 -1
@@ -7,12 +7,11 @@ 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';
11
10
  import { withTheme } from '@dxos/storybook-utils';
12
11
 
13
12
  import { ColumnMenu } from './ColumnMenu';
14
- import { type ColumnSettingsProps } from './ColumnSettings';
15
- import { type ColumnDef } from '../../schema';
13
+ import { type ColumnSettingsFormProps } from './ColumnSettingsForm';
14
+ import { type ColumnProps } from '../../schema';
16
15
 
17
16
  export default {
18
17
  title: 'react-ui-table/ColumnMenu',
@@ -20,27 +19,27 @@ export default {
20
19
  decorators: [withTheme],
21
20
  };
22
21
 
23
- const defs: Pick<ColumnSettingsProps, 'tableDef' | 'tablesToReference'> = {
22
+ const defs: Pick<ColumnSettingsFormProps, 'tableDef' | 'tablesToReference'> = {
24
23
  tableDef: {
25
24
  id: '1',
26
25
  name: 'table 1',
27
- columns: [{ id: 'col-1', prop: 'one', type: FieldValueType.String }],
26
+ columns: [{ id: 'col-1', prop: 'one-foo', type: 'string' }],
28
27
  },
29
28
  tablesToReference: [
30
29
  {
31
30
  id: '1',
32
31
  name: 'table 1',
33
- columns: [{ id: 'col-1', prop: 'one', type: FieldValueType.String }],
32
+ columns: [{ id: 'col-1', prop: 'one-foo', type: 'string' }],
34
33
  },
35
34
  {
36
35
  id: '2',
37
36
  name: 'table 2',
38
- columns: [{ id: 'col-1', prop: 'two', type: FieldValueType.String }],
37
+ columns: [{ id: 'col-1', prop: 'two-foo', type: 'string' }],
39
38
  },
40
39
  ],
41
40
  };
42
41
 
43
- const functions: Pick<ColumnSettingsProps, 'onUpdate' | 'onDelete'> = {
42
+ const funcs: Pick<ColumnSettingsFormProps, 'onUpdate' | 'onDelete'> = {
44
43
  onUpdate: (...args: any) => console.log('onUpdate args', args),
45
44
  onDelete: (...args: any) => console.log('onDelete args', args),
46
45
  };
@@ -50,10 +49,10 @@ export const Default = {
50
49
  column: {
51
50
  id: 'test',
52
51
  label: 'test',
53
- } as ColumnDef,
52
+ } as ColumnProps,
54
53
 
55
54
  ...defs,
56
- ...functions,
55
+ ...funcs,
57
56
 
58
57
  context: {
59
58
  header: {
@@ -90,13 +89,11 @@ export const ReactiveSort = {
90
89
  column: {
91
90
  id: 'test',
92
91
  label: 'test',
93
- } as ColumnDef,
92
+ } as ColumnProps,
94
93
  context: {
95
94
  header: {
96
95
  column: {
97
96
  getCanSort: () => true,
98
- getIsSorted: () => sort,
99
- clearSorting: () => setSort(false),
100
97
  toggleSorting: (desc?: boolean) => {
101
98
  if (desc === undefined) {
102
99
  setSort(false);
@@ -106,6 +103,8 @@ export const ReactiveSort = {
106
103
  setSort('asc');
107
104
  }
108
105
  },
106
+ getIsSorted: () => sort,
107
+ clearSorting: () => setSort(false),
109
108
  getToggleSortingHandler: () => () => {
110
109
  if (sort === 'asc') {
111
110
  setSort('desc');
@@ -9,25 +9,22 @@ 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 { ColumnSettings } from './ColumnSettings';
12
+ import { ColumnSettingsForm } from './ColumnSettingsForm';
13
13
  import { useSortColumn } from '../../hooks';
14
- import { type TableDef, type ColumnDef } from '../../schema';
14
+ import { type TableDef, type ColumnProps } 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: ColumnDef;
20
+ column: ColumnProps;
21
21
  columnOrderable: boolean;
22
22
  columnPosition: 'start' | 'end' | undefined;
23
23
  onColumnReorder: (columnId: string, direction: 'left' | 'right') => void;
24
- onUpdate?: (id: string, column: ColumnDef) => void;
24
+ onUpdate?: (id: string, column: ColumnProps) => void;
25
25
  onDelete?: (id: string) => void;
26
26
  };
27
27
 
28
- /**
29
- * @deprecated
30
- */
31
28
  export const ColumnMenu = <TData extends RowData, TValue>({
32
29
  column,
33
30
  columnOrderable,
@@ -141,7 +138,7 @@ export const ColumnMenu = <TData extends RowData, TValue>({
141
138
  <Popover.Portal>
142
139
  <Popover.Content>
143
140
  <Popover.Viewport>
144
- <ColumnSettings {...props} column={column} onClose={() => setIsColumnSettingsOpen(false)} />
141
+ <ColumnSettingsForm {...props} column={column} onClose={() => setIsColumnSettingsOpen(false)} />
145
142
  </Popover.Viewport>
146
143
  <Popover.Arrow />
147
144
  </Popover.Content>
@@ -3,38 +3,25 @@
3
3
  //
4
4
 
5
5
  import '@dxos-theme';
6
-
7
6
  import React from 'react';
8
7
 
9
- import { FieldValueType } from '@dxos/schema';
10
- import { withTheme, withLayout } from '@dxos/storybook-utils';
8
+ import { withTheme } from '@dxos/storybook-utils';
11
9
 
12
- import { ColumnSettings, type ColumnSettingsProps } from './ColumnSettings';
10
+ import { ColumnSettingsForm, type ColumnSettingsFormProps } from './ColumnSettingsForm';
13
11
  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
- );
21
12
 
22
13
  export default {
23
- title: 'react-ui-table/ColumnSettings',
24
- component: ColumnSettings,
25
- decorators: [withTheme, withLayout()],
26
- parameters: {
27
- translations,
28
- },
29
- render: Story,
14
+ title: 'react-ui-table/ColumnSettingsForm',
15
+ component: ColumnSettingsForm,
16
+ decorators: [withTheme],
30
17
  };
31
18
 
32
19
  const sampleTableDef: TableDef = {
33
20
  id: '1',
34
21
  name: 'Sample Table',
35
22
  columns: [
36
- { id: 'col-1', prop: 'name', type: FieldValueType.String, label: 'Name' },
37
- { id: 'col-2', prop: 'age', type: FieldValueType.Number, label: 'Age', digits: 0 },
23
+ { id: 'col-1', prop: 'name', type: 'string', label: 'Name' },
24
+ { id: 'col-2', prop: 'age', type: 'number', label: 'Age', digits: 0 },
38
25
  ],
39
26
  };
40
27
 
@@ -44,17 +31,17 @@ const sampleTablesToReference: TableDef[] = [
44
31
  id: '2',
45
32
  name: 'Reference Table',
46
33
  columns: [
47
- { id: 'ref-col-1', prop: 'id', type: FieldValueType.String, label: 'ID' },
48
- { id: 'ref-col-2', prop: 'description', type: FieldValueType.String, label: 'Description' },
34
+ { id: 'ref-col-1', prop: 'id', type: 'string', label: 'ID' },
35
+ { id: 'ref-col-2', prop: 'description', type: 'string', label: 'Description' },
49
36
  ],
50
37
  },
51
38
  ];
52
39
 
53
- const defaultArgs: ColumnSettingsProps = {
40
+ const defaultArgs: ColumnSettingsFormProps = {
54
41
  column: {
55
42
  id: 'col-1',
56
43
  prop: 'name',
57
- type: FieldValueType.String,
44
+ type: 'string',
58
45
  label: 'Name',
59
46
  },
60
47
  tableDef: sampleTableDef,
@@ -74,7 +61,7 @@ export const NumberColumn = {
74
61
  column: {
75
62
  id: 'col-2',
76
63
  prop: 'age',
77
- type: FieldValueType.Number,
64
+ type: 'number',
78
65
  label: 'Age',
79
66
  digits: 0,
80
67
  },
@@ -87,7 +74,7 @@ export const ReferenceColumn = {
87
74
  column: {
88
75
  id: 'col-3',
89
76
  prop: 'reference',
90
- type: FieldValueType.Ref,
77
+ type: 'ref',
91
78
  label: 'Reference',
92
79
  refTable: '2',
93
80
  refProp: 'ref-col-1',
@@ -101,8 +88,17 @@ export const NewColumn = {
101
88
  column: {
102
89
  id: 'new-col',
103
90
  prop: '',
104
- type: FieldValueType.String,
91
+ type: 'string',
105
92
  label: '',
106
93
  },
107
94
  },
108
95
  };
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;
@@ -1,39 +1,31 @@
1
1
  //
2
2
  // Copyright 2024 DXOS.org
3
3
  //
4
-
5
4
  import React, { useRef, useState } from 'react';
6
5
 
7
6
  import { Button, Input, Select, useTranslation } from '@dxos/react-ui';
8
- import { FieldValueTypes, type FieldValueType } from '@dxos/schema';
9
7
  import { safeParseInt } from '@dxos/util';
10
8
 
11
- import { type TableDef, type ColumnDef } from '../../schema';
9
+ import { type TableDef, type ColumnProps, type ColumnType } from '../../schema';
12
10
  import { translationKey } from '../../translations';
13
11
 
14
- export type ColumnSettingsProps = {
15
- column: ColumnDef;
12
+ export type ColumnSettingsFormProps = {
13
+ column: ColumnProps;
16
14
  tableDef: TableDef;
17
- // TODO(burdon): Rename.
18
15
  tablesToReference: TableDef[];
19
- onUpdate?: (id: string, column: ColumnDef) => void;
20
- onDelete?: (id: string) => void;
16
+ onUpdate?: ((id: string, column: ColumnProps) => void) | undefined;
17
+ onDelete?: ((id: string) => void) | undefined;
21
18
  onClose?: () => void;
22
19
  };
23
20
 
24
- /**
25
- * @deprecated
26
- */
27
- export const ColumnSettings = ({
21
+ export const ColumnSettingsForm = ({
28
22
  column,
29
23
  tableDef,
30
24
  tablesToReference,
31
25
  onUpdate,
32
26
  onDelete,
33
27
  onClose,
34
- }: ColumnSettingsProps) => {
35
- const { t } = useTranslation(translationKey);
36
- const propRef = useRef<HTMLInputElement>(null);
28
+ }: ColumnSettingsFormProps) => {
37
29
  const [formState, setFormState] = useState({
38
30
  prop: column.id,
39
31
  refTable: column.refTable,
@@ -43,6 +35,9 @@ export const ColumnSettings = ({
43
35
  digits: String(column.digits ?? '0'),
44
36
  });
45
37
 
38
+ const propRef = useRef<HTMLInputElement>(null);
39
+ const { t } = useTranslation(translationKey);
40
+
46
41
  const handleSave = () => {
47
42
  const { prop, refTable, refProp, type, label, digits } = formState;
48
43
 
@@ -67,7 +62,7 @@ export const ColumnSettings = ({
67
62
  id: prop, // TODO(burdon): Make unique.
68
63
  prop,
69
64
  label,
70
- type: type as FieldValueType,
65
+ type: type as ColumnProps['type'],
71
66
  refTable,
72
67
  refProp,
73
68
  digits: safeParseInt(digits),
@@ -80,10 +75,9 @@ export const ColumnSettings = ({
80
75
  onClose?.();
81
76
  };
82
77
 
83
- // TODO(burdon): Standardize dialog/popup.
84
78
  return (
85
- <div className='flex flex-col w-full gap-4'>
86
- <div className='flex flex-col gap-2'>
79
+ <div className='p-1 space-y-2'>
80
+ <div className='space-y-1'>
87
81
  <Input.Root>
88
82
  <Input.Label>{t('column label label')}</Input.Label>
89
83
  <Input.TextInput
@@ -94,7 +88,8 @@ export const ColumnSettings = ({
94
88
  data-testid='table.column-settings.label'
95
89
  />
96
90
  </Input.Root>
97
-
91
+ </div>
92
+ <div className='space-y-1'>
98
93
  <Input.Root>
99
94
  <Input.Label>{t('property key label')}</Input.Label>
100
95
  <Input.TextInput
@@ -106,7 +101,8 @@ export const ColumnSettings = ({
106
101
  }
107
102
  />
108
103
  </Input.Root>
109
-
104
+ </div>
105
+ <div className='space-y-1'>
110
106
  <Input.Root>
111
107
  <Input.Label>{t('column type label')}</Input.Label>
112
108
  <Select.Root
@@ -117,7 +113,7 @@ export const ColumnSettings = ({
117
113
  <Select.Portal>
118
114
  <Select.Content>
119
115
  <Select.Viewport>
120
- {FieldValueTypes.map((type) => (
116
+ {(['number', 'boolean', 'string', 'ref'] as ColumnType[]).map((type) => (
121
117
  <Select.Option key={type} value={type}>
122
118
  {t(`${type} column type label`)}
123
119
  </Select.Option>
@@ -127,8 +123,9 @@ export const ColumnSettings = ({
127
123
  </Select.Portal>
128
124
  </Select.Root>
129
125
  </Input.Root>
130
-
131
- {formState.type === 'number' && (
126
+ </div>
127
+ {formState.type === 'number' && (
128
+ <div className='space-y-1'>
132
129
  <Input.Root>
133
130
  <Input.Label>{t('digits label')}</Input.Label>
134
131
  <Input.TextInput
@@ -136,10 +133,12 @@ export const ColumnSettings = ({
136
133
  onChange={(event) => setFormState((prevState) => ({ ...prevState, digits: event.target.value }))}
137
134
  />
138
135
  </Input.Root>
139
- )}
136
+ </div>
137
+ )}
140
138
 
141
- {formState.type === 'ref' && (
142
- <>
139
+ {formState.type === 'ref' && (
140
+ <>
141
+ <div className='space-y-1'>
143
142
  <Input.Root>
144
143
  <Input.Label>Table</Input.Label>
145
144
  <Select.Root
@@ -162,8 +161,9 @@ export const ColumnSettings = ({
162
161
  </Select.Portal>
163
162
  </Select.Root>
164
163
  </Input.Root>
165
-
166
- {formState.refTable && (
164
+ </div>
165
+ {formState.refTable && (
166
+ <div className='space-y-1'>
167
167
  <Input.Root>
168
168
  <Input.Label>Table property</Input.Label>
169
169
  <Select.Root
@@ -186,21 +186,20 @@ export const ColumnSettings = ({
186
186
  </Select.Portal>
187
187
  </Select.Root>
188
188
  </Input.Root>
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>
189
+ </div>
190
+ )}
191
+ </>
192
+ )}
193
+
194
+ <div role='none' className='h-1' />
195
+
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>
204
203
  </div>
205
204
  </div>
206
205
  );
@@ -3,4 +3,4 @@
3
3
  //
4
4
 
5
5
  export * from './ColumnMenu';
6
- export * from './ColumnSettings';
6
+ export * from './ColumnSettingsForm';
@@ -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 { registerSignalRuntime } from '@dxos/echo-signals/react';
11
12
  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 { withSignals, withTheme } from '@dxos/storybook-utils';
15
+ import { withTheme } from '@dxos/storybook-utils';
16
16
  import { range } from '@dxos/util';
17
17
 
18
18
  import { Table } from './Table';
@@ -406,117 +406,105 @@ export const TenThousandRows = {
406
406
  },
407
407
  };
408
408
 
409
- // TODO(burdon): Warning: Encountered two children with the same key.
409
+ registerSignalRuntime();
410
+ const state = create({ items: createItems(10) });
410
411
 
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) {
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) {
437
438
  return;
438
439
  }
439
440
 
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);
441
+ const interval = setInterval(() => {
442
+ if (state.items.length === 0) {
443
+ return;
444
+ }
446
445
 
447
- return () => clearInterval(i);
448
- }, [periodicMutations, mutationInterval, state.items]);
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);
449
452
 
450
- useEffect(() => {
451
- if (!periodicInsertions) {
452
- return;
453
- }
453
+ return () => clearInterval(interval);
454
+ }, [periodicMutations, mutationInterval, state.items]);
454
455
 
455
- const i = setInterval(() => {
456
- log('inserting...');
457
- state.items.push(createItems(1)[0]);
458
- }, insertionInterval);
456
+ useEffect(() => {
457
+ if (!periodicInsertions) {
458
+ return;
459
+ }
459
460
 
460
- return () => clearInterval(i);
461
- }, [periodicInsertions, insertionInterval, state.items]);
461
+ const interval = setInterval(() => {
462
+ console.log('Inserting...');
463
+ state.items.push(createItems(1)[0]);
464
+ }, insertionInterval);
462
465
 
463
- useEffect(() => {
464
- if (!periodicDeletions) {
465
- return;
466
- }
466
+ return () => clearInterval(interval);
467
+ }, [periodicInsertions, insertionInterval, state.items]);
467
468
 
468
- const i = setInterval(() => {
469
- if (state.items.length === 0) {
469
+ useEffect(() => {
470
+ if (!periodicDeletions) {
470
471
  return;
471
472
  }
472
473
 
473
- log('deleting...');
474
- const randomIndex = Math.floor(Math.random() * state.items.length);
475
- state.items.splice(randomIndex, 1);
476
- }, deletionInterval);
474
+ const interval = setInterval(() => {
475
+ if (state.items.length === 0) {
476
+ return;
477
+ }
477
478
 
478
- return () => clearInterval(i);
479
- }, [periodicDeletions, deletionInterval, state.items]);
479
+ console.log('Deleting');
480
480
 
481
- const onUpdate = useCallback((...args: any[]) => {}, []);
482
- const columns = useMemo(() => makeColumns(onUpdate), []);
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);
483
485
 
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
- };
486
+ return () => clearInterval(interval);
487
+ }, [periodicDeletions, deletionInterval, state.items]);
502
488
 
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' },
489
+ const onUpdate = useCallback((...args: any[]) => {}, []);
490
+ const columns = useMemo(() => makeColumns(onUpdate), []);
491
+
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
+ );
511
509
  },
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,
522
510
  };