@selvajs/ui 6.5.1-beta.1 → 6.6.0-beta.12

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 (446) hide show
  1. package/dist/components/ConfirmDialog.svelte +2 -10
  2. package/dist/components/ErrorScreen.svelte +21 -27
  3. package/dist/components/compute/AppLayout.svelte +298 -128
  4. package/dist/components/compute/AppLayout.svelte.d.ts +22 -0
  5. package/dist/components/compute/CollapsedPanelStrip.svelte +4 -2
  6. package/dist/components/compute/ComputeApp.svelte +45 -24
  7. package/dist/components/compute/ComputeApp.svelte.d.ts +19 -2
  8. package/dist/components/compute/ComputeMessagesDialog.svelte +47 -83
  9. package/dist/components/compute/ParameterPresetManager.svelte +37 -130
  10. package/dist/components/compute/ParameterPresetManager.svelte.d.ts +4 -5
  11. package/dist/components/compute/SolveMessages.svelte +131 -77
  12. package/dist/components/compute/SolveMessages.svelte.d.ts +7 -12
  13. package/dist/components/layout/AppShell.svelte +10 -6
  14. package/dist/components/layout/PageFooter.svelte +23 -11
  15. package/dist/components/layout/PageHeader.svelte +11 -7
  16. package/dist/components/layout/Pagination.svelte +2 -4
  17. package/dist/components/layout/SectionHeader.svelte +4 -2
  18. package/dist/components/layout/SideNav.svelte +56 -7
  19. package/dist/components/preview/ChartOutput.svelte +91 -48
  20. package/dist/components/preview/Group.svelte +92 -103
  21. package/dist/components/preview/Group.svelte.d.ts +1 -1
  22. package/dist/components/preview/HelpButton.svelte +36 -0
  23. package/dist/components/preview/HelpButton.svelte.d.ts +8 -0
  24. package/dist/components/preview/ImageOutput.svelte +434 -72
  25. package/dist/components/preview/InputControl.svelte +163 -90
  26. package/dist/components/preview/InputControl.svelte.d.ts +5 -1
  27. package/dist/components/preview/OutputDisplay.svelte +44 -42
  28. package/dist/components/preview/TabBar.svelte +106 -22
  29. package/dist/components/preview/TabBar.svelte.d.ts +1 -0
  30. package/dist/components/preview/TabContent.svelte +63 -57
  31. package/dist/components/preview/TabContent.svelte.d.ts +5 -1
  32. package/dist/components/preview/TabLayout.svelte +27 -5
  33. package/dist/components/preview/TabLayout.svelte.d.ts +5 -0
  34. package/dist/components/preview/inputs/CheckboxInput.svelte +7 -7
  35. package/dist/components/preview/inputs/CheckboxInput.svelte.d.ts +3 -0
  36. package/dist/components/preview/inputs/ChecklistInput.svelte +7 -2
  37. package/dist/components/preview/inputs/ChecklistInput.svelte.d.ts +2 -1
  38. package/dist/components/preview/inputs/ColorInput.svelte +4 -2
  39. package/dist/components/preview/inputs/ColorInput.svelte.d.ts +1 -0
  40. package/dist/components/preview/inputs/DropdownInput.svelte +19 -4
  41. package/dist/components/preview/inputs/DropdownInput.svelte.d.ts +2 -1
  42. package/dist/components/preview/inputs/FileInput.svelte +112 -108
  43. package/dist/components/preview/inputs/GeometryInput.svelte +128 -0
  44. package/dist/components/preview/inputs/GeometryInput.svelte.d.ts +21 -0
  45. package/dist/components/preview/inputs/NumberInput.svelte +123 -61
  46. package/dist/components/preview/inputs/NumberInput.svelte.d.ts +2 -0
  47. package/dist/components/preview/inputs/OptionGlyph.svelte +29 -0
  48. package/dist/components/preview/inputs/OptionGlyph.svelte.d.ts +8 -0
  49. package/dist/components/preview/inputs/SegmentedInput.svelte +44 -0
  50. package/dist/components/preview/inputs/SegmentedInput.svelte.d.ts +12 -0
  51. package/dist/components/preview/inputs/TextInput.svelte +8 -4
  52. package/dist/components/preview/inputs/TileInput.svelte +80 -0
  53. package/dist/components/preview/inputs/TileInput.svelte.d.ts +12 -0
  54. package/dist/components/preview/inputs/index.d.ts +3 -0
  55. package/dist/components/preview/inputs/index.js +3 -0
  56. package/dist/components/primitives/CalculateButton.svelte +56 -24
  57. package/dist/components/primitives/CalculateButton.svelte.d.ts +3 -0
  58. package/dist/components/primitives/Callout.svelte +11 -18
  59. package/dist/components/primitives/DataTable.svelte +38 -5
  60. package/dist/components/primitives/DataTable.svelte.d.ts +2 -0
  61. package/dist/components/primitives/FilterableDropdown.svelte +42 -129
  62. package/dist/components/primitives/FilterableDropdown.svelte.d.ts +1 -1
  63. package/dist/components/primitives/IssueList.svelte +56 -0
  64. package/dist/components/primitives/IssueList.svelte.d.ts +20 -0
  65. package/dist/components/primitives/SeverityIcon.svelte +15 -0
  66. package/dist/components/primitives/SeverityIcon.svelte.d.ts +8 -0
  67. package/dist/components/primitives/SolvingIndicator.svelte +43 -42
  68. package/dist/components/primitives/SolvingIndicator.svelte.d.ts +6 -0
  69. package/dist/components/primitives/StateDisplay.svelte +19 -79
  70. package/dist/components/primitives/ViewToggle.svelte +18 -33
  71. package/dist/components/primitives/alert-dialog/alert-dialog-action.svelte +9 -3
  72. package/dist/components/primitives/alert-dialog/alert-dialog-action.svelte.d.ts +6 -1
  73. package/dist/components/primitives/alert-dialog/alert-dialog-content.svelte +1 -1
  74. package/dist/components/primitives/alert-dialog/alert-dialog-overlay.svelte +1 -1
  75. package/dist/components/primitives/badge/badge.svelte +2 -2
  76. package/dist/components/primitives/badge/badge.svelte.d.ts +4 -4
  77. package/dist/components/primitives/button/button.svelte +6 -2
  78. package/dist/components/primitives/button/button.svelte.d.ts +10 -4
  79. package/dist/components/primitives/card/card-header.svelte +1 -1
  80. package/dist/components/primitives/card/card.svelte +21 -5
  81. package/dist/components/primitives/card/card.svelte.d.ts +25 -1
  82. package/dist/components/primitives/card/index.d.ts +1 -2
  83. package/dist/components/primitives/card/index.js +2 -3
  84. package/dist/components/primitives/checkbox/checkbox.svelte +1 -1
  85. package/dist/components/primitives/command/command-dialog.svelte +42 -0
  86. package/dist/components/primitives/command/command-dialog.svelte.d.ts +14 -0
  87. package/dist/components/primitives/command/command-empty.svelte +17 -0
  88. package/dist/components/primitives/command/command-empty.svelte.d.ts +4 -0
  89. package/dist/components/primitives/command/command-group.svelte +33 -0
  90. package/dist/components/primitives/command/command-group.svelte.d.ts +7 -0
  91. package/dist/components/primitives/command/command-input.svelte +36 -0
  92. package/dist/components/primitives/command/command-input.svelte.d.ts +4 -0
  93. package/dist/components/primitives/command/command-item.svelte +28 -0
  94. package/dist/components/primitives/command/command-item.svelte.d.ts +4 -0
  95. package/dist/components/primitives/command/command-link-item.svelte +21 -0
  96. package/dist/components/primitives/command/command-link-item.svelte.d.ts +4 -0
  97. package/dist/components/primitives/command/command-list.svelte +20 -0
  98. package/dist/components/primitives/command/command-list.svelte.d.ts +4 -0
  99. package/dist/components/primitives/command/command-loading.svelte +7 -0
  100. package/dist/components/primitives/command/command-loading.svelte.d.ts +4 -0
  101. package/dist/components/primitives/command/command-separator.svelte +17 -0
  102. package/dist/components/primitives/command/command-separator.svelte.d.ts +4 -0
  103. package/dist/components/primitives/command/command-shortcut.svelte +23 -0
  104. package/dist/components/primitives/command/command-shortcut.svelte.d.ts +5 -0
  105. package/dist/components/primitives/command/command.svelte +28 -0
  106. package/dist/components/primitives/command/command.svelte.d.ts +8 -0
  107. package/dist/components/primitives/command/index.d.ts +12 -0
  108. package/dist/components/primitives/command/index.js +14 -0
  109. package/dist/components/primitives/context-menu/context-menu-content.svelte +1 -1
  110. package/dist/components/primitives/context-menu/context-menu-sub-content.svelte +1 -1
  111. package/dist/components/primitives/dialog/dialog-content.svelte +11 -3
  112. package/dist/components/primitives/dialog/dialog-content.svelte.d.ts +2 -0
  113. package/dist/components/primitives/dialog/dialog-overlay.svelte +1 -1
  114. package/dist/components/primitives/dialog/dialog-title.svelte +6 -2
  115. package/dist/components/primitives/dialog/dialog-title.svelte.d.ts +5 -1
  116. package/dist/components/primitives/drawer/Drawer.svelte +2 -2
  117. package/dist/components/primitives/dropdown-menu/dropdown-menu-checkbox-group.svelte +16 -0
  118. package/dist/components/primitives/dropdown-menu/dropdown-menu-checkbox-group.svelte.d.ts +4 -0
  119. package/dist/components/primitives/dropdown-menu/dropdown-menu-checkbox-item.svelte +46 -0
  120. package/dist/components/primitives/dropdown-menu/dropdown-menu-checkbox-item.svelte.d.ts +9 -0
  121. package/dist/components/primitives/dropdown-menu/dropdown-menu-content.svelte +31 -0
  122. package/dist/components/primitives/dropdown-menu/dropdown-menu-content.svelte.d.ts +10 -0
  123. package/dist/components/primitives/dropdown-menu/dropdown-menu-group-heading.svelte +22 -0
  124. package/dist/components/primitives/dropdown-menu/dropdown-menu-group-heading.svelte.d.ts +8 -0
  125. package/dist/components/primitives/dropdown-menu/dropdown-menu-group.svelte +7 -0
  126. package/dist/components/primitives/dropdown-menu/dropdown-menu-group.svelte.d.ts +4 -0
  127. package/dist/components/primitives/dropdown-menu/dropdown-menu-item.svelte +27 -0
  128. package/dist/components/primitives/dropdown-menu/dropdown-menu-item.svelte.d.ts +8 -0
  129. package/dist/components/primitives/dropdown-menu/dropdown-menu-label.svelte +24 -0
  130. package/dist/components/primitives/dropdown-menu/dropdown-menu-label.svelte.d.ts +8 -0
  131. package/dist/components/primitives/dropdown-menu/dropdown-menu-portal.svelte +7 -0
  132. package/dist/components/primitives/dropdown-menu/dropdown-menu-portal.svelte.d.ts +3 -0
  133. package/dist/components/primitives/dropdown-menu/dropdown-menu-radio-group.svelte +16 -0
  134. package/dist/components/primitives/dropdown-menu/dropdown-menu-radio-group.svelte.d.ts +4 -0
  135. package/dist/components/primitives/dropdown-menu/dropdown-menu-radio-item.svelte +36 -0
  136. package/dist/components/primitives/dropdown-menu/dropdown-menu-radio-item.svelte.d.ts +4 -0
  137. package/dist/components/primitives/dropdown-menu/dropdown-menu-separator.svelte +17 -0
  138. package/dist/components/primitives/dropdown-menu/dropdown-menu-separator.svelte.d.ts +4 -0
  139. package/dist/components/primitives/dropdown-menu/dropdown-menu-shortcut.svelte +23 -0
  140. package/dist/components/primitives/dropdown-menu/dropdown-menu-shortcut.svelte.d.ts +5 -0
  141. package/dist/components/primitives/dropdown-menu/dropdown-menu-sub-content.svelte +31 -0
  142. package/dist/components/primitives/dropdown-menu/dropdown-menu-sub-content.svelte.d.ts +10 -0
  143. package/dist/components/primitives/dropdown-menu/dropdown-menu-sub-trigger.svelte +29 -0
  144. package/dist/components/primitives/dropdown-menu/dropdown-menu-sub-trigger.svelte.d.ts +7 -0
  145. package/dist/components/primitives/dropdown-menu/dropdown-menu-sub.svelte +7 -0
  146. package/dist/components/primitives/dropdown-menu/dropdown-menu-sub.svelte.d.ts +3 -0
  147. package/dist/components/primitives/dropdown-menu/dropdown-menu-trigger.svelte +7 -0
  148. package/dist/components/primitives/dropdown-menu/dropdown-menu-trigger.svelte.d.ts +4 -0
  149. package/dist/components/primitives/dropdown-menu/dropdown-menu.svelte +7 -0
  150. package/dist/components/primitives/dropdown-menu/dropdown-menu.svelte.d.ts +3 -0
  151. package/dist/components/primitives/dropdown-menu/index.d.ts +18 -0
  152. package/dist/components/primitives/dropdown-menu/index.js +18 -0
  153. package/dist/components/primitives/{alert/alert-description.svelte → empty/empty-content.svelte} +3 -3
  154. package/dist/components/primitives/empty/empty-content.svelte.d.ts +5 -0
  155. package/dist/components/primitives/empty/empty-description.svelte +23 -0
  156. package/dist/components/primitives/{alert/alert-description.svelte.d.ts → empty/empty-description.svelte.d.ts} +4 -4
  157. package/dist/components/primitives/{alert/alert-title.svelte → empty/empty-header.svelte} +3 -3
  158. package/dist/components/primitives/empty/empty-header.svelte.d.ts +5 -0
  159. package/dist/components/primitives/empty/empty-media.svelte +41 -0
  160. package/dist/components/primitives/empty/empty-media.svelte.d.ts +26 -0
  161. package/dist/components/primitives/{card/card-action.svelte → empty/empty-title.svelte} +2 -2
  162. package/dist/components/primitives/{card/card-action.svelte.d.ts → empty/empty-title.svelte.d.ts} +3 -3
  163. package/dist/components/primitives/empty/empty.svelte +23 -0
  164. package/dist/components/primitives/empty/empty.svelte.d.ts +5 -0
  165. package/dist/components/primitives/empty/index.d.ts +7 -0
  166. package/dist/components/primitives/empty/index.js +9 -0
  167. package/dist/components/primitives/index.d.ts +10 -1
  168. package/dist/components/primitives/index.js +10 -1
  169. package/dist/components/primitives/input/input.svelte +4 -4
  170. package/dist/components/primitives/input-group/index.d.ts +7 -0
  171. package/dist/components/primitives/input-group/index.js +9 -0
  172. package/dist/components/primitives/input-group/input-group-addon.svelte +53 -0
  173. package/dist/components/primitives/input-group/input-group-addon.svelte.d.ts +32 -0
  174. package/dist/components/primitives/input-group/input-group-button.svelte +49 -0
  175. package/dist/components/primitives/input-group/input-group-button.svelte.d.ts +32 -0
  176. package/dist/components/primitives/input-group/input-group-input.svelte +25 -0
  177. package/dist/components/primitives/input-group/input-group-input.svelte.d.ts +11 -0
  178. package/dist/components/primitives/input-group/input-group-text.svelte +22 -0
  179. package/dist/components/primitives/input-group/input-group-text.svelte.d.ts +5 -0
  180. package/dist/components/primitives/input-group/input-group-textarea.svelte +23 -0
  181. package/dist/components/primitives/input-group/input-group-textarea.svelte.d.ts +3 -0
  182. package/dist/components/primitives/input-group/input-group.svelte +24 -0
  183. package/dist/components/primitives/{alert/alert-title.svelte.d.ts → input-group/input-group.svelte.d.ts} +4 -4
  184. package/dist/components/primitives/mode-toggle/mode-toggle.svelte +6 -7
  185. package/dist/components/primitives/popover/index.d.ts +9 -0
  186. package/dist/components/primitives/popover/index.js +11 -0
  187. package/dist/components/primitives/popover/popover-close.svelte +7 -0
  188. package/dist/components/primitives/popover/popover-close.svelte.d.ts +4 -0
  189. package/dist/components/primitives/popover/popover-content.svelte +31 -0
  190. package/dist/components/primitives/popover/popover-content.svelte.d.ts +10 -0
  191. package/dist/components/primitives/popover/popover-description.svelte +20 -0
  192. package/dist/components/primitives/popover/popover-description.svelte.d.ts +5 -0
  193. package/dist/components/primitives/popover/popover-header.svelte +20 -0
  194. package/dist/components/primitives/popover/popover-header.svelte.d.ts +5 -0
  195. package/dist/components/primitives/popover/popover-portal.svelte +7 -0
  196. package/dist/components/primitives/popover/popover-portal.svelte.d.ts +3 -0
  197. package/dist/components/primitives/popover/popover-title.svelte +15 -0
  198. package/dist/components/primitives/popover/popover-title.svelte.d.ts +5 -0
  199. package/dist/components/primitives/popover/popover-trigger.svelte +17 -0
  200. package/dist/components/primitives/popover/popover-trigger.svelte.d.ts +4 -0
  201. package/dist/components/primitives/popover/popover.svelte +7 -0
  202. package/dist/components/primitives/popover/popover.svelte.d.ts +3 -0
  203. package/dist/components/primitives/resizable/resizable-handle.svelte +6 -2
  204. package/dist/components/primitives/resizable/resizable-handle.svelte.d.ts +2 -0
  205. package/dist/components/primitives/resizable/resizable-pane-group.svelte +1 -4
  206. package/dist/components/primitives/scroll-area/scroll-area.svelte +1 -1
  207. package/dist/components/primitives/search/search.svelte +3 -3
  208. package/dist/components/primitives/select/select-content.svelte +1 -1
  209. package/dist/components/primitives/select/select-trigger.svelte +1 -1
  210. package/dist/components/primitives/severity.d.ts +7 -0
  211. package/dist/components/primitives/severity.js +19 -0
  212. package/dist/components/primitives/slider/slider.svelte +8 -3
  213. package/dist/components/primitives/slider/slider.svelte.d.ts +5 -1
  214. package/dist/components/primitives/sonner/sonner.svelte +1 -1
  215. package/dist/components/primitives/spinner/index.d.ts +1 -0
  216. package/dist/components/primitives/spinner/index.js +1 -0
  217. package/dist/components/primitives/spinner/spinner.svelte +29 -0
  218. package/dist/components/primitives/spinner/spinner.svelte.d.ts +4 -0
  219. package/dist/components/primitives/switch/switch.svelte +2 -2
  220. package/dist/components/primitives/tabs/tabs-list.svelte +27 -5
  221. package/dist/components/primitives/tabs/tabs-list.svelte.d.ts +22 -1
  222. package/dist/components/primitives/tabs/tabs-trigger.svelte +23 -5
  223. package/dist/components/primitives/tabs/tabs-trigger.svelte.d.ts +22 -1
  224. package/dist/components/primitives/tabs/tabs.svelte +6 -2
  225. package/dist/components/primitives/tabs/tabs.svelte.d.ts +5 -1
  226. package/dist/components/primitives/textarea/textarea.svelte +1 -1
  227. package/dist/components/primitives/theme-switcher/ThemeSwitcher.svelte +1 -1
  228. package/dist/components/primitives/toggle/index.d.ts +3 -0
  229. package/dist/components/primitives/toggle/index.js +5 -0
  230. package/dist/components/primitives/toggle/toggle.svelte +54 -0
  231. package/dist/components/primitives/toggle/toggle.svelte.d.ts +46 -0
  232. package/dist/components/primitives/toggle-group/index.d.ts +3 -0
  233. package/dist/components/primitives/toggle-group/index.js +5 -0
  234. package/dist/components/primitives/toggle-group/toggle-group-item.svelte +35 -0
  235. package/dist/components/primitives/toggle-group/toggle-group-item.svelte.d.ts +6 -0
  236. package/dist/components/primitives/toggle-group/toggle-group.svelte +75 -0
  237. package/dist/components/primitives/toggle-group/toggle-group.svelte.d.ts +17 -0
  238. package/dist/components/viewer/MeshMetadataPanel.svelte +119 -0
  239. package/dist/components/viewer/MeshMetadataPanel.svelte.d.ts +9 -0
  240. package/dist/components/viewer/SceneManager.svelte +14 -5
  241. package/dist/components/viewer/Viewer.svelte +243 -221
  242. package/dist/components/viewer/Viewer.svelte.d.ts +3 -0
  243. package/dist/compute/run-panel-action.d.ts +8 -0
  244. package/dist/compute/run-panel-action.js +12 -0
  245. package/dist/compute/solving.svelte.d.ts +11 -7
  246. package/dist/compute/solving.svelte.js +64 -45
  247. package/dist/compute/useSolveSession.svelte.js +3 -0
  248. package/dist/constants.d.ts +6 -8
  249. package/dist/constants.js +7 -9
  250. package/dist/contexts/hostContext.svelte.d.ts +39 -0
  251. package/dist/contexts/hostContext.svelte.js +9 -0
  252. package/dist/i18n/localeContext.svelte.d.ts +10 -3
  253. package/dist/i18n/localeContext.svelte.js +27 -5
  254. package/dist/i18n/messages.d.ts +150 -2
  255. package/dist/i18n/messages.js +261 -11
  256. package/dist/index.d.ts +4 -1
  257. package/dist/index.js +3 -0
  258. package/dist/public.d.ts +1 -1
  259. package/dist/schema/host-support.d.ts +29 -0
  260. package/dist/schema/host-support.js +97 -0
  261. package/dist/schema/option-display.d.ts +12 -0
  262. package/dist/schema/option-display.js +29 -0
  263. package/dist/schema/param-exporter.d.ts +4 -1
  264. package/dist/schema/param-exporter.js +10 -6
  265. package/dist/schema/visibility-rules.js +21 -0
  266. package/dist/styles/base.css +80 -10
  267. package/dist/types/actionButton.d.ts +17 -3
  268. package/dist/types/presetLabels.d.ts +3 -2
  269. package/dist/types/presetLabels.js +9 -8
  270. package/dist/utils/file-download.js +10 -22
  271. package/dist/utils/host-files.d.ts +12 -0
  272. package/dist/utils/host-files.js +46 -0
  273. package/dist/utils/loadScript.d.ts +2 -0
  274. package/dist/utils/loadScript.js +2 -0
  275. package/dist/utils/webp-to-png.d.ts +10 -0
  276. package/dist/utils/webp-to-png.js +41 -0
  277. package/package.json +19 -15
  278. package/src/lib/components/ConfirmDialog.svelte +2 -10
  279. package/src/lib/components/ErrorScreen.svelte +21 -27
  280. package/src/lib/components/compute/AppLayout.svelte +298 -128
  281. package/src/lib/components/compute/CollapsedPanelStrip.svelte +4 -2
  282. package/src/lib/components/compute/ComputeApp.svelte +45 -24
  283. package/src/lib/components/compute/ComputeMessagesDialog.svelte +47 -83
  284. package/src/lib/components/compute/ParameterPresetManager.svelte +37 -130
  285. package/src/lib/components/compute/SolveMessages.svelte +131 -77
  286. package/src/lib/components/layout/AppShell.svelte +10 -6
  287. package/src/lib/components/layout/PageFooter.svelte +23 -11
  288. package/src/lib/components/layout/PageHeader.svelte +11 -7
  289. package/src/lib/components/layout/Pagination.svelte +2 -4
  290. package/src/lib/components/layout/SectionHeader.svelte +4 -2
  291. package/src/lib/components/layout/SideNav.svelte +56 -7
  292. package/src/lib/components/preview/ChartOutput.svelte +91 -48
  293. package/src/lib/components/preview/Group.svelte +92 -103
  294. package/src/lib/components/preview/HelpButton.svelte +36 -0
  295. package/src/lib/components/preview/ImageOutput.svelte +434 -72
  296. package/src/lib/components/preview/InputControl.svelte +163 -90
  297. package/src/lib/components/preview/OutputDisplay.svelte +44 -42
  298. package/src/lib/components/preview/TabBar.svelte +106 -22
  299. package/src/lib/components/preview/TabContent.svelte +63 -57
  300. package/src/lib/components/preview/TabLayout.svelte +27 -5
  301. package/src/lib/components/preview/inputs/CheckboxInput.svelte +7 -7
  302. package/src/lib/components/preview/inputs/ChecklistInput.svelte +7 -2
  303. package/src/lib/components/preview/inputs/ColorInput.svelte +4 -2
  304. package/src/lib/components/preview/inputs/DropdownInput.svelte +19 -4
  305. package/src/lib/components/preview/inputs/FileInput.svelte +112 -108
  306. package/src/lib/components/preview/inputs/GeometryInput.svelte +128 -0
  307. package/src/lib/components/preview/inputs/NumberInput.svelte +123 -61
  308. package/src/lib/components/preview/inputs/OptionGlyph.svelte +29 -0
  309. package/src/lib/components/preview/inputs/SegmentedInput.svelte +44 -0
  310. package/src/lib/components/preview/inputs/TextInput.svelte +8 -4
  311. package/src/lib/components/preview/inputs/TileInput.svelte +80 -0
  312. package/src/lib/components/preview/inputs/index.ts +3 -0
  313. package/src/lib/components/primitives/CalculateButton.svelte +56 -24
  314. package/src/lib/components/primitives/Callout.svelte +11 -18
  315. package/src/lib/components/primitives/DataTable.svelte +38 -5
  316. package/src/lib/components/primitives/FilterableDropdown.svelte +42 -129
  317. package/src/lib/components/primitives/IssueList.svelte +56 -0
  318. package/src/lib/components/primitives/SeverityIcon.svelte +15 -0
  319. package/src/lib/components/primitives/SolvingIndicator.svelte +43 -42
  320. package/src/lib/components/primitives/StateDisplay.svelte +19 -79
  321. package/src/lib/components/primitives/ViewToggle.svelte +18 -33
  322. package/src/lib/components/primitives/alert-dialog/alert-dialog-action.svelte +9 -3
  323. package/src/lib/components/primitives/alert-dialog/alert-dialog-content.svelte +1 -1
  324. package/src/lib/components/primitives/alert-dialog/alert-dialog-overlay.svelte +1 -1
  325. package/src/lib/components/primitives/badge/badge.svelte +2 -2
  326. package/src/lib/components/primitives/button/button.svelte +6 -2
  327. package/src/lib/components/primitives/card/card-header.svelte +1 -1
  328. package/src/lib/components/primitives/card/card.svelte +21 -5
  329. package/src/lib/components/primitives/card/index.ts +1 -4
  330. package/src/lib/components/primitives/checkbox/checkbox.svelte +1 -1
  331. package/src/lib/components/primitives/command/command-dialog.svelte +42 -0
  332. package/src/lib/components/primitives/command/command-empty.svelte +17 -0
  333. package/src/lib/components/primitives/command/command-group.svelte +33 -0
  334. package/src/lib/components/primitives/command/command-input.svelte +36 -0
  335. package/src/lib/components/primitives/command/command-item.svelte +28 -0
  336. package/src/lib/components/primitives/command/command-link-item.svelte +21 -0
  337. package/src/lib/components/primitives/command/command-list.svelte +20 -0
  338. package/src/lib/components/primitives/command/command-loading.svelte +7 -0
  339. package/src/lib/components/primitives/command/command-separator.svelte +17 -0
  340. package/src/lib/components/primitives/command/command-shortcut.svelte +23 -0
  341. package/src/lib/components/primitives/command/command.svelte +28 -0
  342. package/src/lib/components/primitives/command/index.ts +37 -0
  343. package/src/lib/components/primitives/context-menu/context-menu-content.svelte +1 -1
  344. package/src/lib/components/primitives/context-menu/context-menu-sub-content.svelte +1 -1
  345. package/src/lib/components/primitives/dialog/dialog-content.svelte +11 -3
  346. package/src/lib/components/primitives/dialog/dialog-overlay.svelte +1 -1
  347. package/src/lib/components/primitives/dialog/dialog-title.svelte +6 -2
  348. package/src/lib/components/primitives/drawer/Drawer.svelte +2 -2
  349. package/src/lib/components/primitives/dropdown-menu/dropdown-menu-checkbox-group.svelte +16 -0
  350. package/src/lib/components/primitives/dropdown-menu/dropdown-menu-checkbox-item.svelte +46 -0
  351. package/src/lib/components/primitives/dropdown-menu/dropdown-menu-content.svelte +31 -0
  352. package/src/lib/components/primitives/dropdown-menu/dropdown-menu-group-heading.svelte +22 -0
  353. package/src/lib/components/primitives/dropdown-menu/dropdown-menu-group.svelte +7 -0
  354. package/src/lib/components/primitives/dropdown-menu/dropdown-menu-item.svelte +27 -0
  355. package/src/lib/components/primitives/dropdown-menu/dropdown-menu-label.svelte +24 -0
  356. package/src/lib/components/primitives/dropdown-menu/dropdown-menu-portal.svelte +7 -0
  357. package/src/lib/components/primitives/dropdown-menu/dropdown-menu-radio-group.svelte +16 -0
  358. package/src/lib/components/primitives/dropdown-menu/dropdown-menu-radio-item.svelte +36 -0
  359. package/src/lib/components/primitives/dropdown-menu/dropdown-menu-separator.svelte +17 -0
  360. package/src/lib/components/primitives/dropdown-menu/dropdown-menu-shortcut.svelte +23 -0
  361. package/src/lib/components/primitives/dropdown-menu/dropdown-menu-sub-content.svelte +31 -0
  362. package/src/lib/components/primitives/dropdown-menu/dropdown-menu-sub-trigger.svelte +29 -0
  363. package/src/lib/components/primitives/dropdown-menu/dropdown-menu-sub.svelte +7 -0
  364. package/src/lib/components/primitives/dropdown-menu/dropdown-menu-trigger.svelte +7 -0
  365. package/src/lib/components/primitives/dropdown-menu/dropdown-menu.svelte +7 -0
  366. package/src/lib/components/primitives/dropdown-menu/index.ts +54 -0
  367. package/src/lib/components/primitives/{alert/alert-description.svelte → empty/empty-content.svelte} +3 -3
  368. package/src/lib/components/primitives/empty/empty-description.svelte +23 -0
  369. package/src/lib/components/primitives/{alert/alert-title.svelte → empty/empty-header.svelte} +3 -3
  370. package/src/lib/components/primitives/empty/empty-media.svelte +41 -0
  371. package/src/lib/components/primitives/{card/card-action.svelte → empty/empty-title.svelte} +2 -2
  372. package/src/lib/components/primitives/empty/empty.svelte +23 -0
  373. package/src/lib/components/primitives/empty/index.ts +22 -0
  374. package/src/lib/components/primitives/index.ts +10 -1
  375. package/src/lib/components/primitives/input/input.svelte +4 -4
  376. package/src/lib/components/primitives/input-group/index.ts +22 -0
  377. package/src/lib/components/primitives/input-group/input-group-addon.svelte +53 -0
  378. package/src/lib/components/primitives/input-group/input-group-button.svelte +49 -0
  379. package/src/lib/components/primitives/input-group/input-group-input.svelte +25 -0
  380. package/src/lib/components/primitives/input-group/input-group-text.svelte +22 -0
  381. package/src/lib/components/primitives/input-group/input-group-textarea.svelte +23 -0
  382. package/src/lib/components/primitives/input-group/input-group.svelte +24 -0
  383. package/src/lib/components/primitives/mode-toggle/mode-toggle.svelte +6 -7
  384. package/src/lib/components/primitives/popover/index.ts +28 -0
  385. package/src/lib/components/primitives/popover/popover-close.svelte +7 -0
  386. package/src/lib/components/primitives/popover/popover-content.svelte +31 -0
  387. package/src/lib/components/primitives/popover/popover-description.svelte +20 -0
  388. package/src/lib/components/primitives/popover/popover-header.svelte +20 -0
  389. package/src/lib/components/primitives/popover/popover-portal.svelte +7 -0
  390. package/src/lib/components/primitives/popover/popover-title.svelte +15 -0
  391. package/src/lib/components/primitives/popover/popover-trigger.svelte +17 -0
  392. package/src/lib/components/primitives/popover/popover.svelte +7 -0
  393. package/src/lib/components/primitives/resizable/resizable-handle.svelte +6 -2
  394. package/src/lib/components/primitives/resizable/resizable-pane-group.svelte +1 -4
  395. package/src/lib/components/primitives/scroll-area/scroll-area.svelte +1 -1
  396. package/src/lib/components/primitives/search/search.svelte +3 -3
  397. package/src/lib/components/primitives/select/select-content.svelte +1 -1
  398. package/src/lib/components/primitives/select/select-trigger.svelte +1 -1
  399. package/src/lib/components/primitives/severity.ts +26 -0
  400. package/src/lib/components/primitives/slider/slider.svelte +8 -3
  401. package/src/lib/components/primitives/sonner/sonner.svelte +1 -1
  402. package/src/lib/components/primitives/spinner/index.ts +1 -0
  403. package/src/lib/components/primitives/spinner/spinner.svelte +29 -0
  404. package/src/lib/components/primitives/switch/switch.svelte +2 -2
  405. package/src/lib/components/primitives/tabs/tabs-list.svelte +27 -5
  406. package/src/lib/components/primitives/tabs/tabs-trigger.svelte +23 -5
  407. package/src/lib/components/primitives/tabs/tabs.svelte +6 -2
  408. package/src/lib/components/primitives/textarea/textarea.svelte +1 -1
  409. package/src/lib/components/primitives/theme-switcher/ThemeSwitcher.svelte +1 -1
  410. package/src/lib/components/primitives/toggle/index.ts +13 -0
  411. package/src/lib/components/primitives/toggle/toggle.svelte +54 -0
  412. package/src/lib/components/primitives/toggle-group/index.ts +10 -0
  413. package/src/lib/components/primitives/toggle-group/toggle-group-item.svelte +35 -0
  414. package/src/lib/components/primitives/toggle-group/toggle-group.svelte +75 -0
  415. package/src/lib/components/viewer/MeshMetadataPanel.svelte +119 -0
  416. package/src/lib/components/viewer/SceneManager.svelte +14 -5
  417. package/src/lib/components/viewer/Viewer.svelte +243 -221
  418. package/src/lib/compute/run-panel-action.ts +16 -0
  419. package/src/lib/compute/solving.svelte.ts +66 -50
  420. package/src/lib/compute/useSolveSession.svelte.ts +3 -0
  421. package/src/lib/constants.ts +7 -9
  422. package/src/lib/contexts/hostContext.svelte.ts +51 -0
  423. package/src/lib/i18n/localeContext.svelte.ts +40 -5
  424. package/src/lib/i18n/messages.ts +453 -13
  425. package/src/lib/index.ts +21 -0
  426. package/src/lib/public.ts +1 -0
  427. package/src/lib/schema/host-support.ts +129 -0
  428. package/src/lib/schema/option-display.ts +44 -0
  429. package/src/lib/schema/param-exporter.ts +10 -7
  430. package/src/lib/schema/visibility-rules.ts +23 -0
  431. package/src/lib/styles/base.css +80 -10
  432. package/src/lib/types/actionButton.ts +16 -3
  433. package/src/lib/types/presetLabels.ts +13 -11
  434. package/src/lib/utils/file-download.ts +11 -21
  435. package/src/lib/utils/host-files.ts +61 -0
  436. package/src/lib/utils/loadScript.ts +3 -0
  437. package/src/lib/utils/webp-to-png.ts +48 -0
  438. package/dist/components/primitives/alert/alert.svelte +0 -44
  439. package/dist/components/primitives/alert/alert.svelte.d.ts +0 -26
  440. package/dist/components/primitives/alert/index.d.ts +0 -5
  441. package/dist/components/primitives/alert/index.js +0 -7
  442. package/dist/components/viewer/MeshMetadataDialog.svelte +0 -126
  443. package/dist/components/viewer/MeshMetadataDialog.svelte.d.ts +0 -10
  444. package/src/lib/components/primitives/alert/alert.svelte +0 -44
  445. package/src/lib/components/primitives/alert/index.ts +0 -14
  446. package/src/lib/components/viewer/MeshMetadataDialog.svelte +0 -126
@@ -1,5 +1,5 @@
1
1
  <script lang="ts">
2
- import { Download, Upload, AlertTriangle, CheckCircle } from '@lucide/svelte';
2
+ import { Upload } from '@lucide/svelte';
3
3
  import type { UISchema, ParameterPreset } from '@selvajs/schemas';
4
4
  import {
5
5
  createSavedState,
@@ -8,18 +8,14 @@
8
8
  exportStateAsJson,
9
9
  importStateFromJson
10
10
  } from '../../schema/param-exporter';
11
- import { Button, Input, Label, Textarea, Dialog, Card, toast } from '../primitives';
12
-
13
- import type { ActionButton } from '../../types/actionButton';
11
+ import { Button, Input, Label, Textarea, Dialog, Callout, IssueList, toast } from '../primitives';
14
12
  import { DEFAULT_PRESET_LABELS, type PresetLabels } from '../../types/presetLabels';
13
+ import { pickFile } from '../../utils/host-files';
15
14
 
16
15
  interface Props {
17
16
  schema: UISchema;
18
17
  currentValues: Record<string, unknown>;
19
18
  onLoadValues: (values: Record<string, unknown>) => void;
20
- showSaveButton?: boolean;
21
- showLoadButton?: boolean;
22
- actions?: ActionButton[];
23
19
  /** When set, persist saved states via this callback instead of downloading a .slvp file. */
24
20
  onSaveState?: (state: ParameterPreset) => void | Promise<void>;
25
21
  /** When set, the Load dialog lists these states instead of showing a file input. */
@@ -28,17 +24,7 @@
28
24
  labels?: Partial<PresetLabels>;
29
25
  }
30
26
 
31
- let {
32
- schema,
33
- currentValues,
34
- onLoadValues,
35
- showSaveButton = true,
36
- showLoadButton = true,
37
- actions = [],
38
- onSaveState,
39
- onListStates,
40
- labels
41
- }: Props = $props();
27
+ let { schema, currentValues, onLoadValues, onSaveState, onListStates, labels }: Props = $props();
42
28
 
43
29
  const t = $derived({ ...DEFAULT_PRESET_LABELS, ...labels });
44
30
 
@@ -52,13 +38,13 @@
52
38
  let showLoadDialog = $state(false);
53
39
  let loadResult = $state<PresetLoadResult | null>(null);
54
40
  let loadingPresetName = $state('');
55
- let fileInputRef = $state<HTMLInputElement | null>(null);
56
41
 
57
42
  let listedStates = $state<ParameterPreset[]>([]);
58
43
  let isLoadingList = $state(false);
59
44
  let listError = $state('');
60
45
 
61
- function openExportDialog() {
46
+ /** Opens the save dialog. The panel footer's menu calls it. */
47
+ export function openSave() {
62
48
  exportName = `State ${new Date().toLocaleDateString()}`;
63
49
  exportDescription = '';
64
50
  exportAuthor = schema.author || '';
@@ -83,7 +69,7 @@
83
69
  });
84
70
 
85
71
  if (onSaveState) await onSaveState(state);
86
- else exportStateAsJson(state);
72
+ else await exportStateAsJson(state);
87
73
  showExportDialog = false;
88
74
  }
89
75
 
@@ -100,19 +86,16 @@
100
86
  }
101
87
  }
102
88
 
103
- async function handleImport(event: Event) {
104
- const input = event.target as HTMLInputElement;
105
- if (!input.files || input.files.length === 0) return;
89
+ async function importFromFile() {
90
+ // .sps is the pre-rename extension; files with it exist on users' drives, so keep accepting it.
91
+ const file = await pickFile({ accept: '.slvp,.sps' });
92
+ if (!file) return;
106
93
 
107
94
  try {
108
- const imported = await importStateFromJson(input.files[0]);
109
- tryLoad(imported);
95
+ tryLoad(await importStateFromJson(file));
110
96
  } catch (error) {
111
97
  toast.error(t.loadImportError + (error as Error).message);
112
98
  }
113
-
114
- // Reset so re-picking the same file fires `change` again.
115
- input.value = '';
116
99
  }
117
100
 
118
101
  function confirmLoad() {
@@ -128,7 +111,8 @@
128
111
  loadResult = null;
129
112
  }
130
113
 
131
- async function openLoadDialog() {
114
+ /** Opens the load dialog. The panel footer's menu calls it. */
115
+ export async function openLoad() {
132
116
  showLoadDialog = true;
133
117
  if (!onListStates) return;
134
118
 
@@ -145,8 +129,8 @@
145
129
  }
146
130
 
147
131
  function handleLoadClick() {
148
- fileInputRef?.click();
149
132
  showLoadDialog = false;
133
+ void importFromFile();
150
134
  }
151
135
 
152
136
  function selectListedState(preset: ParameterPreset) {
@@ -155,39 +139,6 @@
155
139
  }
156
140
  </script>
157
141
 
158
- {#if showSaveButton}
159
- <Button variant="default" size="sm" onclick={openExportDialog}>
160
- <Download class="mr-2 h-4 w-4" />
161
- {t.saveButton}
162
- </Button>
163
- {/if}
164
-
165
- {#if showLoadButton}
166
- <Button variant="outline" size="sm" onclick={openLoadDialog}>
167
- <Upload class="mr-2 h-4 w-4" />
168
- {t.loadButton}
169
- </Button>
170
- {/if}
171
-
172
- {#each actions as action (action.id)}
173
- <Button variant={action.variant ?? 'outline'} size={action.size ?? 'sm'} onclick={action.onclick}>
174
- {#if action.icon}
175
- {@const IconComponent = action.icon}
176
- <IconComponent class="mr-2 h-4 w-4" />
177
- {/if}
178
- {action.label}
179
- </Button>
180
- {/each}
181
-
182
- <!-- .sps is the pre-rename extension; files with it exist on users' drives, so keep accepting it. -->
183
- <input
184
- bind:this={fileInputRef}
185
- type="file"
186
- accept=".slvp,.sps"
187
- onchange={handleImport}
188
- class="hidden"
189
- />
190
-
191
142
  <!-- Save Dialog -->
192
143
  <Dialog.Root bind:open={showExportDialog}>
193
144
  <Dialog.Content>
@@ -225,7 +176,7 @@
225
176
 
226
177
  <Dialog.Footer>
227
178
  <Button variant="outline" onclick={() => (showExportDialog = false)}>{t.cancelButton}</Button>
228
- <Button onclick={handleExport}>{t.saveButton}</Button>
179
+ <Button onclick={handleExport}>{t.saveConfirmButton}</Button>
229
180
  </Dialog.Footer>
230
181
  </Dialog.Content>
231
182
  </Dialog.Root>
@@ -239,7 +190,7 @@
239
190
  </Dialog.Header>
240
191
 
241
192
  {#if onListStates}
242
- <div class="py-4 max-h-[60vh] overflow-y-auto">
193
+ <div class="py-4">
243
194
  {#if isLoadingList}
244
195
  <p class="text-sm py-8 text-center text-muted-foreground">…</p>
245
196
  {:else if listError}
@@ -283,7 +234,7 @@
283
234
 
284
235
  <!-- Validation Dialog -->
285
236
  <Dialog.Root bind:open={showValidationDialog}>
286
- <Dialog.Content class="max-w-2xl max-h-[80vh] overflow-y-auto">
237
+ <Dialog.Content class="max-w-2xl">
287
238
  <Dialog.Header>
288
239
  <Dialog.Title>{t.validationTitle}</Dialog.Title>
289
240
  <Dialog.Description>
@@ -296,75 +247,31 @@
296
247
  {#if loadResult}
297
248
  <div class="gap-4 py-4 grid">
298
249
  {#if loadResult.isValid}
299
- <Card.Root class="p-4 border-success/30 bg-success/5">
300
- <div class="gap-3 flex items-start">
301
- <CheckCircle class="h-5 w-5 text-success" />
302
- <div>
303
- <h4 class="text-sm font-semibold text-success-foreground">
304
- {t.validationNoIssuesTitle}
305
- </h4>
306
- <p class="text-sm mt-1 text-success-foreground/80">
307
- {t.validationNoIssuesBody}
308
- </p>
309
- </div>
310
- </div>
311
- </Card.Root>
250
+ <Callout tone="success" title={t.validationNoIssuesTitle}>
251
+ {t.validationNoIssuesBody}
252
+ </Callout>
312
253
  {:else if loadResult.canLoad}
313
- <Card.Root class="p-4 border-warning/30 bg-warning/5">
314
- <div class="gap-3 flex items-start">
315
- <AlertTriangle class="h-5 w-5 text-warning" />
316
- <div>
317
- <h4 class="text-sm font-semibold text-warning-foreground">
318
- {t.validationWarningsTitle}
319
- </h4>
320
- <p class="text-sm mt-1 text-warning-foreground/80">
321
- {t.validationWarningsBody.replace('{count}', String(loadResult.issues.length))}
322
- </p>
323
- </div>
324
- </div>
325
- </Card.Root>
254
+ <Callout tone="warning" title={t.validationWarningsTitle}>
255
+ {t.validationWarningsBody.replace('{count}', String(loadResult.issues.length))}
256
+ </Callout>
326
257
  {:else}
327
- <Card.Root class="p-4 border-destructive/30 bg-destructive/5">
328
- <div class="gap-3 flex items-start">
329
- <AlertTriangle class="h-5 w-5 text-destructive" />
330
- <div>
331
- <h4 class="text-sm font-semibold text-destructive">{t.validationErrorsTitle}</h4>
332
- <p class="text-sm mt-1 text-destructive/80">
333
- {t.validationErrorsBody}
334
- </p>
335
- </div>
336
- </div>
337
- </Card.Root>
258
+ <Callout tone="danger" title={t.validationErrorsTitle}>
259
+ {t.validationErrorsBody}
260
+ </Callout>
338
261
  {/if}
339
262
 
340
263
  {#if !loadResult.isValid}
341
- <div class="space-y-2">
264
+ <div class="gap-2 flex flex-col">
342
265
  <h4 class="text-sm font-medium">{t.validationIssuesHeading}</h4>
343
- {#each loadResult.issues as issue (issue.message)}
344
- <div
345
- class="p-3 rounded-lg border {issue.severity === 'error'
346
- ? 'border-destructive/30 bg-destructive/5'
347
- : 'border-warning/30 bg-warning/5'}"
348
- >
349
- <div class="gap-2 flex items-start">
350
- <AlertTriangle
351
- class="h-4 w-4 mt-0.5 {issue.severity === 'error'
352
- ? 'text-destructive'
353
- : 'text-warning'}"
354
- />
355
- <div class="flex-1">
356
- <p class="text-sm font-medium">{issue.message}</p>
357
- {#if issue.details}
358
- <p class="text-xs mt-1 text-muted-foreground">
359
- {t.validationExpected}
360
- {issue.details.expected} → {t.validationActual}
361
- {issue.details.actual}
362
- </p>
363
- {/if}
364
- </div>
365
- </div>
366
- </div>
367
- {/each}
266
+ <IssueList
267
+ issues={loadResult.issues.map((issue) => ({
268
+ severity: issue.severity === 'error' ? 'error' : 'warning',
269
+ message: issue.message,
270
+ detail: issue.details
271
+ ? `${t.validationExpected} ${issue.details.expected} → ${t.validationActual} ${issue.details.actual}`
272
+ : undefined
273
+ }))}
274
+ />
368
275
  </div>
369
276
  {/if}
370
277
  </div>
@@ -1,13 +1,9 @@
1
1
  import type { UISchema, ParameterPreset } from '@selvajs/schemas';
2
- import type { ActionButton } from '../../types/actionButton';
3
2
  import { type PresetLabels } from '../../types/presetLabels';
4
3
  interface Props {
5
4
  schema: UISchema;
6
5
  currentValues: Record<string, unknown>;
7
6
  onLoadValues: (values: Record<string, unknown>) => void;
8
- showSaveButton?: boolean;
9
- showLoadButton?: boolean;
10
- actions?: ActionButton[];
11
7
  /** When set, persist saved states via this callback instead of downloading a .slvp file. */
12
8
  onSaveState?: (state: ParameterPreset) => void | Promise<void>;
13
9
  /** When set, the Load dialog lists these states instead of showing a file input. */
@@ -15,6 +11,9 @@ interface Props {
15
11
  /** Overrides merged over `DEFAULT_PRESET_LABELS`. */
16
12
  labels?: Partial<PresetLabels>;
17
13
  }
18
- declare const ParameterPresetManager: import("svelte").Component<Props, {}, "">;
14
+ declare const ParameterPresetManager: import("svelte").Component<Props, {
15
+ openSave: () => void;
16
+ openLoad: () => Promise<void>;
17
+ }, "">;
19
18
  type ParameterPresetManager = ReturnType<typeof ParameterPresetManager>;
20
19
  export default ParameterPresetManager;
@@ -13,10 +13,13 @@
13
13
  // anything, so it appears on its own after the solve and fades.
14
14
 
15
15
  import { untrack } from 'svelte';
16
- import { CircleAlert, TriangleAlert, Info, LoaderCircle } from '@lucide/svelte';
16
+ import { LoaderCircle } from '@lucide/svelte';
17
17
  import type { SolveDiagnostic } from '@selvajs/solve/shared';
18
18
  import type { LiveSolveState, SolvePhase } from '@selvajs/solve/client';
19
19
  import { Button } from '../primitives/button';
20
+ import IssueList, { type Issue } from '../primitives/IssueList.svelte';
21
+ import SeverityIcon from '../primitives/SeverityIcon.svelte';
22
+ import { getLocaleContext } from '../../i18n/localeContext.svelte';
20
23
 
21
24
  interface Props {
22
25
  /** What the running (or most recent) solve has said over the live channel. */
@@ -28,33 +31,15 @@
28
31
  onabort: () => void;
29
32
  onconfirm: () => void;
30
33
  ondiscard: () => void;
31
- labels?: Labels;
34
+ /**
35
+ * See `createSolvingIndicator`. The live panel would only paint once the solve is over, so
36
+ * an Esc hint stands in for it; the result's messages still show.
37
+ */
38
+ freezesDuringSolve?: boolean;
39
+ /** `floating` overlays the bottom centre; `inline` sits in the flow below the host's content. */
40
+ placement?: 'floating' | 'inline';
32
41
  }
33
42
 
34
- interface Labels {
35
- solving: string;
36
- blockedTitle: string;
37
- messagesTitle: string;
38
- blockedDescription: string;
39
- messagesDescription: string;
40
- confirm: string;
41
- discard: string;
42
- abort: string;
43
- dismiss: string;
44
- }
45
-
46
- const DEFAULT_LABELS: Labels = {
47
- solving: 'Solving…',
48
- blockedTitle: 'Solve stopped',
49
- messagesTitle: 'Solve messages',
50
- blockedDescription: 'The definition stopped this solve. No results were produced.',
51
- messagesDescription: 'This solve reported the following. Continue to see the result.',
52
- confirm: 'Continue',
53
- discard: 'Discard',
54
- abort: 'Abort',
55
- dismiss: 'Dismiss'
56
- };
57
-
58
43
  let {
59
44
  live,
60
45
  phase: sessionPhase,
@@ -62,9 +47,13 @@
62
47
  onabort,
63
48
  onconfirm,
64
49
  ondiscard,
65
- labels = DEFAULT_LABELS
50
+ freezesDuringSolve = false,
51
+ placement = 'floating'
66
52
  }: Props = $props();
67
53
 
54
+ const locale = getLocaleContext();
55
+ const t = $derived(locale.messages);
56
+
68
57
  const REMARK_LINGER_MS = 6000;
69
58
 
70
59
  const progress = $derived([...live.progress.values()]);
@@ -137,16 +126,30 @@
137
126
  // Keyed on the diagnostics array's identity, which every report renews, rather than on a
138
127
  // solve id: only the live channel has one, and on the Compute path remarks arrive with the
139
128
  // result. Once per array, so remarks that sat behind a review do not reappear after Continue.
129
+ //
130
+ // A remark is shown once while it stays raised, not after every solve. Every report repeats
131
+ // it: Grasshopper keeps runtime messages on a Message component an input change did not
132
+ // reach, and Compute re-solves the whole definition. It shows again once a solve stops
133
+ // raising it and a later one raises it anew.
140
134
  let lingering = $state(false);
141
135
  let lingeredFor: SolveDiagnostic[] | null = null;
136
+ let shownRemarks: ReadonlySet<string> = new Set();
137
+ let freshRemarks = $state.raw<SolveDiagnostic[]>([]);
138
+ const remarkKey = (d: SolveDiagnostic) => `${d.source ?? ''}\u0000${d.message}`;
142
139
  $effect(() => {
143
140
  if (phase === 'live') {
144
141
  lingering = false;
145
142
  return;
146
143
  }
147
- if (authoredRemarks.length === 0 || lingeredFor === diagnostics) return;
144
+ if (lingeredFor === diagnostics) return;
148
145
  lingeredFor = diagnostics;
149
- if (phase !== 'idle') return;
146
+ const raised = authoredRemarks.map(remarkKey);
147
+ const stillShown = raised.filter((k) => shownRemarks.has(k));
148
+ const fresh = authoredRemarks.filter((d) => !shownRemarks.has(remarkKey(d)));
149
+ const showNow = phase === 'idle' && fresh.length > 0;
150
+ shownRemarks = new Set(showNow ? [...stillShown, ...fresh.map(remarkKey)] : stillShown);
151
+ if (!showNow) return;
152
+ freshRemarks = fresh;
150
153
  lingering = true;
151
154
  const timer = setTimeout(() => (lingering = false), REMARK_LINGER_MS);
152
155
  return () => clearTimeout(timer);
@@ -165,6 +168,7 @@
165
168
  $effect(() => {
166
169
  if (phase === 'live') {
167
170
  finishing = false;
171
+ if (freezesDuringSolve) return;
168
172
  const timer = setTimeout(() => {
169
173
  revealed = true;
170
174
  revealedAt = performance.now();
@@ -191,7 +195,16 @@
191
195
  // While solving, the live channel is all there is. Once the result lands it is authoritative
192
196
  // — it carries remarks too — so the live list is dropped entirely and nothing is shown twice.
193
197
  const rows = $derived<SolveDiagnostic[]>(
194
- view === 'live' ? [...live.diagnostics] : view === 'idle' ? authoredRemarks : authoredGating
198
+ view === 'live' ? [...live.diagnostics] : view === 'idle' ? freshRemarks : authoredGating
199
+ );
200
+
201
+ // A remark states something without asking anything, so it reads as a quiet note.
202
+ const issues = $derived<Issue[]>(
203
+ rows.map((d) => ({
204
+ severity: d.level === 'remark' ? 'note' : d.level,
205
+ message: d.message,
206
+ source: d.source
207
+ }))
195
208
  );
196
209
 
197
210
  // Steps a few milliseconds long would swap the headline faster than it can be read. Each one
@@ -228,28 +241,59 @@
228
241
  : rows.length > 0 && lingering
229
242
  );
230
243
 
244
+ // What a screen reader hears of the passive views, through a region that outlives the panel: one
245
+ // created together with its text is not announced. The step name, not its counter, so a long
246
+ // solve announces each step rather than every tick. Review and blocked are alerts of their own.
247
+ const announcement = $derived(
248
+ !visible
249
+ ? ''
250
+ : view === 'live'
251
+ ? ((headline ?? progress[0])?.label ?? t.solveSolving)
252
+ : view === 'idle'
253
+ ? rows.map((d) => d.message).join(' ')
254
+ : ''
255
+ );
256
+
231
257
  function dismiss() {
232
258
  dismissedFor = diagnostics;
233
259
  }
234
260
 
235
261
  // Escape resolves to the safe side — discard, keeping what is on screen — never to silently
236
- // applying a result the user has not accepted.
262
+ // applying a result the user has not accepted. A frozen host gets no keydown until the solve
263
+ // ends; there the plugin aborts on the key state, which only counts while Rhino is in front, so
264
+ // a browser tab (local or Compute) has to abort from the page.
237
265
  function handleKeydown(e: KeyboardEvent) {
238
266
  if (e.key !== 'Escape') return;
239
- if (phase === 'review') ondiscard();
267
+ if (phase === 'live') {
268
+ if (!freezesDuringSolve) onabort();
269
+ } else if (phase === 'review') ondiscard();
240
270
  else if (phase === 'blocked') dismiss();
241
271
  }
242
272
  </script>
243
273
 
244
274
  <svelte:window onkeydown={handleKeydown} />
245
275
 
246
- {#if visible}
276
+ <div class="sr-only" role="status" aria-live="polite">{announcement}</div>
277
+
278
+ {#if freezesDuringSolve && view === 'live'}
279
+ <!-- Painted before the solve takes the thread; Abort could not be clicked until it ends. Inline,
280
+ the solving chip carries the hint instead: a line here would resize the footer mid-solve. -->
281
+ {#if placement === 'floating'}
282
+ <p
283
+ class="bottom-4 text-xs fixed left-1/2 z-50 -translate-x-1/2 text-muted-foreground"
284
+ data-testid="solve-esc-hint"
285
+ >
286
+ {t.solveMessagesEscHint}
287
+ </p>
288
+ {/if}
289
+ {:else if visible}
290
+ <!-- Inline, it is a row of the host's footer like the Calculate row under it, not a card: a
291
+ framed box inside an edge-to-edge column reads as a dialog glued into the page. -->
247
292
  <div
248
- class="bottom-4 p-3 shadow-lg fixed left-1/2 z-50 w-[min(32rem,calc(100vw-2rem))] -translate-x-1/2 rounded-lg border bg-background {view ===
249
- 'blocked'
250
- ? 'border-destructive/50'
251
- : ''}"
252
- role={view === 'live' || view === 'idle' ? 'status' : 'alert'}
293
+ class={placement === 'inline'
294
+ ? `px-2 py-2 border-t ${view === 'blocked' ? 'border-destructive/40' : 'border-border/50'}`
295
+ : `p-3 bottom-4 shadow-lg w-lg fixed left-1/2 z-50 max-w-screen-inset -translate-x-1/2 rounded-lg border bg-background ${view === 'blocked' ? 'border-destructive/50' : ''}`}
296
+ role={view === 'review' || view === 'blocked' ? 'alert' : undefined}
253
297
  data-testid="solve-messages"
254
298
  data-view={view}
255
299
  >
@@ -259,7 +303,7 @@
259
303
  <div>
260
304
  <div class="gap-2 flex items-center">
261
305
  <LoaderCircle class="h-4 w-4 animate-spin shrink-0 text-muted-foreground" />
262
- <span class="min-w-0 text-sm flex-1 truncate">{head?.label ?? labels.solving}</span>
306
+ <span class="min-w-0 text-sm flex-1 truncate">{head?.label ?? t.solveSolving}</span>
263
307
  {#if head?.done !== undefined && head?.total !== undefined}
264
308
  <span class="text-xs shrink-0 text-muted-foreground tabular-nums">
265
309
  {head.done} / {head.total}
@@ -267,12 +311,17 @@
267
311
  {/if}
268
312
  <Button
269
313
  variant="secondary"
270
- size="sm"
271
- class="-my-1 h-7 px-3 text-xs shrink-0"
314
+ size="xs"
315
+ class="-my-1 shrink-0"
272
316
  disabled={finishing}
273
317
  onclick={onabort}
318
+ aria-keyshortcuts="Escape"
319
+ title={t.solveMessagesEscHint}
274
320
  >
275
- {labels.abort}
321
+ {t.solveMessagesAbort}
322
+ <kbd class="px-1 font-sans rounded border border-border/60 text-2xs opacity-70">
323
+ Esc
324
+ </kbd>
276
325
  </Button>
277
326
  </div>
278
327
  {#each progress as p, i (p.source ?? '')}
@@ -289,7 +338,7 @@
289
338
  <div
290
339
  class="h-1 overflow-hidden rounded-full bg-muted"
291
340
  role="progressbar"
292
- aria-label={p.label ?? p.source ?? labels.solving}
341
+ aria-label={p.label ?? p.source ?? t.solveSolving}
293
342
  aria-valuemin={0}
294
343
  aria-valuemax={100}
295
344
  aria-valuenow={p.fraction !== undefined ? Math.round(p.fraction * 100) : undefined}
@@ -299,8 +348,9 @@
299
348
  ? { width: 1, ms: FINISH_MS }
300
349
  : (bars[p.source ?? ''] ?? { width: p.fraction, ms: 150 })}
301
350
  <div
302
- class="h-full rounded-full bg-primary transition-[width] ease-linear"
303
- style="width: {bar.width * 100}%; transition-duration: {bar.ms}ms"
351
+ class="h-full w-(--bar-width) rounded-full bg-primary transition-all duration-(--bar-ms) ease-linear"
352
+ style:--bar-width="{bar.width * 100}%"
353
+ style:--bar-ms="{bar.ms}ms"
304
354
  ></div>
305
355
  {:else}
306
356
  <div class="animate-pulse h-full w-1/3 rounded-full bg-primary/60"></div>
@@ -310,56 +360,60 @@
310
360
  {/each}
311
361
  </div>
312
362
  </div>
363
+ {:else if (view === 'review' || view === 'blocked') && placement === 'inline'}
364
+ <!-- Each message carries its own icon, so the label goes without one; the buttons share
365
+ its row rather than adding one under a single line of text. -->
366
+ <div class="mb-1.5 gap-2 flex items-center">
367
+ <span
368
+ class="min-w-0 text-xs font-medium flex-1 truncate {view === 'blocked'
369
+ ? 'text-destructive'
370
+ : 'text-muted-foreground'}"
371
+ >
372
+ {view === 'blocked' ? t.solveBlockedTitle : t.solveMessagesTitle}
373
+ </span>
374
+ {#if view === 'blocked'}
375
+ <Button variant="ghost" size="xs" class="-my-1 shrink-0" onclick={dismiss}>
376
+ {t.solveMessagesDismiss}
377
+ </Button>
378
+ {:else}
379
+ <Button variant="ghost" size="xs" class="-my-1 shrink-0" onclick={ondiscard}>
380
+ {t.solveMessagesDiscard}
381
+ </Button>
382
+ <Button size="xs" class="-my-1 shrink-0" onclick={onconfirm}>
383
+ {t.solveMessagesConfirm}
384
+ </Button>
385
+ {/if}
386
+ </div>
313
387
  {:else if view === 'review' || view === 'blocked'}
314
388
  <div class="mb-2">
315
389
  <div class="gap-2 text-sm font-medium flex items-center">
316
390
  {#if view === 'blocked'}
317
- <CircleAlert class="h-4 w-4 shrink-0 text-destructive" />
318
- {labels.blockedTitle}
391
+ <SeverityIcon severity="error" />
392
+ {t.solveBlockedTitle}
319
393
  {:else}
320
- <TriangleAlert class="h-4 w-4 text-amber-500 shrink-0" />
321
- {labels.messagesTitle}
394
+ <SeverityIcon severity="warning" />
395
+ {t.solveMessagesTitle}
322
396
  {/if}
323
397
  </div>
324
398
  <p class="text-xs text-muted-foreground">
325
- {view === 'blocked' ? labels.blockedDescription : labels.messagesDescription}
399
+ {view === 'blocked' ? t.solveBlocked : t.solveMessagesDescription}
326
400
  </p>
327
401
  </div>
328
402
  {/if}
329
403
 
330
404
  {#if rows.length > 0}
331
- <ul
332
- class="max-h-40 space-y-2 text-sm overflow-y-auto {view === 'live'
333
- ? 'mt-3 pt-3 border-t'
334
- : ''}"
335
- >
336
- {#each rows as row, i (i)}
337
- <li class="gap-2 flex">
338
- {#if row.level === 'error'}
339
- <CircleAlert class="mt-0.5 h-4 w-4 shrink-0 text-destructive" />
340
- {:else if row.level === 'warning'}
341
- <TriangleAlert class="mt-0.5 h-4 w-4 text-amber-500 shrink-0" />
342
- {:else}
343
- <Info class="mt-0.5 h-4 w-4 shrink-0 text-muted-foreground" />
344
- {/if}
345
- <div class="min-w-0 flex-1">
346
- <p class="wrap-anywhere">{row.message}</p>
347
- {#if row.source}
348
- <p class="text-xs text-muted-foreground">{row.source}</p>
349
- {/if}
350
- </div>
351
- </li>
352
- {/each}
353
- </ul>
405
+ <div class="max-h-40 overflow-y-auto {view === 'live' ? 'mt-3 pt-3 border-t' : ''}">
406
+ <IssueList {issues} variant="plain" />
407
+ </div>
354
408
  {/if}
355
409
 
356
- {#if view === 'review' || view === 'blocked'}
410
+ {#if (view === 'review' || view === 'blocked') && placement === 'floating'}
357
411
  <div class="mt-3 gap-2 flex justify-end">
358
412
  {#if view === 'blocked'}
359
- <Button variant="outline" size="sm" onclick={dismiss}>{labels.dismiss}</Button>
413
+ <Button variant="outline" size="sm" onclick={dismiss}>{t.solveMessagesDismiss}</Button>
360
414
  {:else}
361
- <Button variant="outline" size="sm" onclick={ondiscard}>{labels.discard}</Button>
362
- <Button size="sm" onclick={onconfirm}>{labels.confirm}</Button>
415
+ <Button variant="outline" size="sm" onclick={ondiscard}>{t.solveMessagesDiscard}</Button>
416
+ <Button size="sm" onclick={onconfirm}>{t.solveMessagesConfirm}</Button>
363
417
  {/if}
364
418
  </div>
365
419
  {/if}
@@ -1,16 +1,5 @@
1
1
  import type { SolveDiagnostic } from '@selvajs/solve/shared';
2
2
  import type { LiveSolveState, SolvePhase } from '@selvajs/solve/client';
3
- interface Labels {
4
- solving: string;
5
- blockedTitle: string;
6
- messagesTitle: string;
7
- blockedDescription: string;
8
- messagesDescription: string;
9
- confirm: string;
10
- discard: string;
11
- abort: string;
12
- dismiss: string;
13
- }
14
3
  interface Props {
15
4
  /** What the running (or most recent) solve has said over the live channel. */
16
5
  live: LiveSolveState;
@@ -21,7 +10,13 @@ interface Props {
21
10
  onabort: () => void;
22
11
  onconfirm: () => void;
23
12
  ondiscard: () => void;
24
- labels?: Labels;
13
+ /**
14
+ * See `createSolvingIndicator`. The live panel would only paint once the solve is over, so
15
+ * an Esc hint stands in for it; the result's messages still show.
16
+ */
17
+ freezesDuringSolve?: boolean;
18
+ /** `floating` overlays the bottom centre; `inline` sits in the flow below the host's content. */
19
+ placement?: 'floating' | 'inline';
25
20
  }
26
21
  declare const SolveMessages: import("svelte").Component<Props, {}, "">;
27
22
  type SolveMessages = ReturnType<typeof SolveMessages>;