@dxos/app-graph 0.8.3 → 0.8.4-main.1068cf700f

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 (47) hide show
  1. package/dist/lib/browser/index.mjs +1135 -616
  2. package/dist/lib/browser/index.mjs.map +4 -4
  3. package/dist/lib/browser/meta.json +1 -1
  4. package/dist/lib/node-esm/index.mjs +1134 -616
  5. package/dist/lib/node-esm/index.mjs.map +4 -4
  6. package/dist/lib/node-esm/meta.json +1 -1
  7. package/dist/types/src/atoms.d.ts +8 -0
  8. package/dist/types/src/atoms.d.ts.map +1 -0
  9. package/dist/types/src/graph-builder.d.ts +113 -60
  10. package/dist/types/src/graph-builder.d.ts.map +1 -1
  11. package/dist/types/src/graph.d.ts +183 -209
  12. package/dist/types/src/graph.d.ts.map +1 -1
  13. package/dist/types/src/index.d.ts +6 -3
  14. package/dist/types/src/index.d.ts.map +1 -1
  15. package/dist/types/src/node-matcher.d.ts +218 -0
  16. package/dist/types/src/node-matcher.d.ts.map +1 -0
  17. package/dist/types/src/node-matcher.test.d.ts +2 -0
  18. package/dist/types/src/node-matcher.test.d.ts.map +1 -0
  19. package/dist/types/src/node.d.ts +32 -3
  20. package/dist/types/src/node.d.ts.map +1 -1
  21. package/dist/types/src/stories/EchoGraph.stories.d.ts +6 -13
  22. package/dist/types/src/stories/EchoGraph.stories.d.ts.map +1 -1
  23. package/dist/types/tsconfig.tsbuildinfo +1 -1
  24. package/package.json +37 -37
  25. package/src/atoms.ts +25 -0
  26. package/src/graph-builder.test.ts +571 -97
  27. package/src/graph-builder.ts +600 -258
  28. package/src/graph.test.ts +300 -107
  29. package/src/graph.ts +971 -400
  30. package/src/index.ts +9 -3
  31. package/src/node-matcher.test.ts +301 -0
  32. package/src/node-matcher.ts +284 -0
  33. package/src/node.ts +40 -5
  34. package/src/stories/EchoGraph.stories.tsx +128 -233
  35. package/src/stories/Tree.tsx +2 -2
  36. package/dist/lib/node/index.cjs +0 -816
  37. package/dist/lib/node/index.cjs.map +0 -7
  38. package/dist/lib/node/meta.json +0 -1
  39. package/dist/types/src/experimental/graph-projections.test.d.ts +0 -25
  40. package/dist/types/src/experimental/graph-projections.test.d.ts.map +0 -1
  41. package/dist/types/src/signals-integration.test.d.ts +0 -2
  42. package/dist/types/src/signals-integration.test.d.ts.map +0 -1
  43. package/dist/types/src/testing.d.ts +0 -5
  44. package/dist/types/src/testing.d.ts.map +0 -1
  45. package/src/experimental/graph-projections.test.ts +0 -56
  46. package/src/signals-integration.test.ts +0 -218
  47. package/src/testing.ts +0 -20
@@ -2,40 +2,31 @@
2
2
  // Copyright 2023 DXOS.org
3
3
  //
4
4
 
5
- import '@dxos-theme';
6
-
7
- import { type Registry, RegistryContext, Rx, useRxValue } from '@effect-rx/rx-react';
8
- import { Pause, Play, Plus, Timer } from '@phosphor-icons/react';
9
- import { Option, pipe } from 'effect';
10
- import React, { type PropsWithChildren, useCallback, useContext, useEffect, useMemo, useState } from 'react';
11
-
12
- import {
13
- live,
14
- isSpace,
15
- Query,
16
- type QueryResult,
17
- type Space,
18
- SpaceState,
19
- Expando,
20
- type Live,
21
- Filter,
22
- } from '@dxos/client/echo';
23
- import { Obj, Type } from '@dxos/echo';
5
+ import { Atom, type Registry, RegistryContext, useAtomValue } from '@effect-atom/atom-react';
6
+ import { type Meta, type StoryObj } from '@storybook/react-vite';
7
+ import * as Function from 'effect/Function';
8
+ import * as Option from 'effect/Option';
9
+ import React, { type PropsWithChildren, useCallback, useContext, useEffect, useMemo, useRef, useState } from 'react';
10
+
11
+ import { Filter, type Space, SpaceState, isSpace } from '@dxos/client/echo';
12
+ import { Obj, Query } from '@dxos/echo';
13
+ import { TestSchema } from '@dxos/echo/testing';
14
+ import { AtomObj, AtomQuery } from '@dxos/echo-atom';
24
15
  import { faker } from '@dxos/random';
25
16
  import { type Client, useClient } from '@dxos/react-client';
26
17
  import { withClientProvider } from '@dxos/react-client/testing';
27
- import { Button, Input, Select } from '@dxos/react-ui';
18
+ import { Icon, IconButton, Input, Select } from '@dxos/react-ui';
19
+ import { withTheme } from '@dxos/react-ui/testing';
28
20
  import { Path, Tree } from '@dxos/react-ui-list';
29
- import { Tabs } from '@dxos/react-ui-tabs';
30
- import { getSize, mx } from '@dxos/react-ui-theme';
31
- import { withTheme } from '@dxos/storybook-utils';
21
+ import { getSize, mx } from '@dxos/ui-theme';
32
22
  import { byPosition, isNonNullable, safeParseInt } from '@dxos/util';
33
23
 
24
+ import * as CreateAtom from '../atoms';
25
+ import * as Graph from '../graph';
26
+ import * as GraphBuilder from '../graph-builder';
27
+ import * as Node from '../node';
28
+
34
29
  import { JsonTree } from './Tree';
35
- import { type ExpandableGraph, ROOT_ID } from '../graph';
36
- import { GraphBuilder, createExtension, rxFromObservable, rxFromSignal } from '../graph-builder';
37
- import { type Node } from '../node';
38
- import { rxFromQuery } from '../testing';
39
30
 
40
31
  const DEFAULT_PERIOD = 500;
41
32
 
@@ -57,43 +48,44 @@ const actionWeights = {
57
48
  [Action.RENAME_OBJECT]: 4,
58
49
  };
59
50
 
60
- const createGraph = (client: Client, registry: Registry.Registry): ExpandableGraph => {
61
- const spaceBuilderExtension = createExtension({
51
+ const createGraph = (client: Client, registry: Registry.Registry): Graph.ExpandableGraph => {
52
+ const spaceBuilderExtension = GraphBuilder.createExtensionRaw({
62
53
  id: 'space',
63
54
  connector: (node) =>
64
- Rx.make((get) =>
65
- pipe(
55
+ Atom.make((get) =>
56
+ Function.pipe(
66
57
  get(node),
67
- Option.flatMap((node) => (node.id === ROOT_ID ? Option.some(node) : Option.none())),
58
+ Option.flatMap((node) => (node.id === Node.RootId ? Option.some(node) : Option.none())),
68
59
  Option.map(() => {
69
- const spaces = get(rxFromObservable(client.spaces)) ?? [];
60
+ const spaces = get(CreateAtom.fromObservable(client.spaces)) ?? [];
70
61
  return spaces
71
- .filter((space) => get(rxFromObservable(space.state)) === SpaceState.SPACE_READY)
72
- .map((space) => ({
73
- id: space.id,
74
- type: 'dxos.org/type/Space',
75
- properties: { label: get(rxFromSignal(() => space.properties.name)) },
76
- data: space,
77
- }));
62
+ .filter((space: any) => get(CreateAtom.fromObservable(space.state)) === SpaceState.SPACE_READY)
63
+ .map((space) => {
64
+ const propertiesSnapshot = get(AtomObj.make(space.properties));
65
+ return {
66
+ id: space.id,
67
+ type: 'dxos.org/type/Space',
68
+ properties: {
69
+ label: propertiesSnapshot.name,
70
+ },
71
+ data: space,
72
+ };
73
+ });
78
74
  }),
79
75
  Option.getOrElse(() => []),
80
76
  ),
81
77
  ),
82
78
  });
83
79
 
84
- const objectBuilderExtension = createExtension({
80
+ const objectBuilderExtension = GraphBuilder.createExtensionRaw({
85
81
  id: 'object',
86
82
  connector: (node) => {
87
- let query: QueryResult<Live<Expando>> | undefined;
88
- return Rx.make((get) =>
89
- pipe(
83
+ return Atom.make((get) =>
84
+ Function.pipe(
90
85
  get(node),
91
86
  Option.flatMap((node) => (isSpace(node.data) ? Option.some(node.data) : Option.none())),
92
87
  Option.map((space) => {
93
- if (!query) {
94
- query = space.db.query(Query.type(Expando, { type: 'test' }));
95
- }
96
- const objects = get(rxFromQuery(query));
88
+ const objects = get(AtomQuery.make(space.db, Query.type(TestSchema.Expando, { type: 'test' })));
97
89
  return objects.map((object) => ({
98
90
  id: object.id,
99
91
  type: 'dxos.org/type/test',
@@ -107,15 +99,15 @@ const createGraph = (client: Client, registry: Registry.Registry): ExpandableGra
107
99
  },
108
100
  });
109
101
 
110
- const graph = new GraphBuilder({ registry })
111
- .addExtension(spaceBuilderExtension)
112
- .addExtension(objectBuilderExtension).graph;
102
+ const builder = GraphBuilder.make({ registry });
103
+ GraphBuilder.addExtension(builder, spaceBuilderExtension);
104
+ GraphBuilder.addExtension(builder, objectBuilderExtension);
105
+ const graph = builder.graph;
113
106
  graph.onNodeChanged.on(({ id }) => {
114
- graph.expand(id);
107
+ Graph.expand(graph, id);
115
108
  });
116
- graph.expand(ROOT_ID);
109
+ Graph.expand(graph, Node.RootId);
117
110
  (window as any).graph = graph;
118
-
119
111
  return graph;
120
112
  };
121
113
 
@@ -135,9 +127,9 @@ const getRandomSpace = (client: Client): Space | undefined => {
135
127
  const getSpaceWithObjects = async (client: Client): Promise<Space | undefined> => {
136
128
  const readySpaces = client.spaces.get().filter((space) => space.state.get() === SpaceState.SPACE_READY);
137
129
  const spaceQueries = await Promise.all(
138
- readySpaces.map((space) => space.db.query(Filter.type(Expando, { type: 'test' })).run()),
130
+ readySpaces.map((space) => space.db.query(Filter.type(TestSchema.Expando, { type: 'test' })).run()),
139
131
  );
140
- const spaces = readySpaces.filter((space, index) => spaceQueries[index].objects.length > 0);
132
+ const spaces = readySpaces.filter((space, index) => spaceQueries[index].length > 0);
141
133
  return spaces[Math.floor(Math.random() * spaces.length)];
142
134
  };
143
135
 
@@ -154,19 +146,26 @@ const runAction = async (client: Client, action: Action) => {
154
146
  case Action.RENAME_SPACE: {
155
147
  const space = getRandomSpace(client);
156
148
  if (space) {
157
- space.properties.name = faker.commerce.productName();
149
+ Obj.change(space.properties, (p) => {
150
+ p.name = faker.commerce.productName();
151
+ });
158
152
  }
159
153
  break;
160
154
  }
161
155
 
162
156
  case Action.ADD_OBJECT:
163
- getRandomSpace(client)?.db.add(Obj.make(Type.Expando, { type: 'test', name: faker.commerce.productName() }));
157
+ getRandomSpace(client)?.db.add(
158
+ Obj.make(TestSchema.Expando, {
159
+ type: 'test',
160
+ name: faker.commerce.productName(),
161
+ }),
162
+ );
164
163
  break;
165
164
 
166
165
  case Action.REMOVE_OBJECT: {
167
166
  const space = await getSpaceWithObjects(client);
168
167
  if (space) {
169
- const { objects } = await space.db.query(Filter.type(Expando, { type: 'test' })).run();
168
+ const objects = await space.db.query(Filter.type(TestSchema.Expando, { type: 'test' })).run();
170
169
  space.db.remove(objects[Math.floor(Math.random() * objects.length)]);
171
170
  }
172
171
  break;
@@ -175,8 +174,11 @@ const runAction = async (client: Client, action: Action) => {
175
174
  case Action.RENAME_OBJECT: {
176
175
  const space = await getSpaceWithObjects(client);
177
176
  if (space) {
178
- const { objects } = await space.db.query(Filter.type(Expando, { type: 'test' })).run();
179
- objects[Math.floor(Math.random() * objects.length)].name = faker.commerce.productName();
177
+ const objects = await space.db.query(Filter.type(TestSchema.Expando, { type: 'test' })).run();
178
+ const object = objects[Math.floor(Math.random() * objects.length)];
179
+ Obj.change(object, (o) => {
180
+ o.name = faker.commerce.productName();
181
+ });
180
182
  }
181
183
  break;
182
184
  }
@@ -205,23 +207,25 @@ const Controls = ({ children }: PropsWithChildren) => {
205
207
  return (
206
208
  <>
207
209
  <div className='flex shrink-0 p-2 space-x-2'>
208
- <Button onClick={() => setGenerating((generating) => !generating)}>{generating ? <Pause /> : <Play />}</Button>
210
+ <IconButton
211
+ icon={generating ? 'ph--pause--regular' : 'ph--play--regular'}
212
+ label={generating ? 'Pause' : 'Play'}
213
+ onClick={() => setGenerating((generating) => !generating)}
214
+ />
209
215
  <div className='relative' title='mutation period'>
210
216
  <Input.Root>
211
217
  <Input.TextInput
212
218
  autoComplete='off'
213
219
  size={5}
214
- classNames='w-[100px] text-right pie-[22px]'
220
+ classNames='is-[100px] text-right pie-[22px]'
215
221
  placeholder='Interval'
216
222
  value={actionInterval}
217
223
  onChange={({ target: { value } }) => setActionInterval(value)}
218
224
  />
219
225
  </Input.Root>
220
- <Timer className={mx('absolute inline-end-1 block-start-1 mt-[6px]', getSize(3))} />
226
+ <Icon icon='ph--timer--regular' classNames={mx('absolute inline-end-1 block-start-1 mt-[6px]', getSize(3))} />
221
227
  </div>
222
- <Button onClick={() => action && runAction(client, action)}>
223
- <Plus />
224
- </Button>
228
+ <IconButton icon='ph--plus--regular' label='Add' onClick={() => action && runAction(client, action)} />
225
229
  <Select.Root value={action?.toString()} onValueChange={(action) => setAction(action as unknown as Action)}>
226
230
  <Select.TriggerButton placeholder='Select value' />
227
231
  <Select.Portal>
@@ -245,26 +249,30 @@ const Controls = ({ children }: PropsWithChildren) => {
245
249
  );
246
250
  };
247
251
 
248
- export default {
252
+ const meta = {
249
253
  title: 'sdk/app-graph/EchoGraph',
250
254
  decorators: [
251
- withTheme,
255
+ withTheme(),
252
256
  withClientProvider({
253
257
  createIdentity: true,
254
- onIdentityCreated: async ({ client }) => {
258
+ onCreateIdentity: async ({ client }) => {
255
259
  await client.spaces.create();
256
260
  await client.spaces.create();
257
261
  },
258
262
  }),
259
263
  ],
260
- };
264
+ } satisfies Meta;
265
+
266
+ export default meta;
261
267
 
262
- export const JsonView = {
268
+ type Story = StoryObj<typeof meta>;
269
+
270
+ export const JsonView: Story = {
263
271
  render: () => {
264
272
  const client = useClient();
265
273
  const registry = useContext(RegistryContext);
266
274
  const graph = useMemo(() => createGraph(client, registry), [client, registry]);
267
- const data = useRxValue(graph.json());
275
+ const data = useAtomValue(graph.json());
268
276
 
269
277
  return (
270
278
  <>
@@ -275,31 +283,42 @@ export const JsonView = {
275
283
  },
276
284
  };
277
285
 
278
- export const TreeView = {
286
+ export const TreeView: Story = {
279
287
  render: () => {
280
288
  const client = useClient();
281
289
  const registry = useContext(RegistryContext);
282
290
  const graph = useMemo(() => createGraph(client, registry), [client, registry]);
283
- const state = useMemo(() => new Map<string, Live<{ open: boolean; current: boolean }>>(), []);
291
+ const stateRef = useRef(new Map<string, Atom.Writable<{ open: boolean; current: boolean }>>());
292
+
293
+ const getOrCreateState = useMemo(
294
+ () => (path: string) => {
295
+ let atom = stateRef.current.get(path);
296
+ if (!atom) {
297
+ atom = Atom.make({ open: true, current: false }).pipe(Atom.keepAlive);
298
+ stateRef.current.set(path, atom);
299
+ }
300
+ return atom;
301
+ },
302
+ [],
303
+ );
284
304
 
285
305
  const useItems = useCallback(
286
- (node?: Node, options?: { disposition?: string; sort?: boolean }) => {
287
- const connections = useRxValue(graph.connections(node?.id ?? ROOT_ID));
306
+ (node?: Node.Node, options?: { disposition?: string; sort?: boolean }) => {
307
+ const connections = useAtomValue(graph.connections(node?.id ?? Node.RootId));
288
308
  return options?.sort ? connections.toSorted((a, b) => byPosition(a.properties, b.properties)) : connections;
289
309
  },
290
310
  [graph],
291
311
  );
292
312
 
293
313
  const getProps = useCallback(
294
- (node: Node, path: string[]) => {
295
- const children = graph
296
- .getConnections(node.id, 'outbound')
314
+ (node: Node.Node, path: string[]) => {
315
+ const children = Graph.getConnections(graph, node.id, 'outbound')
297
316
  .map((n) => {
298
317
  // Break cycles.
299
318
  const nextPath = [...path, node.id];
300
- return nextPath.includes(n.id) ? undefined : (n as Node);
319
+ return nextPath.includes(n.id) ? undefined : (n as Node.Node);
301
320
  })
302
- .filter(isNonNullable) as Node[];
321
+ .filter(isNonNullable) as Node.Node[];
303
322
  const parentOf =
304
323
  children.length > 0 ? children.map(({ id }) => id) : node.properties.role === 'branch' ? [] : undefined;
305
324
  return {
@@ -312,59 +331,54 @@ export const TreeView = {
312
331
  [graph],
313
332
  );
314
333
 
315
- const isOpen = useCallback(
316
- (_path: string[]) => {
317
- const path = Path.create(..._path);
318
- const object = state.get(path) ?? live({ open: true, current: false });
319
- if (!state.has(path)) {
320
- state.set(path, object);
321
- }
334
+ // Hook that subscribes to item state via Atom.
335
+ const useItemState = (_path: string[]) => {
336
+ const path = useMemo(() => Path.create(..._path), [_path.join('~')]);
337
+ const atom = getOrCreateState(path);
338
+ return useAtomValue(atom);
339
+ };
322
340
 
323
- return object.open;
324
- },
325
- [state],
326
- );
327
-
328
- const isCurrent = useCallback(
329
- (_path: string[]) => {
330
- const path = Path.create(..._path);
331
- const object = state.get(path) ?? live({ open: false, current: false });
332
- if (!state.has(path)) {
333
- state.set(path, object);
334
- }
341
+ const useIsOpen = (_path: string[]) => {
342
+ return useItemState(_path).open;
343
+ };
335
344
 
336
- return object.current;
337
- },
338
- [state],
339
- );
345
+ const useIsCurrent = (_path: string[]) => {
346
+ return useItemState(_path).current;
347
+ };
340
348
 
341
349
  const onOpenChange = useCallback(
342
350
  ({ path: _path, open }: { path: string[]; open: boolean }) => {
343
351
  const path = Path.create(..._path);
344
- const object = state.get(path);
345
- object!.open = open;
352
+ const atom = stateRef.current.get(path);
353
+ if (atom) {
354
+ const prev = registry.get(atom);
355
+ registry.set(atom, { ...prev, open });
356
+ }
346
357
  },
347
- [state],
358
+ [registry],
348
359
  );
349
360
 
350
361
  const onSelect = useCallback(
351
362
  ({ path: _path, current }: { path: string[]; current: boolean }) => {
352
363
  const path = Path.create(..._path);
353
- const object = state.get(path);
354
- object!.current = current;
364
+ const atom = stateRef.current.get(path);
365
+ if (atom) {
366
+ const prev = registry.get(atom);
367
+ registry.set(atom, { ...prev, current });
368
+ }
355
369
  },
356
- [state],
370
+ [registry],
357
371
  );
358
372
 
359
373
  return (
360
374
  <>
361
375
  <Controls />
362
376
  <Tree
363
- id={ROOT_ID}
377
+ id={Node.RootId}
364
378
  useItems={useItems}
365
379
  getProps={getProps}
366
- isOpen={isOpen}
367
- isCurrent={isCurrent}
380
+ useIsOpen={useIsOpen}
381
+ useIsCurrent={useIsCurrent}
368
382
  onOpenChange={onOpenChange}
369
383
  onSelect={onSelect}
370
384
  />
@@ -372,122 +386,3 @@ export const TreeView = {
372
386
  );
373
387
  },
374
388
  };
375
-
376
- // TODO(wittjosiah): Remove.
377
- export const TabTreeView = {
378
- render: () => {
379
- const client = useClient();
380
- const registry = useContext(RegistryContext);
381
- const graph = useMemo(() => createGraph(client, registry), [client, registry]);
382
- const state = useMemo(() => new Map<string, Live<{ open: boolean; current: boolean }>>(), []);
383
-
384
- const useItems = useCallback(
385
- (node?: Node, options?: { disposition?: string; sort?: boolean }) => {
386
- const connections = useRxValue(graph.connections(node?.id ?? ROOT_ID));
387
- return options?.sort ? connections.toSorted((a, b) => byPosition(a.properties, b.properties)) : connections;
388
- },
389
- [graph],
390
- );
391
-
392
- const getProps = useCallback(
393
- (node: Node, path: string[]) => {
394
- const children = graph
395
- .getConnections(node.id, 'outbound')
396
- .map((n) => {
397
- // Break cycles.
398
- const nextPath = [...path, node.id];
399
- return nextPath.includes(n.id) ? undefined : (n as Node);
400
- })
401
- .filter(isNonNullable) as Node[];
402
- const parentOf =
403
- children.length > 0 ? children.map(({ id }) => id) : node.properties.role === 'branch' ? [] : undefined;
404
- return {
405
- id: node.id,
406
- label: node.id,
407
- icon: node.type === 'dxos.org/type/Space' ? 'ph--planet--regular' : 'ph--placeholder--regular',
408
- parentOf,
409
- };
410
- },
411
- [graph],
412
- );
413
-
414
- const isOpen = useCallback(
415
- (_path: string[]) => {
416
- const path = Path.create(..._path);
417
- const object = state.get(path) ?? live({ open: true, current: false });
418
- if (!state.has(path)) {
419
- state.set(path, object);
420
- }
421
-
422
- return object.open;
423
- },
424
- [state],
425
- );
426
-
427
- const isCurrent = useCallback(
428
- (_path: string[]) => {
429
- const path = Path.create(..._path);
430
- const object = state.get(path) ?? live({ open: false, current: false });
431
- if (!state.has(path)) {
432
- state.set(path, object);
433
- }
434
-
435
- return object.current;
436
- },
437
- [state],
438
- );
439
-
440
- const onOpenChange = useCallback(
441
- ({ path: _path, open }: { path: string[]; open: boolean }) => {
442
- const path = Path.create(..._path);
443
- const object = state.get(path);
444
- object!.open = open;
445
- },
446
- [state],
447
- );
448
-
449
- const onSelect = useCallback(
450
- ({ path: _path, current }: { path: string[]; current: boolean }) => {
451
- const path = Path.create(..._path);
452
- const object = state.get(path);
453
- object!.current = current;
454
- },
455
- [state],
456
- );
457
-
458
- const spaces = useItems(graph.root);
459
-
460
- return (
461
- <>
462
- <Controls />
463
- <Tabs.Root defaultValue={spaces[0].id}>
464
- <Tabs.Tablist>
465
- {spaces.map((space) => {
466
- return (
467
- <Tabs.Tab key={space.id} value={space.id}>
468
- {space.id}
469
- </Tabs.Tab>
470
- );
471
- })}
472
- </Tabs.Tablist>
473
- {spaces.map((space) => {
474
- return (
475
- <Tabs.Tabpanel key={space.id} value={space.id}>
476
- <Tree
477
- id={space.id}
478
- root={space}
479
- useItems={useItems}
480
- getProps={getProps}
481
- isOpen={isOpen}
482
- isCurrent={isCurrent}
483
- onOpenChange={onOpenChange}
484
- onSelect={onSelect}
485
- />
486
- </Tabs.Tabpanel>
487
- );
488
- })}
489
- </Tabs.Root>
490
- </>
491
- );
492
- },
493
- };
@@ -4,7 +4,7 @@
4
4
 
5
5
  import React, { type FC, type HTMLAttributes, useState } from 'react';
6
6
 
7
- import { mx } from '@dxos/react-ui-theme';
7
+ import { mx } from '@dxos/ui-theme';
8
8
 
9
9
  // TODO(burdon): Copied form devtools.
10
10
 
@@ -72,7 +72,7 @@ const Scalar: FC<{ value: any }> = ({ value }) => {
72
72
 
73
73
  const Box: FC<HTMLAttributes<HTMLDivElement>> = ({ children, className, ...props }) => {
74
74
  return (
75
- <div className={mx('flex px-2 border border-l-0 font-mono truncate', className)} {...props}>
75
+ <div className={mx('flex pli-2 border border-l-0 font-mono truncate', className)} {...props}>
76
76
  {children}
77
77
  </div>
78
78
  );