@dxos/react-ui-canvas-compute 0.13.0 → 0.14.0

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 (244) hide show
  1. package/dist/lib/chunk-types.mjs +142 -0
  2. package/dist/lib/chunk-types.mjs.map +1 -0
  3. package/dist/lib/index.mjs +526 -430
  4. package/dist/lib/index.mjs.map +1 -1
  5. package/dist/lib/types.mjs +2 -0
  6. package/dist/types/src/graph/controller.d.ts +1 -1
  7. package/dist/types/src/graph/controller.d.ts.map +1 -1
  8. package/dist/types/src/hooks/compute-context.d.ts +5 -4
  9. package/dist/types/src/hooks/compute-context.d.ts.map +1 -1
  10. package/dist/types/src/hooks/index.d.ts +0 -1
  11. package/dist/types/src/hooks/index.d.ts.map +1 -1
  12. package/dist/types/src/hooks/useGraphMonitor.d.ts +18 -1
  13. package/dist/types/src/hooks/useGraphMonitor.d.ts.map +1 -1
  14. package/dist/types/src/index.d.ts +1 -1
  15. package/dist/types/src/index.d.ts.map +1 -1
  16. package/dist/types/src/registry.d.ts +5 -8
  17. package/dist/types/src/registry.d.ts.map +1 -1
  18. package/dist/types/src/scene/compute.stories.d.ts.map +1 -1
  19. package/dist/types/src/scene/echo-store.d.ts +1 -1
  20. package/dist/types/src/scene/echo-store.d.ts.map +1 -1
  21. package/dist/types/src/scene/index.d.ts +0 -3
  22. package/dist/types/src/scene/index.d.ts.map +1 -1
  23. package/dist/types/src/scene/projection.d.ts.map +1 -1
  24. package/dist/types/src/scene/scene.d.ts +2 -2
  25. package/dist/types/src/scene/scene.d.ts.map +1 -1
  26. package/dist/types/src/shapes/Append.d.ts +2 -2
  27. package/dist/types/src/shapes/Append.d.ts.map +1 -1
  28. package/dist/types/src/shapes/Array.d.ts +3 -3
  29. package/dist/types/src/shapes/Array.d.ts.map +1 -1
  30. package/dist/types/src/shapes/Audio.d.ts +2 -2
  31. package/dist/types/src/shapes/Audio.d.ts.map +1 -1
  32. package/dist/types/src/shapes/Beacon.d.ts +2 -2
  33. package/dist/types/src/shapes/Beacon.d.ts.map +1 -1
  34. package/dist/types/src/shapes/Boolean.d.ts +4 -52
  35. package/dist/types/src/shapes/Boolean.d.ts.map +1 -1
  36. package/dist/types/src/shapes/Chat.d.ts +3 -3
  37. package/dist/types/src/shapes/Chat.d.ts.map +1 -1
  38. package/dist/types/src/shapes/Constant.d.ts +3 -4
  39. package/dist/types/src/shapes/Constant.d.ts.map +1 -1
  40. package/dist/types/src/shapes/Database.d.ts +2 -2
  41. package/dist/types/src/shapes/Database.d.ts.map +1 -1
  42. package/dist/types/src/shapes/Feed.d.ts +2 -2
  43. package/dist/types/src/shapes/Feed.d.ts.map +1 -1
  44. package/dist/types/src/shapes/Function.d.ts +3 -5
  45. package/dist/types/src/shapes/Function.d.ts.map +1 -1
  46. package/dist/types/src/shapes/Gpt.d.ts +2 -2
  47. package/dist/types/src/shapes/Gpt.d.ts.map +1 -1
  48. package/dist/types/src/shapes/GptRealtime.d.ts +2 -2
  49. package/dist/types/src/shapes/GptRealtime.d.ts.map +1 -1
  50. package/dist/types/src/shapes/Json.d.ts +5 -5
  51. package/dist/types/src/shapes/Json.d.ts.map +1 -1
  52. package/dist/types/src/shapes/Logic.d.ts +5 -5
  53. package/dist/types/src/shapes/Logic.d.ts.map +1 -1
  54. package/dist/types/src/shapes/RNG.d.ts +2 -2
  55. package/dist/types/src/shapes/RNG.d.ts.map +1 -1
  56. package/dist/types/src/shapes/Scope.d.ts +2 -2
  57. package/dist/types/src/shapes/Scope.d.ts.map +1 -1
  58. package/dist/types/src/shapes/Surface.d.ts +2 -2
  59. package/dist/types/src/shapes/Surface.d.ts.map +1 -1
  60. package/dist/types/src/shapes/Switch.d.ts +2 -2
  61. package/dist/types/src/shapes/Switch.d.ts.map +1 -1
  62. package/dist/types/src/shapes/Table.d.ts +2 -2
  63. package/dist/types/src/shapes/Table.d.ts.map +1 -1
  64. package/dist/types/src/shapes/Template.d.ts +2 -2
  65. package/dist/types/src/shapes/Template.d.ts.map +1 -1
  66. package/dist/types/src/shapes/Text.d.ts +2 -2
  67. package/dist/types/src/shapes/Text.d.ts.map +1 -1
  68. package/dist/types/src/shapes/TextToImage.d.ts +2 -2
  69. package/dist/types/src/shapes/TextToImage.d.ts.map +1 -1
  70. package/dist/types/src/shapes/Thread.d.ts +2 -2
  71. package/dist/types/src/shapes/Thread.d.ts.map +1 -1
  72. package/dist/types/src/shapes/Trigger.d.ts +3 -3
  73. package/dist/types/src/shapes/Trigger.d.ts.map +1 -1
  74. package/dist/types/src/shapes/append-def.d.ts +1 -2
  75. package/dist/types/src/shapes/append-def.d.ts.map +1 -1
  76. package/dist/types/src/shapes/array-def.d.ts +2 -3
  77. package/dist/types/src/shapes/array-def.d.ts.map +1 -1
  78. package/dist/types/src/shapes/audio-def.d.ts +1 -2
  79. package/dist/types/src/shapes/audio-def.d.ts.map +1 -1
  80. package/dist/types/src/shapes/beacon-def.d.ts +1 -2
  81. package/dist/types/src/shapes/beacon-def.d.ts.map +1 -1
  82. package/dist/types/src/shapes/chat-def.d.ts +1 -2
  83. package/dist/types/src/shapes/chat-def.d.ts.map +1 -1
  84. package/dist/types/src/shapes/common/Box.d.ts.map +1 -1
  85. package/dist/types/src/shapes/common/FunctionBody.d.ts.map +1 -1
  86. package/dist/types/src/shapes/common/TextBox.d.ts +26 -0
  87. package/dist/types/src/shapes/common/TextBox.d.ts.map +1 -0
  88. package/dist/types/src/shapes/common/index.d.ts +3 -1
  89. package/dist/types/src/shapes/common/index.d.ts.map +1 -1
  90. package/dist/types/src/shapes/common/node-def.d.ts +24 -0
  91. package/dist/types/src/shapes/common/node-def.d.ts.map +1 -0
  92. package/dist/types/src/shapes/common/ports.d.ts +33 -0
  93. package/dist/types/src/shapes/common/ports.d.ts.map +1 -0
  94. package/dist/types/src/shapes/constant-def.d.ts +1 -2
  95. package/dist/types/src/shapes/constant-def.d.ts.map +1 -1
  96. package/dist/types/src/shapes/database-def.d.ts +1 -2
  97. package/dist/types/src/shapes/database-def.d.ts.map +1 -1
  98. package/dist/types/src/shapes/defs.d.ts +7 -2
  99. package/dist/types/src/shapes/defs.d.ts.map +1 -1
  100. package/dist/types/src/shapes/feed-def.d.ts +1 -2
  101. package/dist/types/src/shapes/feed-def.d.ts.map +1 -1
  102. package/dist/types/src/shapes/function-def.d.ts +1 -2
  103. package/dist/types/src/shapes/function-def.d.ts.map +1 -1
  104. package/dist/types/src/shapes/gpt-def.d.ts +1 -2
  105. package/dist/types/src/shapes/gpt-def.d.ts.map +1 -1
  106. package/dist/types/src/shapes/gpt-realtime-def.d.ts +1 -2
  107. package/dist/types/src/shapes/gpt-realtime-def.d.ts.map +1 -1
  108. package/dist/types/src/shapes/json-def.d.ts +2 -3
  109. package/dist/types/src/shapes/json-def.d.ts.map +1 -1
  110. package/dist/types/src/shapes/logic-def.d.ts +2 -3
  111. package/dist/types/src/shapes/logic-def.d.ts.map +1 -1
  112. package/dist/types/src/shapes/ports.test.d.ts +2 -0
  113. package/dist/types/src/shapes/ports.test.d.ts.map +1 -0
  114. package/dist/types/src/shapes/rng-def.d.ts +1 -2
  115. package/dist/types/src/shapes/rng-def.d.ts.map +1 -1
  116. package/dist/types/src/shapes/scope-def.d.ts +1 -2
  117. package/dist/types/src/shapes/scope-def.d.ts.map +1 -1
  118. package/dist/types/src/shapes/surface-def.d.ts +1 -2
  119. package/dist/types/src/shapes/surface-def.d.ts.map +1 -1
  120. package/dist/types/src/shapes/switch-def.d.ts +1 -2
  121. package/dist/types/src/shapes/switch-def.d.ts.map +1 -1
  122. package/dist/types/src/shapes/table-def.d.ts +1 -2
  123. package/dist/types/src/shapes/table-def.d.ts.map +1 -1
  124. package/dist/types/src/shapes/template-def.d.ts +1 -2
  125. package/dist/types/src/shapes/template-def.d.ts.map +1 -1
  126. package/dist/types/src/shapes/text-def.d.ts +1 -2
  127. package/dist/types/src/shapes/text-def.d.ts.map +1 -1
  128. package/dist/types/src/shapes/text-to-image-def.d.ts +1 -2
  129. package/dist/types/src/shapes/text-to-image-def.d.ts.map +1 -1
  130. package/dist/types/src/shapes/thread-def.d.ts +1 -2
  131. package/dist/types/src/shapes/thread-def.d.ts.map +1 -1
  132. package/dist/types/src/shapes/trigger-def.d.ts +1 -2
  133. package/dist/types/src/shapes/trigger-def.d.ts.map +1 -1
  134. package/dist/types/src/testing/circuits.d.ts +1 -1
  135. package/dist/types/src/testing/circuits.d.ts.map +1 -1
  136. package/dist/types/src/types/canvas-board.test.d.ts +2 -0
  137. package/dist/types/src/types/canvas-board.test.d.ts.map +1 -0
  138. package/dist/types/src/types/index.d.ts +4 -0
  139. package/dist/types/src/types/index.d.ts.map +1 -0
  140. package/dist/types/src/types/model.d.ts +10 -0
  141. package/dist/types/src/types/model.d.ts.map +1 -0
  142. package/dist/types/src/types/schema.d.ts +66 -0
  143. package/dist/types/src/types/schema.d.ts.map +1 -0
  144. package/dist/types/src/types/shapes.d.ts +114 -0
  145. package/dist/types/src/types/shapes.d.ts.map +1 -0
  146. package/dist/types/tsconfig.tsbuildinfo +1 -1
  147. package/package.json +43 -35
  148. package/src/graph/controller.ts +1 -1
  149. package/src/hooks/compute-context.ts +7 -4
  150. package/src/hooks/index.ts +0 -1
  151. package/src/hooks/useGraphMonitor.ts +10 -1
  152. package/src/index.ts +1 -1
  153. package/src/playwright/scene.spec.ts +3 -3
  154. package/src/registry.ts +63 -91
  155. package/src/scene/compute.stories.tsx +3 -6
  156. package/src/scene/echo-store.test.ts +18 -7
  157. package/src/scene/echo-store.ts +7 -10
  158. package/src/scene/index.ts +0 -3
  159. package/src/scene/projection.ts +2 -3
  160. package/src/scene/scene.test.ts +4 -4
  161. package/src/scene/scene.ts +6 -4
  162. package/src/schema.test.ts +7 -36
  163. package/src/shapes/Append.tsx +2 -3
  164. package/src/shapes/Array.tsx +3 -4
  165. package/src/shapes/Audio.tsx +2 -2
  166. package/src/shapes/Beacon.tsx +2 -2
  167. package/src/shapes/Boolean.tsx +32 -29
  168. package/src/shapes/Chat.tsx +5 -10
  169. package/src/shapes/Constant.tsx +19 -12
  170. package/src/shapes/Database.tsx +2 -4
  171. package/src/shapes/Feed.tsx +2 -3
  172. package/src/shapes/Function.tsx +4 -10
  173. package/src/shapes/Gpt.tsx +2 -3
  174. package/src/shapes/GptRealtime.tsx +2 -2
  175. package/src/shapes/Json.tsx +5 -6
  176. package/src/shapes/Logic.tsx +5 -6
  177. package/src/shapes/RNG.tsx +2 -2
  178. package/src/shapes/Scope.tsx +2 -2
  179. package/src/shapes/Surface.tsx +9 -6
  180. package/src/shapes/Switch.tsx +10 -12
  181. package/src/shapes/Table.tsx +2 -4
  182. package/src/shapes/Template.tsx +10 -9
  183. package/src/shapes/Text.tsx +2 -3
  184. package/src/shapes/TextToImage.tsx +2 -4
  185. package/src/shapes/Thread.tsx +2 -3
  186. package/src/shapes/Trigger.tsx +3 -4
  187. package/src/shapes/append-def.ts +8 -7
  188. package/src/shapes/array-def.ts +8 -8
  189. package/src/shapes/audio-def.ts +8 -7
  190. package/src/shapes/beacon-def.ts +9 -8
  191. package/src/shapes/chat-def.tsx +8 -8
  192. package/src/shapes/common/Box.tsx +7 -4
  193. package/src/shapes/common/FunctionBody.tsx +13 -26
  194. package/src/shapes/common/TextBox.tsx +137 -0
  195. package/src/shapes/common/index.ts +3 -1
  196. package/src/shapes/common/node-def.tsx +117 -0
  197. package/src/shapes/common/ports.ts +107 -0
  198. package/src/shapes/constant-def.tsx +8 -8
  199. package/src/shapes/database-def.ts +8 -8
  200. package/src/shapes/defs.ts +21 -6
  201. package/src/shapes/feed-def.ts +8 -7
  202. package/src/shapes/function-def.ts +8 -7
  203. package/src/shapes/gpt-def.ts +8 -7
  204. package/src/shapes/gpt-realtime-def.ts +10 -10
  205. package/src/shapes/json-def.ts +15 -13
  206. package/src/shapes/logic-def.ts +14 -11
  207. package/src/shapes/ports.test.ts +23 -0
  208. package/src/shapes/rng-def.ts +8 -7
  209. package/src/shapes/scope-def.ts +8 -7
  210. package/src/shapes/surface-def.ts +8 -8
  211. package/src/shapes/switch-def.ts +8 -7
  212. package/src/shapes/table-def.ts +7 -7
  213. package/src/shapes/template-def.ts +8 -7
  214. package/src/shapes/text-def.ts +8 -8
  215. package/src/shapes/text-to-image-def.ts +8 -8
  216. package/src/shapes/thread-def.ts +8 -7
  217. package/src/shapes/trigger-def.ts +11 -8
  218. package/src/testing/circuits.ts +21 -7
  219. package/src/types/canvas-board.test.ts +84 -0
  220. package/src/types/index.ts +7 -0
  221. package/src/types/model.ts +63 -0
  222. package/src/types/schema.ts +73 -0
  223. package/src/types/shapes.ts +73 -0
  224. package/dist/types/src/compute-layout.d.ts +0 -9
  225. package/dist/types/src/compute-layout.d.ts.map +0 -1
  226. package/dist/types/src/compute.stories.d.ts +0 -58
  227. package/dist/types/src/compute.stories.d.ts.map +0 -1
  228. package/dist/types/src/hooks/useComputeGraphController.d.ts +0 -10
  229. package/dist/types/src/hooks/useComputeGraphController.d.ts.map +0 -1
  230. package/dist/types/src/scene/NodeView.d.ts +0 -11
  231. package/dist/types/src/scene/NodeView.d.ts.map +0 -1
  232. package/dist/types/src/scene/defs.d.ts +0 -5
  233. package/dist/types/src/scene/defs.d.ts.map +0 -1
  234. package/dist/types/src/scene/ports.d.ts +0 -5
  235. package/dist/types/src/scene/ports.d.ts.map +0 -1
  236. package/dist/types/src/shapes/common/function-anchors.d.ts +0 -12
  237. package/dist/types/src/shapes/common/function-anchors.d.ts.map +0 -1
  238. package/src/compute-layout.ts +0 -37
  239. package/src/compute.stories.tsx +0 -302
  240. package/src/hooks/useComputeGraphController.ts +0 -65
  241. package/src/scene/NodeView.tsx +0 -42
  242. package/src/scene/defs.ts +0 -158
  243. package/src/scene/ports.ts +0 -30
  244. package/src/shapes/common/function-anchors.ts +0 -44
@@ -5,9 +5,8 @@
5
5
  import * as Schema from 'effect/Schema';
6
6
  import * as Struct from 'effect/Struct';
7
7
 
8
- import { type ShapeDef, createAnchorMap } from '@dxos/react-ui-canvas-editor';
9
-
10
- import { ComputeShape, type CreateShapeProps, createAnchorId, createShape } from './defs.ts';
8
+ import { createPorts, defineComputeNode } from './common/index.ts';
9
+ import { ComputeShape, type CreateShapeProps, createAnchorId, createShape, withZ } from './defs.ts';
11
10
  import { ScopeComponent } from './Scope.tsx';
12
11
 
13
12
  // Kept out of `Scope.tsx`: react-refresh only fast-refreshes a module whose
@@ -31,11 +30,13 @@ export const createScope = (props: CreateScopeProps) =>
31
30
  ...props,
32
31
  });
33
32
 
34
- export const scopeShape: ShapeDef<ScopeShape> = {
33
+ export const scopeNodeDef = defineComputeNode<ScopeShape>({
35
34
  type: 'scope',
36
35
  name: 'Scope',
37
36
  icon: 'ph--waveform--regular',
37
+ group: 'Outputs',
38
+ schema: withZ(ScopeShape),
38
39
  component: ScopeComponent,
39
- createShape: createScope,
40
- getAnchors: (shape) => createAnchorMap(shape, { [createAnchorId('input')]: { x: -1, y: 0 } }),
41
- };
40
+ create: createScope,
41
+ ports: (shape) => createPorts(shape.size, { [createAnchorId('input')]: { x: -1, y: 0 } }),
42
+ });
@@ -5,10 +5,8 @@
5
5
  import * as Schema from 'effect/Schema';
6
6
  import * as Struct from 'effect/Struct';
7
7
 
8
- import { type ShapeDef } from '@dxos/react-ui-canvas-editor';
9
- import { createAnchorMap } from '@dxos/react-ui-canvas-editor';
10
-
11
- import { ComputeShape, type CreateShapeProps, createAnchorId, createShape } from './defs.ts';
8
+ import { createPorts, defineComputeNode } from './common/index.ts';
9
+ import { ComputeShape, type CreateShapeProps, createAnchorId, createShape, withZ } from './defs.ts';
12
10
  import { SurfaceComponent } from './Surface.tsx';
13
11
 
14
12
  // Kept out of `Surface.tsx`: react-refresh only fast-refreshes a module whose
@@ -31,12 +29,14 @@ export const createSurface = (props: CreateSurfaceProps) =>
31
29
  ...props,
32
30
  });
33
31
 
34
- export const surfaceShape: ShapeDef<SurfaceShape> = {
32
+ export const surfaceNodeDef = defineComputeNode<SurfaceShape>({
35
33
  type: 'surface',
36
34
  name: 'Surface',
37
35
  icon: 'ph--frame-corners--regular',
36
+ group: 'Outputs',
37
+ schema: withZ(SurfaceShape),
38
38
  component: SurfaceComponent,
39
- createShape: createSurface,
40
- getAnchors: (shape) => createAnchorMap(shape, { [createAnchorId('input')]: { x: -1, y: 0 } }),
39
+ create: createSurface,
40
+ ports: (shape) => createPorts(shape.size, { [createAnchorId('input')]: { x: -1, y: 0 } }),
41
41
  resizable: true,
42
- };
42
+ });
@@ -5,9 +5,8 @@
5
5
  import * as Schema from 'effect/Schema';
6
6
  import * as Struct from 'effect/Struct';
7
7
 
8
- import { type ShapeDef, createAnchorMap } from '@dxos/react-ui-canvas-editor';
9
-
10
- import { ComputeShape, type CreateShapeProps, createAnchorId, createShape } from './defs.ts';
8
+ import { createPorts, defineComputeNode } from './common/index.ts';
9
+ import { ComputeShape, type CreateShapeProps, createAnchorId, createShape, withZ } from './defs.ts';
11
10
  import { SwitchComponent } from './Switch.tsx';
12
11
 
13
12
  // Kept out of `Switch.tsx`: react-refresh only fast-refreshes a module whose
@@ -26,11 +25,13 @@ export type CreateSwitchProps = CreateShapeProps<SwitchShape>;
26
25
  export const createSwitch = (props: CreateSwitchProps) =>
27
26
  createShape<SwitchShape>({ type: 'switch', size: { width: 64, height: 64 }, ...props });
28
27
 
29
- export const switchShape: ShapeDef<SwitchShape> = {
28
+ export const switchNodeDef = defineComputeNode<SwitchShape>({
30
29
  type: 'switch',
31
30
  name: 'Switch',
32
31
  icon: 'ph--toggle-left--regular',
32
+ group: 'Inputs',
33
+ schema: withZ(SwitchShape),
33
34
  component: SwitchComponent,
34
- createShape: createSwitch,
35
- getAnchors: (shape) => createAnchorMap(shape, { [createAnchorId('output')]: { x: 1, y: 0 } }),
36
- };
35
+ create: createSwitch,
36
+ ports: (shape) => createPorts(shape.size, { [createAnchorId('output')]: { x: 1, y: 0 } }),
37
+ });
@@ -7,11 +7,10 @@ import * as Struct from 'effect/Struct';
7
7
 
8
8
  import { createInputSchema, createOutputSchema } from '@dxos/conductor';
9
9
  import { Type } from '@dxos/echo';
10
- import { type ShapeDef } from '@dxos/react-ui-canvas-editor';
11
10
  import { Message } from '@dxos/types';
12
11
 
13
- import { createFunctionAnchors } from './common/index.ts';
14
- import { ComputeShape, type CreateShapeProps, createShape } from './defs.ts';
12
+ import { createFunctionPorts, defineComputeNode } from './common/index.ts';
13
+ import { ComputeShape, type CreateShapeProps, createShape, withZ } from './defs.ts';
15
14
  import { TableComponent } from './Table.tsx';
16
15
 
17
16
  // Kept out of `Table.tsx`: react-refresh only fast-refreshes a module whose
@@ -34,12 +33,13 @@ export type CreateTableProps = CreateShapeProps<TableShape>;
34
33
  export const createTable = (props: CreateTableProps) =>
35
34
  createShape<TableShape>({ type: 'table', size: { width: 320, height: 512 }, ...props });
36
35
 
37
- export const tableShape: ShapeDef<TableShape> = {
36
+ export const tableNodeDef = defineComputeNode<TableShape>({
38
37
  type: 'table',
39
38
  name: 'Table',
40
39
  icon: 'ph--table--regular',
40
+ schema: withZ(TableShape),
41
41
  component: TableComponent,
42
- createShape: createTable,
43
- getAnchors: (shape) => createFunctionAnchors(shape, InputSchema, OutputSchema),
42
+ create: createTable,
43
+ ports: (shape) => createFunctionPorts(shape.size, InputSchema, OutputSchema),
44
44
  resizable: true,
45
- };
45
+ });
@@ -6,10 +6,9 @@ import * as Schema from 'effect/Schema';
6
6
  import * as Struct from 'effect/Struct';
7
7
 
8
8
  import { ComputeValueType, TemplateOutput, VoidInput } from '@dxos/conductor';
9
- import { type ShapeDef } from '@dxos/react-ui-canvas-editor';
10
9
 
11
- import { createFunctionAnchors } from './common/index.ts';
12
- import { ComputeShape, type CreateShapeProps, createShape } from './defs.ts';
10
+ import { createFunctionPorts, defineComputeNode } from './common/index.ts';
11
+ import { ComputeShape, type CreateShapeProps, createShape, withZ } from './defs.ts';
13
12
  import { TemplateComponent } from './Template.tsx';
14
13
 
15
14
  // Kept out of `Template.tsx`: react-refresh only fast-refreshes a module whose
@@ -37,12 +36,14 @@ export type CreateTemplateProps = CreateShapeProps<TemplateShape> & { text?: str
37
36
  export const createTemplate = (props: CreateTemplateProps) =>
38
37
  createShape<TemplateShape>({ type: 'template', size: { width: 256, height: 384 }, ...props });
39
38
 
40
- export const templateShape: ShapeDef<TemplateShape> = {
39
+ export const templateNodeDef = defineComputeNode<TemplateShape>({
41
40
  type: 'template',
42
41
  name: 'Template',
43
42
  icon: 'ph--article--regular',
43
+ group: 'Inputs',
44
+ schema: withZ(TemplateShape),
44
45
  component: TemplateComponent,
45
- createShape: createTemplate,
46
- getAnchors: (shape) => createFunctionAnchors(shape, VoidInput, TemplateOutput),
46
+ create: createTemplate,
47
+ ports: (shape) => createFunctionPorts(shape.size, VoidInput, TemplateOutput),
47
48
  resizable: true,
48
- };
49
+ });
@@ -5,10 +5,8 @@
5
5
  import * as Schema from 'effect/Schema';
6
6
  import * as Struct from 'effect/Struct';
7
7
 
8
- import { type ShapeDef } from '@dxos/react-ui-canvas-editor';
9
- import { createAnchorMap } from '@dxos/react-ui-canvas-editor';
10
-
11
- import { ComputeShape, type CreateShapeProps, createAnchorId, createShape } from './defs.ts';
8
+ import { createPorts, defineComputeNode } from './common/index.ts';
9
+ import { ComputeShape, type CreateShapeProps, createAnchorId, createShape, withZ } from './defs.ts';
12
10
  import { TextComponent } from './Text.tsx';
13
11
 
14
12
  // Kept out of `Text.tsx`: react-refresh only fast-refreshes a module whose
@@ -27,12 +25,14 @@ export type CreateTextProps = CreateShapeProps<TextShape>;
27
25
  export const createText = (props: CreateTextProps) =>
28
26
  createShape<TextShape>({ type: 'text', size: { width: 384, height: 384 }, ...props });
29
27
 
30
- export const textShape: ShapeDef<TextShape> = {
28
+ export const textNodeDef = defineComputeNode<TextShape>({
31
29
  type: 'text',
32
30
  name: 'Text',
33
31
  icon: 'ph--article--regular',
32
+ group: 'Outputs',
33
+ schema: withZ(TextShape),
34
34
  component: TextComponent,
35
- createShape: createText,
36
- getAnchors: (shape) => createAnchorMap(shape, { [createAnchorId('input')]: { x: -1, y: 0 } }),
35
+ create: createText,
36
+ ports: (shape) => createPorts(shape.size, { [createAnchorId('input')]: { x: -1, y: 0 } }),
37
37
  resizable: true,
38
- };
38
+ });
@@ -5,10 +5,8 @@
5
5
  import * as Schema from 'effect/Schema';
6
6
  import * as Struct from 'effect/Struct';
7
7
 
8
- import { type ShapeDef } from '@dxos/react-ui-canvas-editor';
9
- import { createAnchorMap } from '@dxos/react-ui-canvas-editor';
10
-
11
- import { ComputeShape, type CreateShapeProps, createAnchorId, createShape } from './defs.ts';
8
+ import { createPorts, defineComputeNode } from './common/index.ts';
9
+ import { ComputeShape, type CreateShapeProps, createAnchorId, createShape, withZ } from './defs.ts';
12
10
  import { TextToImageComponent } from './TextToImage.tsx';
13
11
 
14
12
  // Kept out of `TextToImage.tsx`: react-refresh only fast-refreshes a module whose
@@ -27,11 +25,13 @@ export type CreateTextToImageProps = CreateShapeProps<TextToImageShape>;
27
25
  export const createTextToImage = (props: CreateTextToImageProps) =>
28
26
  createShape<TextToImageShape>({ type: 'text-to-image', size: { width: 128, height: 64 }, ...props });
29
27
 
30
- export const textToImageShape: ShapeDef<TextToImageShape> = {
28
+ export const textToImageNodeDef = defineComputeNode<TextToImageShape>({
31
29
  type: 'text-to-image',
32
30
  name: 'Image',
33
31
  icon: 'ph--image--regular',
32
+ group: 'Transform',
33
+ schema: withZ(TextToImageShape),
34
34
  component: TextToImageComponent,
35
- createShape: createTextToImage,
36
- getAnchors: (shape) => createAnchorMap(shape, { [createAnchorId('output')]: { x: 1, y: 0 } }),
37
- };
35
+ create: createTextToImage,
36
+ ports: (shape) => createPorts(shape.size, { [createAnchorId('output')]: { x: 1, y: 0 } }),
37
+ });
@@ -7,11 +7,10 @@ import * as Struct from 'effect/Struct';
7
7
 
8
8
  import { createInputSchema, createOutputSchema } from '@dxos/conductor';
9
9
  import { Type } from '@dxos/echo';
10
- import { type ShapeDef } from '@dxos/react-ui-canvas-editor';
11
10
  import { Message } from '@dxos/types';
12
11
 
13
- import { createFunctionAnchors } from './common/index.ts';
14
- import { ComputeShape, type CreateShapeProps, createShape } from './defs.ts';
12
+ import { createFunctionPorts, defineComputeNode } from './common/index.ts';
13
+ import { ComputeShape, type CreateShapeProps, createShape, withZ } from './defs.ts';
15
14
  import { ThreadComponent } from './Thread.tsx';
16
15
 
17
16
  // Kept out of `Thread.tsx`: react-refresh only fast-refreshes a module whose
@@ -34,12 +33,14 @@ export type CreateThreadProps = CreateShapeProps<ThreadShape>;
34
33
  export const createThread = (props: CreateThreadProps) =>
35
34
  createShape<ThreadShape>({ type: 'thread', size: { width: 384, height: 384 }, ...props });
36
35
 
37
- export const threadShape: ShapeDef<ThreadShape> = {
36
+ export const threadNodeDef = defineComputeNode<ThreadShape>({
38
37
  type: 'thread',
39
38
  name: 'Thread',
40
39
  icon: 'ph--chats-circle--regular',
40
+ group: 'Outputs',
41
+ schema: withZ(ThreadShape),
41
42
  component: ThreadComponent,
42
- createShape: createThread,
43
- getAnchors: (shape) => createFunctionAnchors(shape, InputSchema, OutputSchema),
43
+ create: createThread,
44
+ ports: (shape) => createFunctionPorts(shape.size, InputSchema, OutputSchema),
44
45
  resizable: true,
45
- };
46
+ });
@@ -10,10 +10,9 @@ import * as TriggerEvent from '@dxos/compute/TriggerEvent';
10
10
  import { VoidInput } from '@dxos/conductor';
11
11
  import { Ref } from '@dxos/echo';
12
12
  import { type SpaceId } from '@dxos/keys';
13
- import { type ShapeDef } from '@dxos/react-ui-canvas-editor';
14
13
 
15
- import { createFunctionAnchors, getHeight } from './common/index.ts';
16
- import { ComputeShape, type CreateShapeProps, createShape } from './defs.ts';
14
+ import { createFunctionPorts, defineComputeNode, getHeight } from './common/index.ts';
15
+ import { ComputeShape, type CreateShapeProps, createShape, withZ } from './defs.ts';
17
16
  import { createTriggerSpec, getOutputSchema } from './trigger-spec.ts';
18
17
  import { TriggerComponent } from './Trigger.tsx';
19
18
 
@@ -54,12 +53,16 @@ export const createTrigger = (props: CreateTriggerProps): TriggerShape => {
54
53
  });
55
54
  };
56
55
 
57
- export const triggerShape: ShapeDef<TriggerShape> = {
56
+ export const triggerNodeDef = defineComputeNode<TriggerShape>({
58
57
  type: 'trigger',
59
58
  name: 'Trigger',
60
59
  icon: 'ph--lightning--regular',
60
+ group: 'Inputs',
61
+ schema: withZ(TriggerShapeSchema),
61
62
  component: TriggerComponent,
62
- createShape: createTrigger,
63
- getAnchors: (shape) =>
64
- createFunctionAnchors(shape, VoidInput, getOutputSchema(shape.functionTrigger?.target?.spec?.kind ?? 'email')),
65
- };
63
+ create: createTrigger,
64
+ // The factory makes an ECHO object, so the default size is stated rather than sampled.
65
+ defaultSize: { width: 192, height: getHeight(TriggerEvent.EmailEvent) },
66
+ ports: (shape) =>
67
+ createFunctionPorts(shape.size, VoidInput, getOutputSchema(shape.functionTrigger?.target?.spec?.kind ?? 'email')),
68
+ });
@@ -4,8 +4,7 @@
4
4
 
5
5
  import { createSystemPrompt } from '@dxos/assistant';
6
6
  import { EID, EntityId, SpaceId } from '@dxos/keys';
7
- import { type Dimension, type Point } from '@dxos/react-ui-canvas';
8
- import { CanvasGraphModel, createNote, pointMultiply, pointsToRect, rectToPoints } from '@dxos/react-ui-canvas-editor';
7
+ import { type Point, type Size } from '@dxos/react-ui-canvas/scene';
9
8
 
10
9
  import {
11
10
  type ComputeShape,
@@ -33,6 +32,7 @@ import {
33
32
  createText,
34
33
  createTextToImage,
35
34
  } from '../shapes/index.ts';
35
+ import { CanvasGraphModel, type NoteShape } from '../types/index.ts';
36
36
 
37
37
  //
38
38
  // Circuits
@@ -304,12 +304,26 @@ export const createAudioCircuit = () => {
304
304
  // Utils
305
305
  //
306
306
 
307
- const position = (rect: Point & Partial<Dimension>, snap = 32): { center: Point; size?: Dimension } => {
308
- const [center, size] = rectToPoints({ width: 0, height: 0, ...rect });
309
- const { x, y, width, height } = pointsToRect([pointMultiply(center, snap), pointMultiply(size, snap)]);
307
+ /** A note, sized as the editor's note tool made one. */
308
+ const createNote = ({
309
+ id,
310
+ ...rest
311
+ }: Omit<NoteShape, 'type' | 'size'> & Partial<Pick<NoteShape, 'size'>>): NoteShape => ({
312
+ id,
313
+ type: 'note',
314
+ size: { width: 256, height: 128 },
315
+ ...rest,
316
+ });
317
+
318
+ /** A rectangle in grid cells scaled to pixels; the size is kept only when both extents are non-zero. */
319
+ const position = (
320
+ { x, y, width = 0, height = 0 }: Point & Partial<Size>,
321
+ snap = 32,
322
+ ): { center: Point; size?: Size } => {
323
+ const center = { x: Math.min(x, x + width) * snap, y: Math.min(y, y + height) * snap };
310
324
  if (width && height) {
311
- return { center: { x, y }, size: width && height ? { width, height } : undefined };
325
+ return { center, size: { width: Math.abs(width) * snap, height: Math.abs(height) * snap } };
312
326
  } else {
313
- return { center: { x, y } };
327
+ return { center };
314
328
  }
315
329
  };
@@ -0,0 +1,84 @@
1
+ //
2
+ // Copyright 2026 DXOS.org
3
+ //
4
+
5
+ import * as Effect from 'effect/Effect';
6
+ import * as Registry from 'effect/reactivity/AtomRegistry';
7
+ import { describe, test } from 'vitest';
8
+
9
+ import { TestDatabaseLayer } from '@dxos/compute-runtime/testing';
10
+ import { Database, Filter, Obj, Type } from '@dxos/echo';
11
+ import * as EffectEx from '@dxos/effect/EffectEx';
12
+
13
+ import { createEchoStore } from '../scene/index.ts';
14
+ import { CanvasBoard } from './index.ts';
15
+
16
+ /**
17
+ * A board exactly as the legacy canvas editor persisted it (`Obj.toJSON` of its `CanvasBoard`): a compute
18
+ * shape and a note, joined by one connection with both property names. The literal is the compatibility contract,
19
+ * so it is never regenerated from the schema under test.
20
+ */
21
+ const persistedBoard = {
22
+ 'id': '01M4ESMZRC98J310RDFN2TTAFT',
23
+ '@type': 'dxn:org.dxos.type.canvasBoard:0.1.0',
24
+ '@meta': { keys: [] },
25
+ 'name': 'Circuit',
26
+ 'layout': {
27
+ nodes: [
28
+ {
29
+ id: 'switch-1',
30
+ type: 'switch',
31
+ node: 'compute-1',
32
+ center: { x: -128, y: 0 },
33
+ size: { width: 64, height: 64 },
34
+ },
35
+ {
36
+ id: 'note-1',
37
+ type: 'note',
38
+ text: 'Hello',
39
+ center: { x: 0, y: -128 },
40
+ size: { width: 256, height: 128 },
41
+ },
42
+ ],
43
+ edges: [{ id: 'edge-1', source: 'switch-1', target: 'note-1', output: 'value', input: 'input' }],
44
+ },
45
+ };
46
+
47
+ const { id, '@type': _type, '@meta': _meta, ...fields } = persistedBoard;
48
+
49
+ /** The persisted board stored in a database and read back through a query for the compute type. */
50
+ const loadBoard = Effect.gen(function* () {
51
+ yield* Database.add(Obj.make(CanvasBoard.CanvasBoard, { id, ...fields }));
52
+ yield* Database.flush();
53
+ return yield* Database.query(Filter.type(CanvasBoard.CanvasBoard)).run;
54
+ }).pipe(Effect.provide(TestDatabaseLayer({ types: [CanvasBoard.CanvasBoard] })), Effect.scoped);
55
+
56
+ describe('CanvasBoard', () => {
57
+ test('keeps the typename and version boards were saved under', ({ expect }) => {
58
+ expect(Type.getTypename(CanvasBoard.CanvasBoard)).toBe('org.dxos.type.canvasBoard');
59
+ expect(Type.getVersion(CanvasBoard.CanvasBoard)).toBe('0.1.0');
60
+ });
61
+
62
+ test('a board as the editor saved it round-trips through a database unchanged', async ({ expect }) => {
63
+ const boards = await EffectEx.runPromise(loadBoard);
64
+ expect(boards).toHaveLength(1);
65
+ const [board] = boards;
66
+ expect(Obj.instanceOf(CanvasBoard.CanvasBoard, board)).toBe(true);
67
+ // `@uri` names the test space, so it is the one key the editor's JSON cannot carry.
68
+ const { '@uri': _uri, ...json } = Obj.toJSON(board);
69
+ expect(json).toEqual(persistedBoard);
70
+ });
71
+
72
+ test('the echo store reads the persisted layout as a scene', async ({ expect }) => {
73
+ const [board] = await EffectEx.runPromise(loadBoard);
74
+ const store = createEchoStore(board);
75
+ const scene = Registry.make().get(store.scene(board.id));
76
+ expect(scene?.name).toBe('Circuit');
77
+ expect(Object.keys(scene?.nodes ?? {})).toEqual(['switch-1', 'note-1']);
78
+ expect(scene?.nodes['note-1']).toMatchObject({ type: 'note', text: 'Hello', center: { x: 0, y: -128 } });
79
+ expect(scene?.links['edge-1']).toMatchObject({
80
+ source: { node: 'switch-1', port: 'output.value' },
81
+ target: { node: 'note-1', port: 'input.input' },
82
+ });
83
+ });
84
+ });
@@ -0,0 +1,7 @@
1
+ //
2
+ // Copyright 2024 DXOS.org
3
+ //
4
+
5
+ export * from './model.ts';
6
+ export * as CanvasBoard from './schema.ts';
7
+ export * from './shapes.ts';
@@ -0,0 +1,63 @@
1
+ //
2
+ // Copyright 2025 DXOS.org
3
+ //
4
+
5
+ import { DEFAULT_INPUT, DEFAULT_OUTPUT } from '@dxos/conductor';
6
+ import { Obj } from '@dxos/echo';
7
+ import { isProxy } from '@dxos/echo/internal';
8
+ import * as GraphModel from '@dxos/graph/GraphModel';
9
+ import { type MakeOptional } from '@dxos/util';
10
+
11
+ import { type Connection, type Shape } from './schema.ts';
12
+
13
+ export class CanvasGraphModel<S extends Shape = Shape> extends GraphModel.AbstractGraphModel<
14
+ S,
15
+ Connection,
16
+ CanvasGraphModel<S>
17
+ > {
18
+ static create<S extends Shape>(
19
+ graph?: Partial<GraphModel.AnyData>,
20
+ change?: GraphModel.GraphChangeFunction,
21
+ ): CanvasGraphModel<S> {
22
+ if (isProxy(graph)) {
23
+ return new CanvasGraphModel<S>({ graph: graph as GraphModel.Data<S, Connection>, change });
24
+ }
25
+
26
+ return new CanvasGraphModel<S>({
27
+ graph: {
28
+ nodes: (graph?.nodes ?? []) as S[],
29
+ edges: (graph?.edges ?? []) as Connection[],
30
+ },
31
+ });
32
+ }
33
+
34
+ override copy(graph?: Partial<GraphModel.Data<S, Connection>>): CanvasGraphModel<S> {
35
+ return CanvasGraphModel.create<S>(graph);
36
+ }
37
+
38
+ createNode({ id, ...rest }: MakeOptional<S, 'id'>): S {
39
+ const node: S = { id: id ?? Obj.ID.random(), ...rest } as S;
40
+ this.addNode(node);
41
+ return node;
42
+ }
43
+
44
+ createEdge({
45
+ id,
46
+ source,
47
+ target,
48
+ output = DEFAULT_OUTPUT,
49
+ input = DEFAULT_INPUT,
50
+ ...rest
51
+ }: MakeOptional<Connection, 'id'>): Connection {
52
+ const edge: Connection = {
53
+ id: id ?? Obj.ID.random(),
54
+ source,
55
+ target,
56
+ output,
57
+ input,
58
+ ...rest,
59
+ } as Connection;
60
+ this.addEdge(edge);
61
+ return edge;
62
+ }
63
+ }
@@ -0,0 +1,73 @@
1
+ //
2
+ // Copyright 2024 DXOS.org
3
+ //
4
+
5
+ import * as Schema from 'effect/Schema';
6
+ import * as Struct from 'effect/Struct';
7
+
8
+ import { ComputeGraph, ComputeGraphModel } from '@dxos/conductor';
9
+ import { Annotation, DXN, Obj, Ref, Type } from '@dxos/echo';
10
+ import * as GraphEdge from '@dxos/graph/GraphEdge';
11
+ import * as GraphModel from '@dxos/graph/GraphModel';
12
+ import * as GraphNode from '@dxos/graph/GraphNode';
13
+
14
+ // TODO(burdon): Consider interop with TLDraw and GeoJSON standards?
15
+
16
+ /**
17
+ * Base type for all shapes.
18
+ */
19
+ export const Shape = GraphNode.GraphNode.mapFields((fields) => Struct.omit(fields, ['type'])).pipe(
20
+ // TODO(burdon): Breaks graph contract?
21
+ Schema.fieldsAssign({
22
+ type: Schema.String,
23
+ text: Schema.optional(Schema.String),
24
+ guide: Schema.optional(Schema.Boolean),
25
+ classNames: Schema.optional(Schema.String),
26
+ }),
27
+ );
28
+
29
+ export type Shape = Schema.Schema.Type<typeof Shape>;
30
+
31
+ /**
32
+ * Connections between shapes.
33
+ */
34
+ export const Connection = GraphEdge.GraphEdge.mapFields(
35
+ Struct.assign({
36
+ input: Schema.optional(Schema.String),
37
+ output: Schema.optional(Schema.String),
38
+ }),
39
+ );
40
+
41
+ export type Connection = Schema.Schema.Type<typeof Connection>;
42
+
43
+ // TODO(burdon): Rename scene?
44
+ export const Layout = Schema.Struct({
45
+ shapes: Schema.Array(Shape),
46
+ });
47
+
48
+ export type Layout = Schema.Schema.Type<typeof Layout>;
49
+
50
+ // TODO(wittjosiah): Rename WorkflowType?
51
+ export class CanvasBoard extends Type.makeObject<CanvasBoard>(DXN.make('org.dxos.type.canvasBoard', '0.1.0'))(
52
+ Schema.Struct({
53
+ name: Schema.optional(Schema.String),
54
+
55
+ computeGraph: Schema.optional(Ref.Ref(ComputeGraph)),
56
+
57
+ /**
58
+ * Graph of shapes positioned on the canvas.
59
+ */
60
+ layout: GraphModel.Data,
61
+ }).pipe(Annotation.IconAnnotation.set({ icon: 'ph--infinity--regular', hue: 'sky' }), Annotation.UserType.set()),
62
+ ) {}
63
+
64
+ /**
65
+ * Creates a CanvasBoard with default empty layout and compute graph when not provided.
66
+ */
67
+ export const make = (props: Partial<Obj.MakeProps<typeof CanvasBoard>> = {}) => {
68
+ return Obj.make(CanvasBoard, {
69
+ ...props,
70
+ layout: props.layout ?? { nodes: [], edges: [] },
71
+ computeGraph: props.computeGraph ?? Ref.make(ComputeGraphModel.create().root),
72
+ });
73
+ };
@@ -0,0 +1,73 @@
1
+ //
2
+ // Copyright 2024 DXOS.org
3
+ //
4
+
5
+ import * as Schema from 'effect/Schema';
6
+ import * as Struct from 'effect/Struct';
7
+
8
+ import { Shape } from './schema.ts';
9
+
10
+ // The engine's `Point` / `Size` structs, declared here because its `/scene` entry also exports React, which this
11
+ // React-free entry must not import (plugins load it in workers).
12
+ const Point = Schema.Struct({ x: Schema.Number, y: Schema.Number });
13
+ const Size = Schema.Struct({ width: Schema.Number, height: Schema.Number });
14
+
15
+ //
16
+ // Path
17
+ //
18
+
19
+ export const PathShape = Shape.mapFields(
20
+ Struct.assign({
21
+ type: Schema.Literal('path'),
22
+ path: Schema.String,
23
+ start: Schema.optional(Schema.String),
24
+ end: Schema.optional(Schema.String),
25
+ }),
26
+ );
27
+
28
+ export type PathShape = Schema.Schema.Type<typeof PathShape>;
29
+ export const isPath = Schema.is(PathShape);
30
+
31
+ //
32
+ // Polygon
33
+ //
34
+
35
+ /**
36
+ * Closed shape.
37
+ * Common handling via Frame.
38
+ */
39
+ // `Schema.mutable` is arrays-only in v4, so a struct's fields are made mutable key by key.
40
+ export const Polygon = Shape.mapFields(
41
+ Struct.assign({
42
+ center: Point,
43
+ size: Size.mapFields(Struct.map(Schema.mutableKey)),
44
+ }),
45
+ ).mapFields(Struct.map(Schema.mutableKey));
46
+
47
+ export type Polygon = Schema.Schema.Type<typeof Polygon>;
48
+ export const isPolygon = Schema.is(Polygon);
49
+
50
+ export const EllipseShape = Polygon.mapFields(
51
+ Struct.assign({
52
+ type: Schema.Literal('ellipse'),
53
+ }),
54
+ );
55
+
56
+ export type EllipseShape = Schema.Schema.Type<typeof EllipseShape>;
57
+
58
+ export const NoteShape = Polygon.mapFields(
59
+ Struct.assign({
60
+ type: Schema.Literal('note'),
61
+ }),
62
+ );
63
+
64
+ export type NoteShape = Schema.Schema.Type<typeof NoteShape>;
65
+
66
+ export const RectangleShape = Polygon.mapFields(
67
+ Struct.assign({
68
+ type: Schema.Literal('rectangle'),
69
+ rounded: Schema.optional(Schema.Number),
70
+ }),
71
+ );
72
+
73
+ export type RectangleShape = Schema.Schema.Type<typeof RectangleShape>;
@@ -1,9 +0,0 @@
1
- import { type Anchor, ShapeLayout, type ShapeRegistry } from '@dxos/react-ui-canvas-editor';
2
- import { type ComputeGraphController } from './graph/index.ts';
3
- import { type ComputeShape } from './shapes/index.ts';
4
- export declare class ComputeShapeLayout extends ShapeLayout {
5
- private _controller;
6
- constructor(_controller: ComputeGraphController, registry: ShapeRegistry);
7
- getAnchors(shape: ComputeShape): Record<string, Anchor>;
8
- }
9
- //# sourceMappingURL=compute-layout.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"compute-layout.d.ts","sourceRoot":"","sources":["../../../src/compute-layout.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,KAAK,MAAM,EAAE,WAAW,EAAE,KAAK,aAAa,EAAE,MAAM,8BAA8B,CAAC;AAE5F,OAAO,EAAE,KAAK,sBAAsB,EAAE,MAAM,kBAAkB,CAAC;AAC/D,OAAO,EAAE,KAAK,YAAY,EAAyB,MAAM,mBAAmB,CAAC;AAG7E,qBAAa,kBAAmB,SAAQ,WAAW;IAE/C,OAAO,CAAC,WAAW;IADrB,YACU,WAAW,EAAE,sBAAsB,EAC3C,QAAQ,EAAE,aAAa,EAGxB;IAGQ,UAAU,CAAC,KAAK,EAAE,YAAY,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAc/D;CACF"}