@stephen-netu/design-system 0.2.0 → 0.2.2

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 (198) 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/CheckpointPill.svelte +7 -2
  10. package/dist/d0-data-viz/CheckpointPill.svelte.d.ts.map +1 -1
  11. package/dist/d0-data-viz/theme-integration.d.ts +3 -3
  12. package/dist/d0-data-viz/theme-integration.js +3 -3
  13. package/dist/d0-data-viz/theme-integration.test.js +41 -0
  14. package/dist/demos/BspSizingInfographic.svelte +3 -32
  15. package/dist/editor/CodeEditor.test.js +38 -0
  16. package/dist/editor/FindReplaceDialog.svelte +32 -32
  17. package/dist/editor/MarkdownEditor.svelte +71 -58
  18. package/dist/editor/MarkdownEditor.svelte.d.ts.map +1 -1
  19. package/dist/editor/MarkdownEditor.test.js +38 -0
  20. package/dist/editor/components/CorrectionTooltip.svelte +0 -1
  21. package/dist/editor/extensions/expansion.d.ts.map +1 -1
  22. package/dist/editor/extensions/expansion.js +16 -10
  23. package/dist/entity-graph-view/WorldView.svelte +1 -1
  24. package/dist/fabric/ai/ChatPanel.svelte +31 -31
  25. package/dist/fabric/ai/ResearchPanel.svelte +6 -3
  26. package/dist/fabric/ai/ResearchPanel.svelte.d.ts.map +1 -1
  27. package/dist/fabric/index.d.ts +4 -5
  28. package/dist/fabric/index.d.ts.map +1 -1
  29. package/dist/fabric/index.js +3 -3
  30. package/dist/fabric/input/{CommandBar.svelte → AppHeaderBar.svelte} +13 -13
  31. package/dist/fabric/input/{CommandBar.svelte.d.ts → AppHeaderBar.svelte.d.ts} +5 -5
  32. package/dist/fabric/input/AppHeaderBar.svelte.d.ts.map +1 -0
  33. package/dist/fabric/input/{CommandBar.test.js → AppHeaderBar.test.js} +9 -9
  34. package/dist/fabric/input/index.d.ts +2 -2
  35. package/dist/fabric/input/index.d.ts.map +1 -1
  36. package/dist/fabric/input/index.js +1 -1
  37. package/dist/fabric/layout/KanbanBoard.svelte +25 -155
  38. package/dist/fabric/layout/KanbanBoard.svelte.d.ts +2 -26
  39. package/dist/fabric/layout/KanbanBoard.svelte.d.ts.map +1 -1
  40. package/dist/fabric/layout/KanbanBoard.test.js +125 -10
  41. package/dist/fabric/layout/KanbanCard.svelte +27 -223
  42. package/dist/fabric/layout/KanbanCard.svelte.d.ts +2 -19
  43. package/dist/fabric/layout/KanbanCard.svelte.d.ts.map +1 -1
  44. package/dist/fabric/layout/KanbanColumn.svelte +41 -275
  45. package/dist/fabric/layout/KanbanColumn.svelte.d.ts +2 -22
  46. package/dist/fabric/layout/KanbanColumn.svelte.d.ts.map +1 -1
  47. package/dist/fabric/layout/index.d.ts +2 -5
  48. package/dist/fabric/layout/index.d.ts.map +1 -1
  49. package/dist/fabric/layout/index.js +1 -1
  50. package/dist/g0-generative/renderer/OpenUIRenderer.svelte +3 -3
  51. package/dist/index.d.ts.map +1 -1
  52. package/dist/index.js +4 -2
  53. package/dist/l0-layout/SectionSplitter.svelte +5 -5
  54. package/dist/l0-layout/block-writer/BlockItem.svelte +6 -4
  55. package/dist/l0-layout/card/CompactCard.svelte +4 -3
  56. package/dist/l0-layout/grant/GrantCard.svelte +15 -5
  57. package/dist/l0-layout/grant/GrantCard.svelte.d.ts.map +1 -1
  58. package/dist/l0-layout/index.d.ts +2 -0
  59. package/dist/l0-layout/index.d.ts.map +1 -1
  60. package/dist/l0-layout/index.js +1 -0
  61. package/dist/l0-layout/kanban/KanbanBoard.svelte +246 -29
  62. package/dist/l0-layout/kanban/KanbanBoard.svelte.d.ts +28 -2
  63. package/dist/l0-layout/kanban/KanbanBoard.svelte.d.ts.map +1 -1
  64. package/dist/l0-layout/kanban/KanbanCard.svelte +175 -150
  65. package/dist/l0-layout/kanban/KanbanCard.svelte.d.ts +16 -18
  66. package/dist/l0-layout/kanban/KanbanCard.svelte.d.ts.map +1 -1
  67. package/dist/l0-layout/kanban/KanbanColumn.svelte +152 -78
  68. package/dist/l0-layout/kanban/KanbanColumn.svelte.d.ts +28 -7
  69. package/dist/l0-layout/kanban/KanbanColumn.svelte.d.ts.map +1 -1
  70. package/dist/l0-layout/kanban/index.d.ts +6 -0
  71. package/dist/l0-layout/kanban/index.d.ts.map +1 -0
  72. package/dist/l0-layout/kanban/index.js +3 -0
  73. package/dist/n0-node-graph/Node.svelte +2 -2
  74. package/dist/n0-node-graph/NodePalette.svelte +2 -2
  75. package/dist/n1-flow-canvas/graph-state.test.js +69 -0
  76. package/dist/n1-flow-canvas/utils.test.js +116 -0
  77. package/dist/n3-force-graph/GraphTooltip.svelte +2 -2
  78. package/dist/n4-adaptive-manifold/AdaptiveManifold.svelte +12 -11
  79. package/dist/n4-adaptive-manifold/AdaptiveManifold.svelte.d.ts.map +1 -1
  80. package/dist/n4-adaptive-manifold/classifier.test.js +104 -0
  81. package/dist/n4-adaptive-manifold/n4-tokens.css +2 -2
  82. package/dist/p0-primitives/ThemeProvider.svelte +10 -11
  83. package/dist/p0-primitives/ThemeProvider.svelte.d.ts +1 -1
  84. package/dist/p0-primitives/ThemeProvider.svelte.d.ts.map +1 -1
  85. package/dist/p0-primitives/canvas-theme.d.ts +12 -0
  86. package/dist/p0-primitives/canvas-theme.d.ts.map +1 -1
  87. package/dist/p0-primitives/canvas-theme.js +10 -0
  88. package/dist/p0-primitives/index.d.ts +2 -1
  89. package/dist/p0-primitives/index.d.ts.map +1 -1
  90. package/dist/p0-primitives/index.js +1 -0
  91. package/dist/p0-primitives/theme-context.d.ts +9 -0
  92. package/dist/p0-primitives/theme-context.d.ts.map +1 -0
  93. package/dist/p0-primitives/theme-context.js +8 -0
  94. package/dist/p0-primitives/tokens/tokens.css +22 -11
  95. package/dist/p0-primitives/utils/index.d.ts +2 -2
  96. package/dist/p0-primitives/utils/index.d.ts.map +1 -1
  97. package/dist/s0-state/SyncStatus.svelte +1 -1
  98. package/dist/s0-state/ThemeStore.svelte.d.ts +3 -2
  99. package/dist/s0-state/ThemeStore.svelte.d.ts.map +1 -1
  100. package/dist/s0-state/ThemeStore.svelte.js +20 -1
  101. package/dist/s0-state/index.d.ts +0 -1
  102. package/dist/s0-state/index.d.ts.map +1 -1
  103. package/dist/s0-state/index.js +1 -0
  104. package/dist/s0-state/modal-stack-store.svelte.d.ts +25 -0
  105. package/dist/s0-state/modal-stack-store.svelte.d.ts.map +1 -1
  106. package/dist/s0-state/modal-stack-store.svelte.js +19 -0
  107. package/dist/showcase/Showcase.svelte +43 -34
  108. package/dist/showcase/Showcase.svelte.d.ts.map +1 -1
  109. package/dist/spatial/BspTilingCanvas.svelte +7 -5
  110. package/dist/spatial/BspTilingCanvas.svelte.d.ts +1 -0
  111. package/dist/spatial/BspTilingCanvas.svelte.d.ts.map +1 -1
  112. package/dist/spatial/BspTilingSimulation.test.js +88 -0
  113. package/dist/spatial/CameraController.test.js +120 -0
  114. package/dist/spatial/ForceCanvas.svelte +20 -13
  115. package/dist/spatial/ForceCanvas.svelte.d.ts +1 -0
  116. package/dist/spatial/ForceCanvas.svelte.d.ts.map +1 -1
  117. package/dist/spatial/ForceSimulation.svelte.d.ts.map +1 -1
  118. package/dist/spatial/ForceSimulation.svelte.js +32 -21
  119. package/dist/spatial/LodRenderer.svelte +16 -1
  120. package/dist/spatial/LodRenderer.svelte.d.ts +1 -0
  121. package/dist/spatial/LodRenderer.svelte.d.ts.map +1 -1
  122. package/dist/spatial/SnapZoomCamera.svelte +25 -13
  123. package/dist/spatial/SnapZoomCamera.svelte.d.ts +1 -0
  124. package/dist/spatial/SnapZoomCamera.svelte.d.ts.map +1 -1
  125. package/dist/spatial/ZoneTiler.svelte +5 -2
  126. package/dist/spatial/ZoneTiler.svelte.d.ts +1 -0
  127. package/dist/spatial/ZoneTiler.svelte.d.ts.map +1 -1
  128. package/dist/spatial/d3-types.d.ts +31 -0
  129. package/dist/spatial/d3-types.d.ts.map +1 -0
  130. package/dist/spatial/d3-types.js +19 -0
  131. package/dist/ssr-import-clean.test.js +37 -0
  132. package/dist/t0-transport/fs.d.ts +12 -0
  133. package/dist/t0-transport/fs.d.ts.map +1 -0
  134. package/dist/t0-transport/fs.js +55 -0
  135. package/dist/t0-transport/index.d.ts +1 -0
  136. package/dist/t0-transport/index.d.ts.map +1 -1
  137. package/dist/t0-transport/index.js +1 -0
  138. package/dist/t0-transport/invoke.d.ts.map +1 -1
  139. package/dist/t0-transport/invoke.js +5 -2
  140. package/dist/t0-transport/quality.d.ts +12 -3
  141. package/dist/t0-transport/quality.d.ts.map +1 -1
  142. package/dist/t0-transport/quality.js +17 -4
  143. package/dist/t0-transport/substrate.svelte.d.ts +27 -0
  144. package/dist/t0-transport/substrate.svelte.d.ts.map +1 -0
  145. package/dist/t0-transport/substrate.svelte.js +49 -0
  146. package/dist/u0-primitives/LockIndicator.svelte +1 -1
  147. package/dist/u0-primitives/VerticalToolbar.svelte +1 -1
  148. package/dist/u0-primitives/accordion/Accordion.svelte +10 -9
  149. package/dist/u0-primitives/accordion/Accordion.svelte.d.ts +0 -7
  150. package/dist/u0-primitives/accordion/Accordion.svelte.d.ts.map +1 -1
  151. package/dist/u0-primitives/accordion/Accordion.test.js +5 -5
  152. package/dist/u0-primitives/badge/Badge.test.js +10 -10
  153. package/dist/u0-primitives/badge/ValidityBadge.test.js +9 -9
  154. package/dist/u0-primitives/button/Button.svelte +3 -1
  155. package/dist/u0-primitives/button/Button.svelte.d.ts +1 -0
  156. package/dist/u0-primitives/button/Button.svelte.d.ts.map +1 -1
  157. package/dist/u0-primitives/button/Button.test.js +11 -11
  158. package/dist/u0-primitives/card/Card.svelte +26 -20
  159. package/dist/u0-primitives/card/Card.svelte.d.ts.map +1 -1
  160. package/dist/u0-primitives/command-palette/CommandPalette.svelte +27 -0
  161. package/dist/u0-primitives/command-palette/CommandPalette.svelte.d.ts.map +1 -1
  162. package/dist/u0-primitives/command-palette/commandStore.svelte.d.ts.map +1 -1
  163. package/dist/u0-primitives/command-palette/commandStore.svelte.js +2 -1
  164. package/dist/u0-primitives/dropdown/Dropdown.test.js +1 -1
  165. package/dist/u0-primitives/index.d.ts +2 -0
  166. package/dist/u0-primitives/index.d.ts.map +1 -1
  167. package/dist/u0-primitives/index.js +1 -0
  168. package/dist/u0-primitives/input/Input.svelte +9 -0
  169. package/dist/u0-primitives/input/Input.svelte.d.ts.map +1 -1
  170. package/dist/u0-primitives/input/Input.test.js +1 -1
  171. package/dist/u0-primitives/modal/Modal.svelte +46 -23
  172. package/dist/u0-primitives/modal/Modal.svelte.d.ts.map +1 -1
  173. package/dist/u0-primitives/modal/Modal.test.js +63 -15
  174. package/dist/u0-primitives/rsvp/RsvpReader.svelte +8 -8
  175. package/dist/u0-primitives/rsvp/RsvpReader.svelte.d.ts.map +1 -1
  176. package/dist/u0-primitives/steps/Steps.svelte +2 -2
  177. package/dist/u0-primitives/surface-state/SurfaceState.svelte +190 -0
  178. package/dist/u0-primitives/surface-state/SurfaceState.svelte.d.ts +15 -0
  179. package/dist/u0-primitives/surface-state/SurfaceState.svelte.d.ts.map +1 -0
  180. package/dist/u0-primitives/toggle/Toggle.svelte +12 -2
  181. package/dist/u0-primitives/tooltip/Tooltip.test.js +12 -12
  182. package/dist/v0-diagrams/MarkmapDiagram.test.js +49 -0
  183. package/dist/v0-diagrams/MermaidDiagram.svelte +21 -9
  184. package/dist/v0-diagrams/MermaidDiagram.svelte.d.ts.map +1 -1
  185. package/dist/v0-diagrams/MermaidDiagram.test.js +40 -0
  186. package/package.json +51 -24
  187. package/src/n4-adaptive-manifold/n4-tokens.css +2 -2
  188. package/src/p0-primitives/tokens/tokens.css +22 -11
  189. package/src/p0-primitives/tokens/tokens.json +13 -2
  190. package/dist/b0-app-shell/command-bar/CommandBar.svelte.d.ts.map +0 -1
  191. package/dist/fabric/input/CommandBar.svelte.d.ts.map +0 -1
  192. package/dist/stores/vaultStore.svelte +0 -14
  193. package/dist/stores/vaultStore.svelte.d.ts +0 -24
  194. package/dist/stores/vaultStore.svelte.d.ts.map +0 -1
  195. package/dist/tauri/index.d.ts +0 -3
  196. package/dist/tauri/index.d.ts.map +0 -1
  197. package/dist/tauri/index.js +0 -11
  198. package/dist/types/tauri.d.ts +0 -18
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/u0-primitives/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,OAAO,IAAI,MAAM,EAAE,MAAM,wBAAwB,CAAC;AAC3D,OAAO,EAAE,OAAO,IAAI,KAAK,EAAE,MAAM,sBAAsB,CAAC;AACxD,OAAO,EAAE,OAAO,IAAI,IAAI,EAAE,MAAM,oBAAoB,CAAC;AACrD,OAAO,EAAE,OAAO,IAAI,KAAK,EAAE,MAAM,sBAAsB,CAAC;AACxD,OAAO,EAAE,OAAO,IAAI,aAAa,EAAE,MAAM,8BAA8B,CAAC;AACxE,OAAO,EAAE,OAAO,IAAI,MAAM,EAAE,MAAM,wBAAwB,CAAC;AAC3D,OAAO,EAAE,OAAO,IAAI,MAAM,EAAE,MAAM,wBAAwB,CAAC;AAC3D,OAAO,EAAE,OAAO,IAAI,OAAO,EAAE,MAAM,0BAA0B,CAAC;AAC9D,OAAO,EAAE,OAAO,IAAI,QAAQ,EAAE,MAAM,4BAA4B,CAAC;AACjE,OAAO,EAAE,OAAO,IAAI,IAAI,EAAE,MAAM,oBAAoB,CAAC;AACrD,YAAY,EAAE,GAAG,EAAE,MAAM,mBAAmB,CAAC;AAC7C,OAAO,EAAE,OAAO,IAAI,OAAO,EAAE,MAAM,0BAA0B,CAAC;AAC9D,OAAO,EAAE,OAAO,IAAI,KAAK,EAAE,MAAM,sBAAsB,CAAC;AACxD,OAAO,EAAE,OAAO,IAAI,YAAY,EAAE,MAAM,qCAAqC,CAAC;AAC9E,YAAY,EAAE,gBAAgB,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AAGhF,OAAO,EAAE,OAAO,IAAI,eAAe,EAAE,MAAM,0BAA0B,CAAC;AACtE,OAAO,EAAE,OAAO,IAAI,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AACxE,OAAO,EAAE,OAAO,IAAI,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAClE,YAAY,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAC5D,YAAY,EAAE,qBAAqB,EAAE,MAAM,2BAA2B,CAAC;AACvE,YAAY,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AAGlE,OAAO,EAAE,OAAO,IAAI,UAAU,EAAE,MAAM,0BAA0B,CAAC;AACjE,cAAc,mBAAmB,CAAC;AAGlC,OAAO,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjE,YAAY,EACV,aAAa,EACb,gBAAgB,EAChB,aAAa,EACb,cAAc,EACd,iBAAiB,EACjB,cAAc,EACd,oBAAoB,GACrB,MAAM,mBAAmB,CAAC;AAG3B,OAAO,EAAE,OAAO,IAAI,gBAAgB,EAAE,MAAM,uCAAuC,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/u0-primitives/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,OAAO,IAAI,MAAM,EAAE,MAAM,wBAAwB,CAAC;AAC3D,OAAO,EAAE,OAAO,IAAI,KAAK,EAAE,MAAM,sBAAsB,CAAC;AACxD,OAAO,EAAE,OAAO,IAAI,IAAI,EAAE,MAAM,oBAAoB,CAAC;AACrD,OAAO,EAAE,OAAO,IAAI,KAAK,EAAE,MAAM,sBAAsB,CAAC;AACxD,OAAO,EAAE,OAAO,IAAI,aAAa,EAAE,MAAM,8BAA8B,CAAC;AACxE,OAAO,EAAE,OAAO,IAAI,MAAM,EAAE,MAAM,wBAAwB,CAAC;AAC3D,OAAO,EAAE,OAAO,IAAI,MAAM,EAAE,MAAM,wBAAwB,CAAC;AAC3D,OAAO,EAAE,OAAO,IAAI,OAAO,EAAE,MAAM,0BAA0B,CAAC;AAC9D,OAAO,EAAE,OAAO,IAAI,QAAQ,EAAE,MAAM,4BAA4B,CAAC;AACjE,OAAO,EAAE,OAAO,IAAI,IAAI,EAAE,MAAM,oBAAoB,CAAC;AACrD,YAAY,EAAE,GAAG,EAAE,MAAM,mBAAmB,CAAC;AAC7C,OAAO,EAAE,OAAO,IAAI,OAAO,EAAE,MAAM,0BAA0B,CAAC;AAC9D,OAAO,EAAE,OAAO,IAAI,YAAY,EAAE,MAAM,qCAAqC,CAAC;AAC9E,YAAY,EAAE,gBAAgB,EAAE,KAAK,IAAI,iBAAiB,EAAE,MAAM,qCAAqC,CAAC;AACxG,OAAO,EAAE,OAAO,IAAI,KAAK,EAAE,MAAM,sBAAsB,CAAC;AACxD,OAAO,EAAE,OAAO,IAAI,YAAY,EAAE,MAAM,qCAAqC,CAAC;AAC9E,YAAY,EAAE,gBAAgB,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AAGhF,OAAO,EAAE,OAAO,IAAI,eAAe,EAAE,MAAM,0BAA0B,CAAC;AACtE,OAAO,EAAE,OAAO,IAAI,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AACxE,OAAO,EAAE,OAAO,IAAI,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAClE,YAAY,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAC5D,YAAY,EAAE,qBAAqB,EAAE,MAAM,2BAA2B,CAAC;AACvE,YAAY,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AAGlE,OAAO,EAAE,OAAO,IAAI,UAAU,EAAE,MAAM,0BAA0B,CAAC;AACjE,cAAc,mBAAmB,CAAC;AAGlC,OAAO,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjE,YAAY,EACV,aAAa,EACb,gBAAgB,EAChB,aAAa,EACb,cAAc,EACd,iBAAiB,EACjB,cAAc,EACd,oBAAoB,GACrB,MAAM,mBAAmB,CAAC;AAG3B,OAAO,EAAE,OAAO,IAAI,gBAAgB,EAAE,MAAM,uCAAuC,CAAC"}
@@ -10,6 +10,7 @@ export { default as Tooltip } from './tooltip/Tooltip.svelte';
10
10
  export { default as Dropdown } from './dropdown/Dropdown.svelte';
11
11
  export { default as Tabs } from './tabs/Tabs.svelte';
12
12
  export { default as Spinner } from './spinner/Spinner.svelte';
13
+ export { default as SurfaceState } from './surface-state/SurfaceState.svelte';
13
14
  export { default as Modal } from './modal/Modal.svelte';
14
15
  export { default as AnimatedIcon } from './animated-icon/AnimatedIcon.svelte';
15
16
  // New from NNJAS port
@@ -67,6 +67,13 @@
67
67
  showCompletions = false;
68
68
  }
69
69
 
70
+ function handleCompletionKeydown(e: KeyboardEvent, completion: { label: string }) {
71
+ if (e.key === 'Enter' || e.key === ' ') {
72
+ e.preventDefault();
73
+ applyCompletion(completion);
74
+ }
75
+ }
76
+
70
77
  function handleInput() {
71
78
  fetchCompletions(value);
72
79
  }
@@ -182,8 +189,10 @@
182
189
  id="autocomplete-option-{i}"
183
190
  role="option"
184
191
  aria-selected={i === selectedIndex}
192
+ tabindex={i === selectedIndex ? 0 : -1}
185
193
  class:selected={i === selectedIndex}
186
194
  onclick={() => applyCompletion(completion)}
195
+ onkeydown={(e) => handleCompletionKeydown(e, completion)}
187
196
  class="ds-input-autocomplete__item"
188
197
  >
189
198
  {#if completion.type}
@@ -1 +1 @@
1
- {"version":3,"file":"Input.svelte.d.ts","sourceRoot":"","sources":["../../../src/u0-primitives/input/Input.svelte.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,QAAQ,CAAC;AAGpC,MAAM,WAAW,kBAAkB;IACjC,WAAW,EAAE,KAAK,CAAC;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CACvE;AAED,MAAM,WAAW,kBAAkB;IACjC,MAAM,EAAE;QAAE,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC,kBAAkB,CAAC,GAAG,kBAAkB,CAAA;KAAE,CAAC;IAC1F,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,KAAK;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,GAAG,QAAQ,GAAG,UAAU,GAAG,OAAO,GAAG,KAAK,CAAC;IACxD,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,YAAY,CAAC,EAAE,kBAAkB,CAAC;CACnC;AA+IH,QAAA,MAAM,KAAK,gDAAwC,CAAC;AACpD,KAAK,KAAK,GAAG,UAAU,CAAC,OAAO,KAAK,CAAC,CAAC;AACtC,eAAe,KAAK,CAAC"}
1
+ {"version":3,"file":"Input.svelte.d.ts","sourceRoot":"","sources":["../../../src/u0-primitives/input/Input.svelte.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,QAAQ,CAAC;AAGpC,MAAM,WAAW,kBAAkB;IACjC,WAAW,EAAE,KAAK,CAAC;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CACvE;AAED,MAAM,WAAW,kBAAkB;IACjC,MAAM,EAAE;QAAE,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC,kBAAkB,CAAC,GAAG,kBAAkB,CAAA;KAAE,CAAC;IAC1F,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,KAAK;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,GAAG,QAAQ,GAAG,UAAU,GAAG,OAAO,GAAG,KAAK,CAAC;IACxD,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,YAAY,CAAC,EAAE,kBAAkB,CAAC;CACnC;AAsJH,QAAA,MAAM,KAAK,gDAAwC,CAAC;AACpD,KAAK,KAAK,GAAG,UAAU,CAAC,OAAO,KAAK,CAAC,CAAC;AACtC,eAAe,KAAK,CAAC"}
@@ -37,7 +37,7 @@ describe('Input', () => {
37
37
  });
38
38
  it('displays leading icon element when iconLeading is provided', () => {
39
39
  const { container } = render(Input, {
40
- iconLeading: () => '<svg class="test-icon"></svg>'
40
+ iconLeading: (() => '')
41
41
  });
42
42
  expect(container.querySelector('.ds-input-icon.leading')).not.toBeNull();
43
43
  });
@@ -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 '../../s0-state/modal-stack-store.svelte';
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,17 +258,17 @@
235
258
  .modal-dialog {
236
259
  position: relative;
237
260
  background: var(--color-bg-panel-elevated);
238
- border: 1px solid var(--border-default);
261
+ border: var(--border-width-thin) solid var(--border-default);
239
262
  border-radius: var(--radius-xl);
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
270
  box-shadow: var(--shadow-xl);
248
- transform: translateY(20px) scale(0.98);
271
+ transform: translateY(1.25rem) scale(0.98);
249
272
  transition: transform var(--transition-normal), opacity var(--transition-normal);
250
273
  opacity: 0;
251
274
  }
@@ -256,7 +279,7 @@
256
279
  }
257
280
 
258
281
  .modal-dialog:focus {
259
- box-shadow: 0 0 0 2px var(--color-accent), var(--shadow-xl);
282
+ box-shadow: 0 0 0 var(--border-width-default) var(--color-accent), var(--shadow-xl);
260
283
  }
261
284
 
262
285
  .modal-header {
@@ -264,7 +287,7 @@
264
287
  justify-content: space-between;
265
288
  align-items: center;
266
289
  padding: var(--space-5) var(--space-6);
267
- border-bottom: 1px solid var(--border-default);
290
+ border-bottom: var(--border-width-thin) solid var(--border-default);
268
291
  flex-shrink: 0;
269
292
  }
270
293
 
@@ -303,8 +326,8 @@
303
326
  }
304
327
 
305
328
  .modal-close-btn:focus-visible {
306
- outline: 2px solid var(--color-accent);
307
- outline-offset: 2px;
329
+ outline: var(--border-width-default) solid var(--color-accent);
330
+ outline-offset: var(--border-width-default);
308
331
  }
309
332
 
310
333
  .modal-content {
@@ -320,12 +343,12 @@
320
343
  justify-content: flex-end;
321
344
  gap: var(--space-3);
322
345
  padding: var(--space-4) var(--space-6);
323
- border-top: 1px solid var(--border-default);
346
+ border-top: var(--border-width-thin) solid var(--border-default);
324
347
  flex-shrink: 0;
325
348
  }
326
349
 
327
350
  /* 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; }
351
+ :global(.modal-dialog[data-size="small"]) { max-width: 25rem; }
352
+ :global(.modal-dialog[data-size="large"]) { max-width: 50rem; }
330
353
  :global(.modal-dialog[data-size="full"]) { max-width: 95vw; max-height: 95vh; }
331
354
  </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 '../../s0-state/modal-stack-store.svelte';
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;
@@ -1 +1 @@
1
- {"version":3,"file":"RsvpReader.svelte.d.ts","sourceRoot":"","sources":["../../../src/u0-primitives/rsvp/RsvpReader.svelte.ts"],"names":[],"mappings":"AAMC,KAAK,gBAAgB,GAAI;IACtB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,SAAS,GAAG,MAAM,CAAC;IAC1B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,IAAI,CAAC;IACxB,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;CACtB,CAAC;AAqIJ,QAAA,MAAM,UAAU,sDAAwC,CAAC;AACzD,KAAK,UAAU,GAAG,UAAU,CAAC,OAAO,UAAU,CAAC,CAAC;AAChD,eAAe,UAAU,CAAC"}
1
+ {"version":3,"file":"RsvpReader.svelte.d.ts","sourceRoot":"","sources":["../../../src/u0-primitives/rsvp/RsvpReader.svelte.ts"],"names":[],"mappings":"AAOC,KAAK,gBAAgB,GAAI;IACtB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,SAAS,GAAG,MAAM,CAAC;IAC1B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,IAAI,CAAC;IACxB,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;CACtB,CAAC;AAsIJ,QAAA,MAAM,UAAU,sDAAwC,CAAC;AACzD,KAAK,UAAU,GAAG,UAAU,CAAC,OAAO,UAAU,CAAC,CAAC;AAChD,eAAe,UAAU,CAAC"}
@@ -93,7 +93,7 @@
93
93
  color: var(--color-text-secondary, #a09880);
94
94
  }
95
95
 
96
- .steps[vertical="false"] {
96
+ .steps:not(.vertical) {
97
97
  flex-direction: column;
98
98
  align-items: stretch;
99
99
  }
@@ -159,7 +159,7 @@
159
159
 
160
160
  /* Responsive adjustments */
161
161
  @media (max-width: 640px) {
162
- .steps[vertical="true"] {
162
+ .steps.vertical {
163
163
  flex-direction: column;
164
164
  align-items: flex-start;
165
165
  }
@@ -0,0 +1,190 @@
1
+ <script lang="ts">
2
+ import type { Snippet } from 'svelte';
3
+ import Spinner from '../spinner/Spinner.svelte';
4
+ import Button from '../button/Button.svelte';
5
+
6
+ export type SurfaceStateKind = 'loading' | 'empty' | 'error' | 'degraded';
7
+
8
+ export interface Props {
9
+ state: SurfaceStateKind;
10
+ title?: string;
11
+ message?: string;
12
+ actionLabel?: string;
13
+ onRetry?: () => void | Promise<void>;
14
+ class?: string;
15
+ children?: Snippet;
16
+ }
17
+
18
+ let {
19
+ state,
20
+ title,
21
+ message,
22
+ actionLabel,
23
+ onRetry,
24
+ class: className = '',
25
+ children,
26
+ }: Props = $props();
27
+
28
+ const effectiveTitle = $derived(
29
+ title ??
30
+ (state === 'loading'
31
+ ? 'Loading'
32
+ : state === 'empty'
33
+ ? 'Nothing here yet'
34
+ : state === 'error'
35
+ ? 'Something went wrong'
36
+ : 'Substrate offline')
37
+ );
38
+
39
+ const effectiveMessage = $derived(
40
+ message ??
41
+ (state === 'loading'
42
+ ? 'Preparing the surface…'
43
+ : state === 'empty'
44
+ ? 'No content is available for this view.'
45
+ : state === 'error'
46
+ ? 'The operation could not be completed. Please try again.'
47
+ : 'The SOVEREIGN daemon isn’t responding. Your data is safe; reconnect to continue.')
48
+ );
49
+
50
+ const effectiveActionLabel = $derived(actionLabel ?? (state === 'degraded' ? 'Retry' : 'Try again'));
51
+
52
+ const isBusy = $derived(state === 'loading' || state === 'degraded');
53
+ const showAction = $derived(state === 'error' || state === 'degraded');
54
+ </script>
55
+
56
+ <section
57
+ class="ds-surface-state state-{state} {className}"
58
+ role="status"
59
+ aria-live="polite"
60
+ >
61
+ <div class="ds-surface-state__icon" aria-hidden="true">
62
+ {#if isBusy}
63
+ <Spinner size="md" color="accent" />
64
+ {:else if state === 'empty'}
65
+ <span class="ds-surface-state__glyph">∅</span>
66
+ {:else}
67
+ <span class="ds-surface-state__glyph">!</span>
68
+ {/if}
69
+ </div>
70
+
71
+ <div class="ds-surface-state__content">
72
+ <h2 class="ds-surface-state__title">{effectiveTitle}</h2>
73
+ {#if effectiveMessage}
74
+ <p class="ds-surface-state__message">{effectiveMessage}</p>
75
+ {/if}
76
+ {#if children}
77
+ <div class="ds-surface-state__children">
78
+ {@render children()}
79
+ </div>
80
+ {/if}
81
+ </div>
82
+
83
+ {#if showAction}
84
+ <div class="ds-surface-state__actions">
85
+ <Button variant={state === 'error' ? 'danger' : 'secondary'} size="sm" disabled={!onRetry} onclick={() => void onRetry?.()}>
86
+ {effectiveActionLabel}
87
+ </Button>
88
+
89
+ </div>
90
+ {/if}
91
+ </section>
92
+
93
+ <style>
94
+ .ds-surface-state {
95
+ display: flex;
96
+ align-items: center;
97
+ justify-content: center;
98
+ gap: var(--space-3);
99
+ min-height: 14rem;
100
+ padding: var(--space-6);
101
+ border: 1px solid var(--border-subtle);
102
+ border-radius: var(--radius-lg);
103
+ background: var(--color-bg-panel-elevated);
104
+ color: var(--color-text-primary);
105
+ text-align: center;
106
+ }
107
+
108
+ .ds-surface-state__icon {
109
+ display: inline-flex;
110
+ align-items: center;
111
+ justify-content: center;
112
+ width: 3rem;
113
+ height: 3rem;
114
+ flex-shrink: 0;
115
+ border: 1px solid var(--border-default);
116
+ border-radius: var(--radius-full);
117
+ background: var(--color-bg-app);
118
+ }
119
+
120
+ .state-error .ds-surface-state__icon,
121
+ .state-degraded .ds-surface-state__icon {
122
+ border-color: color-mix(in srgb, var(--color-error) 45%, var(--border-default));
123
+ }
124
+
125
+ .state-empty .ds-surface-state__icon {
126
+ border-color: var(--border-default);
127
+ }
128
+
129
+ .ds-surface-state__glyph {
130
+ font-family: var(--font-mono);
131
+ font-size: var(--text-xl);
132
+ font-weight: 700;
133
+ color: var(--color-text-primary);
134
+ }
135
+
136
+ .state-error .ds-surface-state__glyph,
137
+ .state-degraded .ds-surface-state__glyph {
138
+ color: var(--color-error);
139
+ }
140
+
141
+ .state-empty .ds-surface-state__glyph {
142
+ color: var(--color-text-muted);
143
+ }
144
+
145
+ .ds-surface-state__content {
146
+ display: flex;
147
+ flex: 1;
148
+ min-width: 0;
149
+ flex-direction: column;
150
+ gap: var(--space-1);
151
+ }
152
+
153
+ .ds-surface-state__title {
154
+ margin: 0;
155
+ font-size: var(--text-lg);
156
+ font-weight: 600;
157
+ letter-spacing: 0.02em;
158
+ color: var(--color-text-primary);
159
+ }
160
+
161
+ .ds-surface-state__message {
162
+ margin: 0;
163
+ max-width: 34rem;
164
+ color: var(--color-text-secondary);
165
+ font-size: var(--text-sm);
166
+ line-height: 1.5;
167
+ }
168
+
169
+ .ds-surface-state__children {
170
+ margin-top: var(--space-2);
171
+ }
172
+
173
+ .ds-surface-state__actions {
174
+ display: flex;
175
+ align-items: center;
176
+ justify-content: center;
177
+ }
178
+
179
+ @media (max-width: 42rem) {
180
+ .ds-surface-state {
181
+ align-items: flex-start;
182
+ flex-direction: column;
183
+ text-align: left;
184
+ }
185
+
186
+ .ds-surface-state__actions {
187
+ justify-content: flex-start;
188
+ }
189
+ }
190
+ </style>
@@ -0,0 +1,15 @@
1
+ import type { Snippet } from 'svelte';
2
+ export type SurfaceStateKind = 'loading' | 'empty' | 'error' | 'degraded';
3
+ export interface Props {
4
+ state: SurfaceStateKind;
5
+ title?: string;
6
+ message?: string;
7
+ actionLabel?: string;
8
+ onRetry?: () => void | Promise<void>;
9
+ class?: string;
10
+ children?: Snippet;
11
+ }
12
+ declare const SurfaceState: import("svelte").Component<Props, {}, "">;
13
+ type SurfaceState = ReturnType<typeof SurfaceState>;
14
+ export default SurfaceState;
15
+ //# sourceMappingURL=SurfaceState.svelte.d.ts.map