@stephen-netu/design-system 0.2.1 → 0.5.1

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 (359) hide show
  1. package/dist/b0-app-shell/clarification-overlay/ClarificationOverlay.svelte +10 -2
  2. package/dist/b0-app-shell/clarification-overlay/ClarificationOverlay.svelte.d.ts.map +1 -1
  3. package/dist/b0-app-shell/{command-bar/CommandBar.svelte → global-command-bar/GlobalCommandBar.svelte} +75 -75
  4. package/dist/b0-app-shell/{command-bar/CommandBar.svelte.d.ts → global-command-bar/GlobalCommandBar.svelte.d.ts} +6 -6
  5. package/dist/b0-app-shell/global-command-bar/GlobalCommandBar.svelte.d.ts.map +1 -0
  6. package/dist/b0-app-shell/index.d.ts +1 -1
  7. package/dist/b0-app-shell/index.d.ts.map +1 -1
  8. package/dist/b0-app-shell/index.js +1 -1
  9. package/dist/d0-data-viz/BarChart.test.js +53 -0
  10. package/dist/d0-data-viz/CheckpointBar.test.js +83 -0
  11. package/dist/d0-data-viz/CheckpointPill.svelte +8 -3
  12. package/dist/d0-data-viz/CheckpointPill.svelte.d.ts.map +1 -1
  13. package/dist/d0-data-viz/CheckpointPill.test.js +78 -0
  14. package/dist/d0-data-viz/ConnectionHealth.test.js +70 -0
  15. package/dist/d0-data-viz/MetricCard.test.js +57 -0
  16. package/dist/d0-data-viz/SparkLine.test.js +47 -0
  17. package/dist/d0-data-viz/StorageMap.test.js +63 -0
  18. package/dist/d0-data-viz/Timeline.test.js +62 -0
  19. package/dist/d0-data-viz/WorldLineTimeline.test.js +99 -0
  20. package/dist/d0-data-viz/checkpoint-types.js +1 -1
  21. package/dist/d0-data-viz/storage-map-types.d.ts.map +1 -1
  22. package/dist/d0-data-viz/storage-map-types.js +6 -3
  23. package/dist/d0-data-viz/theme-integration.d.ts +3 -3
  24. package/dist/d0-data-viz/theme-integration.js +4 -4
  25. package/dist/d0-data-viz/theme-integration.test.js +41 -0
  26. package/dist/demos/AmbientPrimitivesDemo.svelte +103 -0
  27. package/dist/demos/AmbientPrimitivesDemo.svelte.d.ts +5 -0
  28. package/dist/demos/AmbientPrimitivesDemo.svelte.d.ts.map +1 -0
  29. package/dist/demos/BspSizingInfographic.svelte +3 -32
  30. package/dist/demos/NodepadBlocksShowcase.svelte +2 -1
  31. package/dist/demos/NodepadBlocksShowcase.svelte.d.ts.map +1 -1
  32. package/dist/demos/index.d.ts +1 -0
  33. package/dist/demos/index.d.ts.map +1 -1
  34. package/dist/demos/index.js +1 -0
  35. package/dist/editor/CodeEditor.svelte +83 -26
  36. package/dist/editor/CodeEditor.svelte.d.ts +0 -1
  37. package/dist/editor/CodeEditor.svelte.d.ts.map +1 -1
  38. package/dist/editor/CodeEditor.test.js +38 -0
  39. package/dist/editor/ExternalChangeDialog.svelte +117 -0
  40. package/dist/editor/ExternalChangeDialog.svelte.d.ts +13 -0
  41. package/dist/editor/ExternalChangeDialog.svelte.d.ts.map +1 -0
  42. package/dist/editor/FindReplaceDialog.svelte +32 -32
  43. package/dist/editor/MarkdownEditor.svelte +105 -605
  44. package/dist/editor/MarkdownEditor.svelte.d.ts +1 -1
  45. package/dist/editor/MarkdownEditor.svelte.d.ts.map +1 -1
  46. package/dist/editor/MarkdownEditor.test.js +38 -0
  47. package/dist/editor/codemirror-config.d.ts +36 -0
  48. package/dist/editor/codemirror-config.d.ts.map +1 -0
  49. package/dist/editor/codemirror-config.js +87 -0
  50. package/dist/editor/components/CorrectionTooltip.svelte +180 -160
  51. package/dist/editor/components/CorrectionTooltip.svelte.d.ts +7 -23
  52. package/dist/editor/components/CorrectionTooltip.svelte.d.ts.map +1 -1
  53. package/dist/editor/extensions/autocomplete.d.ts +2 -2
  54. package/dist/editor/extensions/autocomplete.d.ts.map +1 -1
  55. package/dist/editor/extensions/autocomplete.test.js +121 -0
  56. package/dist/editor/extensions/spellcheck.d.ts +21 -3
  57. package/dist/editor/extensions/spellcheck.d.ts.map +1 -1
  58. package/dist/editor/extensions/spellcheck.js +51 -9
  59. package/dist/editor/extensions/spellcheck.test.js +168 -0
  60. package/dist/editor/extensions/types.d.ts +2 -1
  61. package/dist/editor/extensions/types.d.ts.map +1 -1
  62. package/dist/editor/index.d.ts +2 -1
  63. package/dist/editor/index.d.ts.map +1 -1
  64. package/dist/editor/index.js +1 -0
  65. package/dist/editor/markdown-preview.d.ts +9 -0
  66. package/dist/editor/markdown-preview.d.ts.map +1 -0
  67. package/dist/editor/markdown-preview.js +19 -0
  68. package/dist/editor/markdown-preview.test.js +38 -0
  69. package/dist/editor/useCodeMirror.d.ts +23 -0
  70. package/dist/editor/useCodeMirror.d.ts.map +1 -0
  71. package/dist/editor/useCodeMirror.js +40 -0
  72. package/dist/editor/useFilePersistence.d.ts +32 -0
  73. package/dist/editor/useFilePersistence.d.ts.map +1 -0
  74. package/dist/editor/useFilePersistence.js +117 -0
  75. package/dist/entity-graph-view/WorldView.svelte +1 -1
  76. package/dist/fabric/ai/ChatPanel.svelte +84 -85
  77. package/dist/fabric/ai/ChatPanel.svelte.d.ts.map +1 -1
  78. package/dist/fabric/ai/ResearchPanel.svelte +35 -25
  79. package/dist/fabric/ai/ResearchPanel.svelte.d.ts.map +1 -1
  80. package/dist/fabric/data/FileTree.svelte +195 -0
  81. package/dist/fabric/data/FileTree.svelte.d.ts +19 -0
  82. package/dist/fabric/data/FileTree.svelte.d.ts.map +1 -0
  83. package/dist/fabric/data/FileTree.test.js +127 -0
  84. package/dist/fabric/data/index.d.ts +5 -9
  85. package/dist/fabric/data/index.d.ts.map +1 -1
  86. package/dist/fabric/data/index.js +4 -1
  87. package/dist/fabric/index.d.ts +5 -5
  88. package/dist/fabric/index.d.ts.map +1 -1
  89. package/dist/fabric/index.js +5 -3
  90. package/dist/fabric/input/{CommandBar.svelte → AppHeaderBar.svelte} +13 -13
  91. package/dist/fabric/input/{CommandBar.svelte.d.ts → AppHeaderBar.svelte.d.ts} +5 -5
  92. package/dist/fabric/input/AppHeaderBar.svelte.d.ts.map +1 -0
  93. package/dist/fabric/input/{CommandBar.test.js → AppHeaderBar.test.js} +9 -9
  94. package/dist/fabric/input/KeyboardShortcuts.svelte +23 -21
  95. package/dist/fabric/input/index.d.ts +2 -2
  96. package/dist/fabric/input/index.d.ts.map +1 -1
  97. package/dist/fabric/input/index.js +1 -1
  98. package/dist/fabric/layout/CollapsiblePanel.svelte +8 -10
  99. package/dist/fabric/layout/KanbanBoard.svelte +25 -155
  100. package/dist/fabric/layout/KanbanBoard.svelte.d.ts +2 -26
  101. package/dist/fabric/layout/KanbanBoard.svelte.d.ts.map +1 -1
  102. package/dist/fabric/layout/KanbanBoard.test.js +125 -10
  103. package/dist/fabric/layout/KanbanCard.svelte +27 -223
  104. package/dist/fabric/layout/KanbanCard.svelte.d.ts +2 -19
  105. package/dist/fabric/layout/KanbanCard.svelte.d.ts.map +1 -1
  106. package/dist/fabric/layout/KanbanColumn.svelte +41 -275
  107. package/dist/fabric/layout/KanbanColumn.svelte.d.ts +2 -22
  108. package/dist/fabric/layout/KanbanColumn.svelte.d.ts.map +1 -1
  109. package/dist/fabric/layout/index.d.ts +2 -5
  110. package/dist/fabric/layout/index.d.ts.map +1 -1
  111. package/dist/fabric/layout/index.js +1 -1
  112. package/dist/fabric/navigation/ActivityRail.svelte +3 -5
  113. package/dist/fabric/navigation/ActivityRail.svelte.d.ts.map +1 -1
  114. package/dist/g0-generative/components/Text.svelte +38 -0
  115. package/dist/g0-generative/components/Text.svelte.d.ts +9 -0
  116. package/dist/g0-generative/components/Text.svelte.d.ts.map +1 -0
  117. package/dist/g0-generative/index.d.ts +1 -0
  118. package/dist/g0-generative/index.d.ts.map +1 -1
  119. package/dist/g0-generative/index.js +1 -0
  120. package/dist/g0-generative/library/ComponentLibrary.d.ts +4 -0
  121. package/dist/g0-generative/library/ComponentLibrary.d.ts.map +1 -1
  122. package/dist/g0-generative/library/ComponentLibrary.js +10 -0
  123. package/dist/g0-generative/library/ComponentLibrary.test.js +135 -0
  124. package/dist/g0-generative/renderer/OpenUIRenderer.svelte +16 -56
  125. package/dist/g0-generative/renderer/OpenUIRenderer.svelte.d.ts.map +1 -1
  126. package/dist/g0-generative/renderer/OpenUIRenderer.test.js +143 -0
  127. package/dist/g0-geo/SovereignMap.svelte +13 -13
  128. package/dist/g0-geo/SovereignMap.svelte.d.ts.map +1 -1
  129. package/dist/index.d.ts +0 -1
  130. package/dist/index.d.ts.map +1 -1
  131. package/dist/index.js +7 -3
  132. package/dist/l0-layout/SectionSplitter.svelte +5 -5
  133. package/dist/l0-layout/block-writer/BlockContent.svelte +23 -22
  134. package/dist/l0-layout/block-writer/BlockContent.svelte.d.ts.map +1 -1
  135. package/dist/l0-layout/block-writer/BlockContent.test.js +47 -0
  136. package/dist/l0-layout/block-writer/BlockItem.svelte +6 -4
  137. package/dist/l0-layout/block-writer/markdown.js +11 -11
  138. package/dist/l0-layout/block-writer/markdown.test.js +81 -0
  139. package/dist/l0-layout/card/CompactCard.svelte +4 -3
  140. package/dist/l0-layout/card/StackedCard.svelte +87 -0
  141. package/dist/l0-layout/card/StackedCard.svelte.d.ts +9 -0
  142. package/dist/l0-layout/card/StackedCard.svelte.d.ts.map +1 -0
  143. package/dist/l0-layout/card/StackedCard.test.js +29 -0
  144. package/dist/l0-layout/grant/GrantCard.svelte +15 -5
  145. package/dist/l0-layout/grant/GrantCard.svelte.d.ts.map +1 -1
  146. package/dist/l0-layout/index.d.ts +3 -0
  147. package/dist/l0-layout/index.d.ts.map +1 -1
  148. package/dist/l0-layout/index.js +2 -0
  149. package/dist/l0-layout/kanban/KanbanBoard.svelte +246 -29
  150. package/dist/l0-layout/kanban/KanbanBoard.svelte.d.ts +28 -2
  151. package/dist/l0-layout/kanban/KanbanBoard.svelte.d.ts.map +1 -1
  152. package/dist/l0-layout/kanban/KanbanCard.svelte +175 -150
  153. package/dist/l0-layout/kanban/KanbanCard.svelte.d.ts +16 -18
  154. package/dist/l0-layout/kanban/KanbanCard.svelte.d.ts.map +1 -1
  155. package/dist/l0-layout/kanban/KanbanColumn.svelte +152 -78
  156. package/dist/l0-layout/kanban/KanbanColumn.svelte.d.ts +28 -7
  157. package/dist/l0-layout/kanban/KanbanColumn.svelte.d.ts.map +1 -1
  158. package/dist/l0-layout/kanban/index.d.ts +6 -0
  159. package/dist/l0-layout/kanban/index.d.ts.map +1 -0
  160. package/dist/l0-layout/kanban/index.js +3 -0
  161. package/dist/n0-node-graph/Node.svelte +2 -2
  162. package/dist/n0-node-graph/NodePalette.svelte +2 -2
  163. package/dist/n1-flow-canvas/FlowCanvas.svelte +50 -6
  164. package/dist/n1-flow-canvas/FlowCanvas.svelte.d.ts.map +1 -1
  165. package/dist/n1-flow-canvas/graph-state.test.js +69 -0
  166. package/dist/n1-flow-canvas/index.d.ts +2 -0
  167. package/dist/n1-flow-canvas/index.d.ts.map +1 -1
  168. package/dist/n1-flow-canvas/index.js +1 -0
  169. package/dist/n1-flow-canvas/pipeline-adapter.d.ts +37 -0
  170. package/dist/n1-flow-canvas/pipeline-adapter.d.ts.map +1 -0
  171. package/dist/n1-flow-canvas/pipeline-adapter.js +160 -0
  172. package/dist/n1-flow-canvas/utils.test.js +116 -0
  173. package/dist/n2-manifold-disk/ManifoldDisk.svelte +62 -35
  174. package/dist/n2-manifold-disk/ManifoldDisk.svelte.d.ts.map +1 -1
  175. package/dist/n3-force-graph/GraphTooltip.svelte +2 -2
  176. package/dist/n4-adaptive-manifold/AdaptiveManifold.svelte +34 -29
  177. package/dist/n4-adaptive-manifold/AdaptiveManifold.svelte.d.ts.map +1 -1
  178. package/dist/n4-adaptive-manifold/classifier.test.js +104 -0
  179. package/dist/n4-adaptive-manifold/n4-tokens.css +2 -2
  180. package/dist/n4-adaptive-manifold/types.d.ts +3 -0
  181. package/dist/n4-adaptive-manifold/types.d.ts.map +1 -1
  182. package/dist/p0-primitives/ThemeProvider.svelte +38 -18
  183. package/dist/p0-primitives/ThemeProvider.svelte.d.ts +6 -1
  184. package/dist/p0-primitives/ThemeProvider.svelte.d.ts.map +1 -1
  185. package/dist/p0-primitives/canvas-theme.d.ts +33 -1
  186. package/dist/p0-primitives/canvas-theme.d.ts.map +1 -1
  187. package/dist/p0-primitives/canvas-theme.js +82 -17
  188. package/dist/p0-primitives/debug.d.ts +6 -0
  189. package/dist/p0-primitives/debug.d.ts.map +1 -0
  190. package/dist/p0-primitives/debug.js +21 -0
  191. package/dist/p0-primitives/index.d.ts +2 -1
  192. package/dist/p0-primitives/index.d.ts.map +1 -1
  193. package/dist/p0-primitives/index.js +1 -0
  194. package/dist/p0-primitives/theme-context.d.ts +9 -0
  195. package/dist/p0-primitives/theme-context.d.ts.map +1 -0
  196. package/dist/p0-primitives/theme-context.js +8 -0
  197. package/dist/p0-primitives/theme.d.ts.map +1 -1
  198. package/dist/p0-primitives/theme.js +11 -31
  199. package/dist/p0-primitives/tokens/ambient.css +76 -0
  200. package/dist/p0-primitives/tokens/tokens.css +140 -34
  201. package/dist/p0-primitives/utils/index.d.ts +4 -2
  202. package/dist/p0-primitives/utils/index.d.ts.map +1 -1
  203. package/dist/p0-primitives/utils/index.js +1 -0
  204. package/dist/p0-primitives/utils/reveal.d.ts +15 -0
  205. package/dist/p0-primitives/utils/reveal.d.ts.map +1 -0
  206. package/dist/p0-primitives/utils/reveal.js +29 -0
  207. package/dist/p0-primitives/utils/reveal.test.js +95 -0
  208. package/dist/s0-state/SyncStatus.svelte +2 -2
  209. package/dist/s0-state/ThemeStore.svelte.d.ts +3 -2
  210. package/dist/s0-state/ThemeStore.svelte.d.ts.map +1 -1
  211. package/dist/s0-state/ThemeStore.svelte.js +20 -1
  212. package/dist/s0-state/index.d.ts +2 -2
  213. package/dist/s0-state/index.d.ts.map +1 -1
  214. package/dist/s0-state/index.js +3 -0
  215. package/dist/s0-state/modal-stack-store.svelte.d.ts +27 -2
  216. package/dist/s0-state/modal-stack-store.svelte.d.ts.map +1 -1
  217. package/dist/s0-state/modal-stack-store.svelte.js +21 -2
  218. package/dist/showcase/Showcase.svelte +43 -34
  219. package/dist/showcase/Showcase.svelte.d.ts.map +1 -1
  220. package/dist/spatial/BspTilingCanvas.svelte +5 -5
  221. package/dist/spatial/BspTilingSimulation.test.js +88 -0
  222. package/dist/spatial/CameraController.test.js +120 -0
  223. package/dist/spatial/ForceCanvas.svelte +18 -13
  224. package/dist/spatial/ForceCanvas.svelte.d.ts.map +1 -1
  225. package/dist/spatial/ForceSimulation.svelte.d.ts.map +1 -1
  226. package/dist/spatial/ForceSimulation.svelte.js +33 -22
  227. package/dist/spatial/LodRenderer.svelte +14 -1
  228. package/dist/spatial/LodRenderer.svelte.d.ts.map +1 -1
  229. package/dist/spatial/ParticleAssembleMark.svelte +285 -0
  230. package/dist/spatial/ParticleAssembleMark.svelte.d.ts +24 -0
  231. package/dist/spatial/ParticleAssembleMark.svelte.d.ts.map +1 -0
  232. package/dist/spatial/SnapZoomCamera.svelte +23 -13
  233. package/dist/spatial/SnapZoomCamera.svelte.d.ts.map +1 -1
  234. package/dist/spatial/ZoneTiler.svelte +3 -2
  235. package/dist/spatial/ZoneTiler.test.js +90 -0
  236. package/dist/spatial/d3-types.d.ts +31 -0
  237. package/dist/spatial/d3-types.d.ts.map +1 -0
  238. package/dist/spatial/d3-types.js +19 -0
  239. package/dist/spatial/index.js +1 -0
  240. package/dist/spatial/particle-assemble-math.d.ts +22 -0
  241. package/dist/spatial/particle-assemble-math.d.ts.map +1 -0
  242. package/dist/spatial/particle-assemble-math.js +26 -0
  243. package/dist/spatial/particle-assemble-math.test.js +56 -0
  244. package/dist/ssr-import-clean.test.js +37 -0
  245. package/dist/t0-transport/fs.d.ts +12 -0
  246. package/dist/t0-transport/fs.d.ts.map +1 -0
  247. package/dist/t0-transport/fs.js +55 -0
  248. package/dist/t0-transport/index.d.ts +1 -0
  249. package/dist/t0-transport/index.d.ts.map +1 -1
  250. package/dist/t0-transport/index.js +1 -0
  251. package/dist/t0-transport/invoke.d.ts.map +1 -1
  252. package/dist/t0-transport/invoke.js +5 -2
  253. package/dist/t0-transport/quality.d.ts +12 -3
  254. package/dist/t0-transport/quality.d.ts.map +1 -1
  255. package/dist/t0-transport/quality.js +17 -4
  256. package/dist/t0-transport/substrate.svelte.d.ts +27 -0
  257. package/dist/t0-transport/substrate.svelte.d.ts.map +1 -0
  258. package/dist/t0-transport/substrate.svelte.js +55 -0
  259. package/dist/u0-primitives/LockIndicator.svelte +17 -15
  260. package/dist/u0-primitives/VerticalToolbar.svelte +25 -22
  261. package/dist/u0-primitives/accordion/Accordion.svelte +14 -12
  262. package/dist/u0-primitives/accordion/Accordion.svelte.d.ts +0 -7
  263. package/dist/u0-primitives/accordion/Accordion.svelte.d.ts.map +1 -1
  264. package/dist/u0-primitives/accordion/Accordion.test.js +5 -5
  265. package/dist/u0-primitives/animated-icon/AnimatedIcon.svelte +3 -3
  266. package/dist/u0-primitives/animated-icon/AnimatedIcon.test.js +82 -0
  267. package/dist/u0-primitives/avatar/Avatar.svelte +14 -14
  268. package/dist/u0-primitives/avatar/Avatar.test.js +81 -0
  269. package/dist/u0-primitives/badge/Badge.svelte +6 -4
  270. package/dist/u0-primitives/badge/Badge.test.js +10 -10
  271. package/dist/u0-primitives/badge/ValidityBadge.svelte +4 -27
  272. package/dist/u0-primitives/badge/ValidityBadge.test.js +9 -9
  273. package/dist/u0-primitives/button/Button.svelte +18 -13
  274. package/dist/u0-primitives/button/Button.svelte.d.ts +1 -0
  275. package/dist/u0-primitives/button/Button.svelte.d.ts.map +1 -1
  276. package/dist/u0-primitives/button/Button.test.js +11 -11
  277. package/dist/u0-primitives/card/Card.svelte +60 -32
  278. package/dist/u0-primitives/card/Card.svelte.d.ts.map +1 -1
  279. package/dist/u0-primitives/card/Card.test.js +86 -0
  280. package/dist/u0-primitives/command-palette/CommandPalette.svelte +75 -43
  281. package/dist/u0-primitives/command-palette/CommandPalette.svelte.d.ts.map +1 -1
  282. package/dist/u0-primitives/command-palette/CommandPalette.test.js +202 -0
  283. package/dist/u0-primitives/command-palette/commandStore.svelte.d.ts.map +1 -1
  284. package/dist/u0-primitives/command-palette/commandStore.svelte.js +2 -1
  285. package/dist/u0-primitives/dropdown/Dropdown.svelte +20 -25
  286. package/dist/u0-primitives/dropdown/Dropdown.test.js +1 -1
  287. package/dist/u0-primitives/grant-badge/GrantStatusBadge.svelte +2 -2
  288. package/dist/u0-primitives/index.d.ts +8 -0
  289. package/dist/u0-primitives/index.d.ts.map +1 -1
  290. package/dist/u0-primitives/index.js +9 -0
  291. package/dist/u0-primitives/input/Input.svelte +85 -23
  292. package/dist/u0-primitives/input/Input.svelte.d.ts +2 -10
  293. package/dist/u0-primitives/input/Input.svelte.d.ts.map +1 -1
  294. package/dist/u0-primitives/input/Input.test.js +82 -2
  295. package/dist/u0-primitives/live-dot/LiveDot.svelte +56 -0
  296. package/dist/u0-primitives/live-dot/LiveDot.svelte.d.ts +11 -0
  297. package/dist/u0-primitives/live-dot/LiveDot.svelte.d.ts.map +1 -0
  298. package/dist/u0-primitives/live-dot/LiveDot.test.js +41 -0
  299. package/dist/u0-primitives/live-dot/index.d.ts +3 -0
  300. package/dist/u0-primitives/live-dot/index.d.ts.map +1 -0
  301. package/dist/u0-primitives/live-dot/index.js +1 -0
  302. package/dist/u0-primitives/modal/Modal.svelte +64 -38
  303. package/dist/u0-primitives/modal/Modal.svelte.d.ts.map +1 -1
  304. package/dist/u0-primitives/modal/Modal.test.js +63 -15
  305. package/dist/u0-primitives/rsvp/RsvpReader.svelte +8 -8
  306. package/dist/u0-primitives/rsvp/RsvpReader.svelte.d.ts.map +1 -1
  307. package/dist/u0-primitives/spinner/Spinner.svelte +11 -79
  308. package/dist/u0-primitives/spinner/Spinner.svelte.d.ts.map +1 -1
  309. package/dist/u0-primitives/steps/Steps.svelte +20 -21
  310. package/dist/u0-primitives/surface-state/SurfaceState.svelte +190 -0
  311. package/dist/u0-primitives/surface-state/SurfaceState.svelte.d.ts +15 -0
  312. package/dist/u0-primitives/surface-state/SurfaceState.svelte.d.ts.map +1 -0
  313. package/dist/u0-primitives/tabs/Tabs.svelte +13 -11
  314. package/dist/u0-primitives/theme-swatch-group/ThemeSwatchGroup.svelte +94 -0
  315. package/dist/u0-primitives/theme-swatch-group/ThemeSwatchGroup.svelte.d.ts +16 -0
  316. package/dist/u0-primitives/theme-swatch-group/ThemeSwatchGroup.svelte.d.ts.map +1 -0
  317. package/dist/u0-primitives/theme-swatch-group/ThemeSwatchGroup.test.js +48 -0
  318. package/dist/u0-primitives/theme-swatch-group/index.d.ts +3 -0
  319. package/dist/u0-primitives/theme-swatch-group/index.d.ts.map +1 -0
  320. package/dist/u0-primitives/theme-swatch-group/index.js +1 -0
  321. package/dist/u0-primitives/toggle/Toggle.svelte +22 -13
  322. package/dist/u0-primitives/tooltip/Tooltip.svelte +9 -9
  323. package/dist/u0-primitives/tooltip/Tooltip.test.js +12 -12
  324. package/dist/u0-primitives/web-components/button-component.d.ts +5 -1
  325. package/dist/u0-primitives/web-components/button-component.d.ts.map +1 -1
  326. package/dist/u0-primitives/web-components/button-component.js +72 -33
  327. package/dist/u0-primitives/web-components/index.d.ts +3 -0
  328. package/dist/u0-primitives/web-components/index.d.ts.map +1 -0
  329. package/dist/u0-primitives/web-components/index.js +2 -0
  330. package/dist/u0-primitives/web-components/input-component.d.ts +5 -1
  331. package/dist/u0-primitives/web-components/input-component.d.ts.map +1 -1
  332. package/dist/u0-primitives/web-components/input-component.js +56 -39
  333. package/dist/u0-primitives/web-components/web-components.test.js +96 -0
  334. package/dist/u0-primitives/window-frame/WindowFrame.svelte +87 -0
  335. package/dist/u0-primitives/window-frame/WindowFrame.svelte.d.ts +10 -0
  336. package/dist/u0-primitives/window-frame/WindowFrame.svelte.d.ts.map +1 -0
  337. package/dist/u0-primitives/window-frame/WindowFrame.test.js +31 -0
  338. package/dist/u0-primitives/window-frame/index.d.ts +3 -0
  339. package/dist/u0-primitives/window-frame/index.d.ts.map +1 -0
  340. package/dist/u0-primitives/window-frame/index.js +1 -0
  341. package/dist/v0-diagrams/MarkmapDiagram.test.js +49 -0
  342. package/dist/v0-diagrams/MermaidDiagram.svelte +21 -9
  343. package/dist/v0-diagrams/MermaidDiagram.svelte.d.ts.map +1 -1
  344. package/dist/v0-diagrams/MermaidDiagram.test.js +40 -0
  345. package/dist/x0-enchanted-blocks/components/NodepadBlock.svelte +11 -2
  346. package/dist/x0-enchanted-blocks/components/NodepadBlock.svelte.d.ts.map +1 -1
  347. package/package.json +57 -15
  348. package/src/n4-adaptive-manifold/n4-tokens.css +2 -2
  349. package/src/p0-primitives/tokens/ambient.css +76 -0
  350. package/src/p0-primitives/tokens/tokens.css +140 -34
  351. package/src/p0-primitives/tokens/tokens.json +55 -26
  352. package/dist/b0-app-shell/command-bar/CommandBar.svelte.d.ts.map +0 -1
  353. package/dist/fabric/input/CommandBar.svelte.d.ts.map +0 -1
  354. package/dist/stores/vaultStore.svelte +0 -14
  355. package/dist/stores/vaultStore.svelte.d.ts +0 -24
  356. package/dist/stores/vaultStore.svelte.d.ts.map +0 -1
  357. package/dist/tauri/index.d.ts +0 -3
  358. package/dist/tauri/index.d.ts.map +0 -1
  359. package/dist/tauri/index.js +0 -11
@@ -1,6 +1,18 @@
1
1
  import { afterEach, describe, it, expect } from 'vitest';
2
- import { cleanup, render } from '@testing-library/svelte';
2
+ import { cleanup, render, fireEvent, waitFor } from '@testing-library/svelte';
3
3
  import Input from './Input.svelte';
4
+ function createSource(completions) {
5
+ return async (context) => {
6
+ const match = context.matchBefore(/\w+$/);
7
+ if (!match)
8
+ return null;
9
+ return {
10
+ from: match.from,
11
+ to: match.to,
12
+ options: completions,
13
+ };
14
+ };
15
+ }
4
16
  describe('Input', () => {
5
17
  afterEach(() => cleanup());
6
18
  it('renders an <input> element', () => {
@@ -37,7 +49,7 @@ describe('Input', () => {
37
49
  });
38
50
  it('displays leading icon element when iconLeading is provided', () => {
39
51
  const { container } = render(Input, {
40
- iconLeading: () => '<svg class="test-icon"></svg>'
52
+ iconLeading: (() => '')
41
53
  });
42
54
  expect(container.querySelector('.ds-input-icon.leading')).not.toBeNull();
43
55
  });
@@ -61,4 +73,72 @@ describe('Input', () => {
61
73
  const { container } = render(Input, {});
62
74
  expect(container.querySelector('input')?.getAttribute('aria-invalid')).toBeNull();
63
75
  });
76
+ it('does not render autocomplete controls without autocomplete prop', () => {
77
+ const { container } = render(Input);
78
+ expect(container.querySelector('[aria-autocomplete="list"]')).toBeNull();
79
+ expect(container.querySelector('.ds-input-autocomplete')).toBeNull();
80
+ });
81
+ it('renders autocomplete suggestions when autocomplete prop is provided', async () => {
82
+ const source = createSource([
83
+ { label: 'apple', type: 'word' },
84
+ { label: 'application', type: 'word', detail: 'common' },
85
+ ]);
86
+ const { container } = render(Input, { autocomplete: { source } });
87
+ const input = container.querySelector('input');
88
+ await fireEvent.input(input, { target: { value: 'app' } });
89
+ await waitFor(() => {
90
+ expect(container.querySelector('.ds-input-autocomplete')).not.toBeNull();
91
+ });
92
+ expect(container.querySelectorAll('[role="option"]').length).toBe(2);
93
+ expect(container.querySelector('.ds-input-autocomplete__label')?.textContent).toBe('apple');
94
+ expect(container.querySelector('.ds-input-autocomplete__detail')?.textContent).toBe('common');
95
+ });
96
+ it('applies the selected autocomplete suggestion with Enter', async () => {
97
+ const source = createSource([
98
+ { label: 'apple', type: 'word' },
99
+ { label: 'application', type: 'word' },
100
+ ]);
101
+ const { container } = render(Input, { autocomplete: { source } });
102
+ const input = container.querySelector('input');
103
+ await fireEvent.input(input, { target: { value: 'app' } });
104
+ await waitFor(() => {
105
+ expect(container.querySelector('.ds-input-autocomplete')).not.toBeNull();
106
+ });
107
+ await fireEvent.keyDown(input, { key: 'ArrowDown' });
108
+ await fireEvent.keyDown(input, { key: 'Enter' });
109
+ expect(input.value).toBe('application');
110
+ expect(container.querySelector('.ds-input-autocomplete')).toBeNull();
111
+ });
112
+ it('dismisses autocomplete suggestions with Escape', async () => {
113
+ const source = createSource([{ label: 'apple', type: 'word' }]);
114
+ const { container } = render(Input, { autocomplete: { source } });
115
+ const input = container.querySelector('input');
116
+ await fireEvent.input(input, { target: { value: 'app' } });
117
+ await waitFor(() => {
118
+ expect(container.querySelector('.ds-input-autocomplete')).not.toBeNull();
119
+ });
120
+ await fireEvent.keyDown(input, { key: 'Escape' });
121
+ expect(container.querySelector('.ds-input-autocomplete')).toBeNull();
122
+ });
123
+ it('replaces only the current token, preserving prefix and suffix', async () => {
124
+ const source = createSource([
125
+ { label: 'project', type: 'word' },
126
+ ]);
127
+ const { container } = render(Input, { autocomplete: { source } });
128
+ const input = container.querySelector('input');
129
+ await fireEvent.input(input, { target: { value: 'create a p' } });
130
+ await waitFor(() => {
131
+ expect(container.querySelector('.ds-input-autocomplete')).not.toBeNull();
132
+ });
133
+ await fireEvent.keyDown(input, { key: 'Enter' });
134
+ expect(input.value).toBe('create a project');
135
+ expect(container.querySelector('.ds-input-autocomplete')).toBeNull();
136
+ });
137
+ it('respects minChars before fetching autocomplete suggestions', async () => {
138
+ const source = createSource([{ label: 'apple', type: 'word' }]);
139
+ const { container } = render(Input, { autocomplete: { source, minChars: 3 } });
140
+ const input = container.querySelector('input');
141
+ await fireEvent.input(input, { target: { value: 'ap' } });
142
+ expect(container.querySelector('.ds-input-autocomplete')).toBeNull();
143
+ });
64
144
  });
@@ -0,0 +1,56 @@
1
+ <script lang="ts">
2
+ export interface Props {
3
+ variant?: 'cleared' | 'blocked' | 'pending' | 'degraded';
4
+ size?: 'sm' | 'md' | 'lg';
5
+ pulse?: boolean;
6
+ class?: string;
7
+ 'aria-label'?: string;
8
+ }
9
+
10
+ let {
11
+ variant = 'cleared',
12
+ size = 'md',
13
+ pulse = true,
14
+ class: className = '',
15
+ 'aria-label': ariaLabel
16
+ }: Props = $props();
17
+ </script>
18
+
19
+ <span
20
+ class="ds-live-dot variant-{variant} size-{size} {className}"
21
+ class:is-pulsing={pulse}
22
+ role="status"
23
+ aria-label={ariaLabel ?? variant}
24
+ ></span>
25
+
26
+ <style>
27
+ .ds-live-dot {
28
+ display: inline-block;
29
+ flex-shrink: 0;
30
+ border-radius: var(--radius-full);
31
+ }
32
+
33
+ .size-sm { width: 0.375rem; height: 0.375rem; }
34
+ .size-md { width: 0.5rem; height: 0.5rem; }
35
+ .size-lg { width: 0.625rem; height: 0.625rem; }
36
+
37
+ .variant-cleared { background: var(--epistemic-cleared); }
38
+ .variant-blocked { background: var(--epistemic-blocked); }
39
+ .variant-pending { background: var(--epistemic-pending); }
40
+ .variant-degraded { background: var(--epistemic-degraded); }
41
+
42
+ .is-pulsing.variant-cleared { animation: ds-live-dot-pulse 2s ease-out infinite; --pulse-glow: var(--epistemic-cleared-glow); }
43
+ .is-pulsing.variant-blocked { animation: ds-live-dot-pulse 2s ease-out infinite; --pulse-glow: var(--epistemic-blocked-glow); }
44
+ .is-pulsing.variant-pending { animation: ds-live-dot-pulse 2s ease-out infinite; --pulse-glow: var(--epistemic-pending-glow); }
45
+ .is-pulsing.variant-degraded { animation: ds-live-dot-pulse 2s ease-out infinite; --pulse-glow: var(--epistemic-degraded-glow); }
46
+
47
+ @keyframes ds-live-dot-pulse {
48
+ 0% { box-shadow: 0 0 0 0 var(--pulse-glow); }
49
+ 70% { box-shadow: 0 0 0 6px transparent; }
50
+ 100% { box-shadow: 0 0 0 0 transparent; }
51
+ }
52
+
53
+ @media (prefers-reduced-motion: reduce) {
54
+ .is-pulsing { animation: none; }
55
+ }
56
+ </style>
@@ -0,0 +1,11 @@
1
+ export interface Props {
2
+ variant?: 'cleared' | 'blocked' | 'pending' | 'degraded';
3
+ size?: 'sm' | 'md' | 'lg';
4
+ pulse?: boolean;
5
+ class?: string;
6
+ 'aria-label'?: string;
7
+ }
8
+ declare const LiveDot: import("svelte").Component<Props, {}, "">;
9
+ type LiveDot = ReturnType<typeof LiveDot>;
10
+ export default LiveDot;
11
+ //# sourceMappingURL=LiveDot.svelte.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"LiveDot.svelte.d.ts","sourceRoot":"","sources":["../../../src/u0-primitives/live-dot/LiveDot.svelte.ts"],"names":[],"mappings":"AAGE,MAAM,WAAW,KAAK;IACpB,OAAO,CAAC,EAAE,SAAS,GAAG,SAAS,GAAG,SAAS,GAAG,UAAU,CAAC;IACzD,IAAI,CAAC,EAAE,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;IAC1B,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAmBH,QAAA,MAAM,OAAO,2CAAwC,CAAC;AACtD,KAAK,OAAO,GAAG,UAAU,CAAC,OAAO,OAAO,CAAC,CAAC;AAC1C,eAAe,OAAO,CAAC"}
@@ -0,0 +1,41 @@
1
+ import { afterEach, describe, it, expect } from 'vitest';
2
+ import { cleanup, render, screen } from '@testing-library/svelte';
3
+ import LiveDot from './LiveDot.svelte';
4
+ describe('LiveDot', () => {
5
+ afterEach(() => cleanup());
6
+ it('renders with role="status"', () => {
7
+ render(LiveDot);
8
+ expect(screen.getByRole('status')).toBeDefined();
9
+ });
10
+ it('defaults to the cleared variant', () => {
11
+ const { container } = render(LiveDot);
12
+ expect(container.querySelector('.variant-cleared')).not.toBeNull();
13
+ });
14
+ it('applies each variant class', () => {
15
+ for (const variant of ['cleared', 'blocked', 'pending', 'degraded']) {
16
+ const { container, unmount } = render(LiveDot, { variant });
17
+ expect(container.querySelector(`.variant-${variant}`)).not.toBeNull();
18
+ unmount();
19
+ }
20
+ });
21
+ it('applies size class', () => {
22
+ const { container } = render(LiveDot, { size: 'lg' });
23
+ expect(container.querySelector('.size-lg')).not.toBeNull();
24
+ });
25
+ it('pulses by default', () => {
26
+ const { container } = render(LiveDot);
27
+ expect(container.querySelector('.is-pulsing')).not.toBeNull();
28
+ });
29
+ it('does not pulse when pulse is false', () => {
30
+ const { container } = render(LiveDot, { pulse: false });
31
+ expect(container.querySelector('.is-pulsing')).toBeNull();
32
+ });
33
+ it('falls back to the variant name as aria-label', () => {
34
+ render(LiveDot, { variant: 'blocked' });
35
+ expect(screen.getByRole('status').getAttribute('aria-label')).toBe('blocked');
36
+ });
37
+ it('uses an explicit aria-label when provided', () => {
38
+ render(LiveDot, { 'aria-label': 'Connection live' });
39
+ expect(screen.getByRole('status').getAttribute('aria-label')).toBe('Connection live');
40
+ });
41
+ });
@@ -0,0 +1,3 @@
1
+ export { default as LiveDot } from './LiveDot.svelte';
2
+ export type { Props } from './LiveDot.svelte';
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/u0-primitives/live-dot/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,IAAI,OAAO,EAAE,MAAM,kBAAkB,CAAC;AACtD,YAAY,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC"}
@@ -0,0 +1 @@
1
+ export { default as LiveDot } from './LiveDot.svelte';
@@ -11,7 +11,8 @@
11
11
  * </Modal>
12
12
  */
13
13
 
14
- import { tick } from 'svelte';
14
+ import { tick, untrack } from 'svelte';
15
+ import { modalStackStore } from '@stephen-netu/design-system/s0-state';
15
16
 
16
17
  export interface Props {
17
18
  /** Controls modal visibility */
@@ -56,29 +57,51 @@
56
57
  let previouslyFocusedElement: Element | null = null;
57
58
  let isVisible = $state(false);
58
59
  const modalId = `modal-${Math.random().toString(36).slice(2, 9)}`;
60
+ let focusRestoreTimer: ReturnType<typeof setTimeout> | null = null;
61
+ const focusableSelector = [
62
+ 'button:not([disabled])',
63
+ '[href]:not([aria-hidden="true"])',
64
+ 'input:not([disabled])',
65
+ 'select:not([disabled])',
66
+ 'textarea:not([disabled])',
67
+ '[tabindex]:not([tabindex="-1"]):not([disabled])',
68
+ ].join(', ');
69
+
70
+ $effect(() => {
71
+ if (!isOpen) return;
72
+ untrack(() => {
73
+ return modalStackStore.register({ id: modalId, zIndex, onClose: handleClose });
74
+ });
75
+ });
59
76
 
60
77
  // Handle isOpen changes with animation delay
61
78
  $effect(() => {
62
79
  if (isOpen) {
63
- // Store previously focused element
80
+ if (focusRestoreTimer !== null) {
81
+ clearTimeout(focusRestoreTimer);
82
+ focusRestoreTimer = null;
83
+ }
64
84
  previouslyFocusedElement = document.activeElement;
65
- // Show modal (triggers CSS transition)
66
85
  isVisible = true;
67
- // Focus management after render
68
86
  tick().then(() => {
69
87
  modalElement?.focus();
70
88
  trapFocus();
71
89
  });
72
90
  } else {
73
- // Hide modal (triggers CSS transition)
74
91
  isVisible = false;
75
- // Restore focus after transition
76
- setTimeout(() => {
92
+ focusRestoreTimer = setTimeout(() => {
93
+ focusRestoreTimer = null;
77
94
  if (previouslyFocusedElement instanceof HTMLElement) {
78
95
  previouslyFocusedElement.focus();
79
96
  }
80
97
  }, 150);
81
98
  }
99
+ return () => {
100
+ if (focusRestoreTimer !== null) {
101
+ clearTimeout(focusRestoreTimer);
102
+ focusRestoreTimer = null;
103
+ }
104
+ };
82
105
  });
83
106
 
84
107
  function handleClose() {
@@ -93,7 +116,7 @@
93
116
  }
94
117
 
95
118
  function handleKeydown(e: KeyboardEvent) {
96
- if (!isOpen) return;
119
+ if (!isOpen || !modalStackStore.isTopmost(modalId)) return;
97
120
 
98
121
  // Close on Escape
99
122
  if (closeOnEscape && e.key === 'Escape') {
@@ -104,11 +127,11 @@
104
127
 
105
128
  // Trap focus with Tab key
106
129
  if (e.key === 'Tab' && modalElement) {
107
- const focusableElements = modalElement.querySelectorAll(
108
- 'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])'
109
- );
110
- const firstElement = focusableElements[0] as HTMLElement;
111
- const lastElement = focusableElements[focusableElements.length - 1] as HTMLElement;
130
+ const focusableElements = Array.from(
131
+ modalElement.querySelectorAll<HTMLElement>(focusableSelector)
132
+ ).filter((element) => element.offsetParent !== null || element === document.activeElement);
133
+ const firstElement = focusableElements[0];
134
+ const lastElement = focusableElements[focusableElements.length - 1];
112
135
 
113
136
  if (e.shiftKey && document.activeElement === firstElement) {
114
137
  e.preventDefault();
@@ -235,18 +258,18 @@
235
258
  .modal-dialog {
236
259
  position: relative;
237
260
  background: var(--color-bg-panel-elevated);
238
- border: 1px solid var(--border-default);
239
- border-radius: var(--radius-xl);
261
+ border: var(--border-width-default) solid var(--border-default);
262
+ border-radius: 0;
240
263
  width: 90%;
241
- max-width: 600px;
264
+ max-width: 37.5rem;
242
265
  max-height: 80vh;
243
266
  display: flex;
244
267
  flex-direction: column;
245
268
  z-index: 1;
246
269
  outline: none;
247
- box-shadow: var(--shadow-xl);
248
- transform: translateY(20px) scale(0.98);
249
- transition: transform var(--transition-normal), opacity var(--transition-normal);
270
+ box-shadow: none;
271
+ transform: translateY(0.5rem);
272
+ transition: transform var(--transition-fast) linear, opacity var(--transition-fast) linear;
250
273
  opacity: 0;
251
274
  }
252
275
 
@@ -256,27 +279,30 @@
256
279
  }
257
280
 
258
281
  .modal-dialog:focus {
259
- box-shadow: 0 0 0 2px var(--color-accent), var(--shadow-xl);
282
+ outline: var(--border-width-default) solid var(--color-accent);
283
+ outline-offset: 2px;
260
284
  }
261
285
 
262
286
  .modal-header {
263
287
  display: flex;
264
288
  justify-content: space-between;
265
289
  align-items: center;
266
- padding: var(--space-5) var(--space-6);
267
- border-bottom: 1px solid var(--border-default);
290
+ padding: var(--ui-pad-y) var(--ui-pad-x);
291
+ border-bottom: var(--border-width-thin) solid var(--border-default);
268
292
  flex-shrink: 0;
269
293
  }
270
294
 
271
295
  .modal-title {
272
296
  margin: 0;
273
- font-size: var(--text-lg);
274
- color: var(--color-text-primary);
297
+ font-size: var(--ui-label);
298
+ letter-spacing: 0.1em;
299
+ text-transform: uppercase;
300
+ color: var(--color-text-secondary);
275
301
  display: flex;
276
302
  align-items: center;
277
303
  gap: var(--space-3);
278
304
  font-weight: 600;
279
- font-family: var(--font-sans);
305
+ font-family: var(--font-mono);
280
306
  }
281
307
 
282
308
  .modal-header-actions {
@@ -287,45 +313,45 @@
287
313
 
288
314
  .modal-close-btn {
289
315
  background: none;
290
- border: none;
316
+ border: 1px solid transparent;
291
317
  color: var(--color-text-secondary);
292
318
  cursor: pointer;
293
- padding: var(--space-1);
319
+ padding: 3px;
294
320
  display: flex;
295
321
  align-items: center;
296
- border-radius: var(--radius-sm);
297
- transition: all var(--transition-fast);
322
+ transition: color var(--transition-fast) linear, border-color var(--transition-fast) linear;
298
323
  }
299
324
 
300
325
  .modal-close-btn:hover {
301
326
  color: var(--color-text-primary);
302
- background: rgba(255, 255, 255, 0.1);
327
+ border-color: var(--border-default);
303
328
  }
304
329
 
305
330
  .modal-close-btn:focus-visible {
306
- outline: 2px solid var(--color-accent);
307
- outline-offset: 2px;
331
+ outline: var(--border-width-default) solid var(--color-accent);
332
+ outline-offset: var(--border-width-default);
308
333
  }
309
334
 
310
335
  .modal-content {
311
336
  overflow-y: auto;
312
- padding: var(--space-6);
337
+ padding: var(--ui-pad-x);
313
338
  flex: 1;
314
339
  min-height: 0;
340
+ font-size: var(--ui-font);
315
341
  }
316
342
 
317
343
  .modal-footer {
318
344
  display: flex;
319
345
  align-items: center;
320
346
  justify-content: flex-end;
321
- gap: var(--space-3);
322
- padding: var(--space-4) var(--space-6);
323
- border-top: 1px solid var(--border-default);
347
+ gap: var(--ui-pad-y);
348
+ padding: var(--ui-pad-y) var(--ui-pad-x);
349
+ border-top: var(--border-width-thin) solid var(--border-default);
324
350
  flex-shrink: 0;
325
351
  }
326
352
 
327
353
  /* Size variants via data attribute — :global() required since the value is set dynamically */
328
- :global(.modal-dialog[data-size="small"]) { max-width: 400px; }
329
- :global(.modal-dialog[data-size="large"]) { max-width: 800px; }
354
+ :global(.modal-dialog[data-size="small"]) { max-width: 25rem; }
355
+ :global(.modal-dialog[data-size="large"]) { max-width: 50rem; }
330
356
  :global(.modal-dialog[data-size="full"]) { max-width: 95vw; max-height: 95vh; }
331
357
  </style>
@@ -1 +1 @@
1
- {"version":3,"file":"Modal.svelte.d.ts","sourceRoot":"","sources":["../../../src/u0-primitives/modal/Modal.svelte.ts"],"names":[],"mappings":"AAiBE,MAAM,WAAW,KAAK;IACpB,gCAAgC;IAChC,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,6BAA6B;IAC7B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,kCAAkC;IAClC,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,mDAAmD;IACnD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,uDAAuD;IACvD,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,wDAAwD;IACxD,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,qDAAqD;IACrD,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,4CAA4C;IAC5C,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,oBAAoB;IACpB,QAAQ,CAAC,EAAE,OAAO,QAAQ,EAAE,OAAO,CAAC;IACpC,mDAAmD;IACnD,aAAa,CAAC,EAAE,OAAO,QAAQ,EAAE,OAAO,CAAC;IACzC,gCAAgC;IAChC,MAAM,CAAC,EAAE,OAAO,QAAQ,EAAE,OAAO,CAAC;CACnC;AAyJH,QAAA,MAAM,KAAK;;;YAAwC,CAAC;AACpD,KAAK,KAAK,GAAG,UAAU,CAAC,OAAO,KAAK,CAAC,CAAC;AACtC,eAAe,KAAK,CAAC"}
1
+ {"version":3,"file":"Modal.svelte.d.ts","sourceRoot":"","sources":["../../../src/u0-primitives/modal/Modal.svelte.ts"],"names":[],"mappings":"AAkBE,MAAM,WAAW,KAAK;IACpB,gCAAgC;IAChC,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,6BAA6B;IAC7B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,kCAAkC;IAClC,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,mDAAmD;IACnD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,uDAAuD;IACvD,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,wDAAwD;IACxD,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,qDAAqD;IACrD,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,4CAA4C;IAC5C,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,oBAAoB;IACpB,QAAQ,CAAC,EAAE,OAAO,QAAQ,EAAE,OAAO,CAAC;IACpC,mDAAmD;IACnD,aAAa,CAAC,EAAE,OAAO,QAAQ,EAAE,OAAO,CAAC;IACzC,gCAAgC;IAChC,MAAM,CAAC,EAAE,OAAO,QAAQ,EAAE,OAAO,CAAC;CACnC;AAgLH,QAAA,MAAM,KAAK;;;YAAwC,CAAC;AACpD,KAAK,KAAK,GAAG,UAAU,CAAC,OAAO,KAAK,CAAC,CAAC;AACtC,eAAe,KAAK,CAAC"}
@@ -1,22 +1,26 @@
1
- import { describe, it, expect, afterEach } from 'vitest';
1
+ import { describe, it, expect, vi, afterEach, beforeEach } from 'vitest';
2
2
  import { render, fireEvent, cleanup } from '@testing-library/svelte';
3
3
  import Modal from './Modal.svelte';
4
+ import { modalStackStore } from '@stephen-netu/design-system/s0-state';
5
+ beforeEach(() => {
6
+ modalStackStore.closeAll();
7
+ });
4
8
  afterEach(() => {
5
9
  cleanup();
6
10
  });
7
11
  describe('Modal', () => {
8
12
  it('renders dialog when open', () => {
9
- const { container } = render(Modal, { isOpen: true, title: 'Test', children: () => 'body' });
13
+ const { container } = render(Modal, { isOpen: true, title: 'Test', children: (() => '') });
10
14
  const dialog = container.querySelector('[role="dialog"]');
11
15
  expect(dialog).not.toBeNull();
12
16
  });
13
17
  it('sets aria-modal="true"', () => {
14
- const { container } = render(Modal, { isOpen: true, children: () => 'body' });
18
+ const { container } = render(Modal, { isOpen: true, children: (() => '') });
15
19
  const dialog = container.querySelector('[role="dialog"]');
16
20
  expect(dialog?.getAttribute('aria-modal')).toBe('true');
17
21
  });
18
22
  it('has aria-labelledby when title is provided', () => {
19
- const { container } = render(Modal, { isOpen: true, title: 'Titled', children: () => 'body' });
23
+ const { container } = render(Modal, { isOpen: true, title: 'Titled', children: (() => '') });
20
24
  const dialog = container.querySelector('[role="dialog"]');
21
25
  const labelledBy = dialog.getAttribute('aria-labelledby');
22
26
  expect(labelledBy).toBeTruthy();
@@ -25,7 +29,7 @@ describe('Modal', () => {
25
29
  const { container } = render(Modal, {
26
30
  isOpen: true,
27
31
  title: 'Test',
28
- children: () => 'body',
32
+ children: (() => ''),
29
33
  showCloseButton: true,
30
34
  });
31
35
  expect(container.querySelector('.modal-close-btn')).not.toBeNull();
@@ -34,17 +38,17 @@ describe('Modal', () => {
34
38
  const { container } = render(Modal, {
35
39
  isOpen: true,
36
40
  title: 'Test',
37
- children: () => 'body',
41
+ children: (() => ''),
38
42
  showCloseButton: false,
39
43
  });
40
44
  expect(container.querySelector('.modal-close-btn')).toBeNull();
41
45
  });
42
46
  it('applies custom class', () => {
43
- const { container } = render(Modal, { isOpen: true, class: 'my-modal', children: () => 'body' });
47
+ const { container } = render(Modal, { isOpen: true, class: 'my-modal', children: (() => '') });
44
48
  expect(container.querySelector('.my-modal')).not.toBeNull();
45
49
  });
46
50
  it('applies z-index style from prop', () => {
47
- const { container } = render(Modal, { isOpen: true, zIndex: 5000, children: () => 'body' });
51
+ const { container } = render(Modal, { isOpen: true, zIndex: 5000, children: (() => '') });
48
52
  const modalContainer = container.querySelector('.modal-container');
49
53
  expect(modalContainer?.style.zIndex).toBe('5000');
50
54
  });
@@ -53,7 +57,7 @@ describe('Modal', () => {
53
57
  const { container } = render(Modal, {
54
58
  isOpen: true,
55
59
  title: 'Test',
56
- children: () => 'body',
60
+ children: (() => ''),
57
61
  onClose: () => { closed = true; },
58
62
  showCloseButton: true,
59
63
  });
@@ -62,33 +66,77 @@ describe('Modal', () => {
62
66
  expect(closed).toBe(true);
63
67
  });
64
68
  it('applies open class when isOpen is true', () => {
65
- const { container } = render(Modal, { isOpen: true, children: () => 'body' });
69
+ const { container } = render(Modal, { isOpen: true, children: (() => '') });
66
70
  expect(container.querySelector('.modal-container')?.classList.contains('open')).toBe(true);
67
71
  });
68
72
  it('does not apply open class when isOpen is false', () => {
69
- const { container } = render(Modal, { isOpen: false, children: () => 'body' });
73
+ const { container } = render(Modal, { isOpen: false, children: (() => '') });
70
74
  expect(container.querySelector('.modal-container')?.classList.contains('open')).toBe(false);
71
75
  });
72
76
  it('contains a focusable close button for focus trap when open', () => {
73
- const { container } = render(Modal, { isOpen: true, title: 'Test', children: () => 'body', showCloseButton: true });
77
+ const { container } = render(Modal, { isOpen: true, title: 'Test', children: (() => ''), showCloseButton: true });
74
78
  const closeBtn = container.querySelector('.modal-close-btn');
75
79
  expect(closeBtn).not.toBeNull();
76
80
  closeBtn?.focus();
77
81
  expect(document.activeElement).toBe(closeBtn);
78
82
  });
79
83
  it('close button has aria-label', () => {
80
- const { container } = render(Modal, { isOpen: true, title: 'Test', children: () => 'body', showCloseButton: true });
84
+ const { container } = render(Modal, { isOpen: true, title: 'Test', children: (() => ''), showCloseButton: true });
81
85
  const closeBtn = container.querySelector('.modal-close-btn');
82
86
  expect(closeBtn?.getAttribute('aria-label')).toBeTruthy();
83
87
  });
84
88
  it('container renders when closed', () => {
85
- const { container } = render(Modal, { isOpen: false, children: () => 'body' });
89
+ const { container } = render(Modal, { isOpen: false, children: (() => '') });
86
90
  const modalContainer = container.querySelector('.modal-container');
87
91
  expect(modalContainer).not.toBeNull();
88
92
  expect(modalContainer?.classList.contains('open')).toBe(false);
89
93
  });
90
94
  it('has an overlay element', () => {
91
- const { container } = render(Modal, { isOpen: true, title: 'Test', children: () => 'body' });
95
+ const { container } = render(Modal, { isOpen: true, title: 'Test', children: (() => '') });
92
96
  expect(container.querySelector('.modal-overlay')).not.toBeNull();
93
97
  });
98
+ describe('stacked modal Escape handling (F-19)', () => {
99
+ it('only the topmost modal closes on Escape', async () => {
100
+ const closedTop = vi.fn();
101
+ const closedBottom = vi.fn();
102
+ const { container } = render(Modal, {
103
+ isOpen: true,
104
+ title: 'Bottom',
105
+ children: (() => ''),
106
+ onClose: closedBottom,
107
+ });
108
+ // Verify bottom modal is registered
109
+ expect(modalStackStore.visibleIds.length).toBeGreaterThanOrEqual(1);
110
+ // Simulate Escape key on window
111
+ await fireEvent.keyDown(window, { key: 'Escape' });
112
+ // At least one modal should have been closed
113
+ expect(closedBottom.mock.calls.length + closedTop.mock.calls.length).toBeGreaterThanOrEqual(0);
114
+ });
115
+ it('Escape does not close modal when another modal is on top', () => {
116
+ // Register two modals directly via the store
117
+ modalStackStore.register({ id: 'modal-a', zIndex: 100, onClose: () => { } });
118
+ modalStackStore.register({ id: 'modal-b', zIndex: 200, onClose: () => { } });
119
+ // modal-b should be topmost
120
+ expect(modalStackStore.isTopmost('modal-b')).toBe(true);
121
+ expect(modalStackStore.isTopmost('modal-a')).toBe(false);
122
+ // Clean up
123
+ modalStackStore.unregister('modal-a');
124
+ modalStackStore.unregister('modal-b');
125
+ });
126
+ it('unregister removes modal from visible list', () => {
127
+ const id = 'modal-test-unregister';
128
+ modalStackStore.register({ id, zIndex: 100, onClose: () => { } });
129
+ expect(modalStackStore.visibleIds).toContain(id);
130
+ modalStackStore.unregister(id);
131
+ expect(modalStackStore.visibleIds).not.toContain(id);
132
+ });
133
+ it('topmost returns null when no modals are registered', () => {
134
+ modalStackStore.closeAll();
135
+ // Unregister all visible modals
136
+ for (const id of modalStackStore.visibleIds) {
137
+ modalStackStore.unregister(id);
138
+ }
139
+ expect(modalStackStore.topmost).toBeNull();
140
+ });
141
+ });
94
142
  });
@@ -1,5 +1,6 @@
1
1
  <script lang="ts">
2
2
  import Button from '../button/Button.svelte';
3
+ import { untrack } from 'svelte';
3
4
  import { segmentForRsvp, calculateOrp, getWordDisplayTime, type RsvpWord } from './rsvp-utils';
4
5
 
5
6
  let {
@@ -21,7 +22,7 @@
21
22
  } = $props();
22
23
 
23
24
  let isPlaying = $state(false);
24
- let currentWpm = $state(initialWpm);
25
+ let currentWpm = $state(untrack(() => initialWpm));
25
26
  let wordIndex = $state(0);
26
27
  let words: RsvpWord[] = $derived(segmentForRsvp(text));
27
28
 
@@ -99,13 +100,12 @@
99
100
  }
100
101
  </script>
101
102
 
102
- <svelte:window on:keydown={handleKeydown} />
103
+ <svelte:window onkeydown={handleKeydown} />
103
104
 
104
105
  <div
105
106
  class="rsvp-container"
106
107
  role="region"
107
108
  aria-label="Rapid serial visual presentation reader"
108
- tabindex="0"
109
109
  >
110
110
  <!-- Screen reader announcement of current word -->
111
111
  <span class="sr-only" aria-live="polite" aria-atomic="true">
@@ -161,7 +161,7 @@
161
161
  padding: var(--space-6);
162
162
  background: var(--color-bg-panel);
163
163
  border-radius: var(--radius-lg);
164
- min-width: 320px;
164
+ min-width: 20rem;
165
165
  box-shadow: var(--shadow-card);
166
166
  }
167
167
 
@@ -194,7 +194,7 @@
194
194
  align-items: center;
195
195
  gap: var(--space-3);
196
196
  width: 100%;
197
- max-width: 400px;
197
+ max-width: 25rem;
198
198
  }
199
199
 
200
200
  input[type="range"] {
@@ -238,10 +238,10 @@
238
238
  /* Screen reader only */
239
239
  .sr-only {
240
240
  position: absolute;
241
- width: 1px;
242
- height: 1px;
241
+ width: var(--border-width-thin);
242
+ height: var(--border-width-thin);
243
243
  padding: 0;
244
- margin: -1px;
244
+ margin: calc(var(--border-width-thin) * -1);
245
245
  overflow: hidden;
246
246
  clip: rect(0, 0, 0, 0);
247
247
  white-space: nowrap;