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

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 (444) 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 +286 -116
  4. package/dist/components/compute/AppLayout.svelte.d.ts +22 -0
  5. package/dist/components/compute/ComputeApp.svelte +45 -24
  6. package/dist/components/compute/ComputeApp.svelte.d.ts +19 -2
  7. package/dist/components/compute/ComputeMessagesDialog.svelte +47 -83
  8. package/dist/components/compute/ParameterPresetManager.svelte +37 -130
  9. package/dist/components/compute/ParameterPresetManager.svelte.d.ts +4 -5
  10. package/dist/components/compute/SolveMessages.svelte +131 -77
  11. package/dist/components/compute/SolveMessages.svelte.d.ts +7 -12
  12. package/dist/components/layout/AppShell.svelte +10 -6
  13. package/dist/components/layout/PageFooter.svelte +23 -11
  14. package/dist/components/layout/PageHeader.svelte +11 -7
  15. package/dist/components/layout/Pagination.svelte +2 -4
  16. package/dist/components/layout/SectionHeader.svelte +4 -2
  17. package/dist/components/layout/SideNav.svelte +56 -7
  18. package/dist/components/preview/ChartOutput.svelte +35 -25
  19. package/dist/components/preview/Group.svelte +92 -103
  20. package/dist/components/preview/Group.svelte.d.ts +1 -1
  21. package/dist/components/preview/HelpButton.svelte +36 -0
  22. package/dist/components/preview/HelpButton.svelte.d.ts +8 -0
  23. package/dist/components/preview/ImageOutput.svelte +430 -71
  24. package/dist/components/preview/InputControl.svelte +163 -90
  25. package/dist/components/preview/InputControl.svelte.d.ts +5 -1
  26. package/dist/components/preview/OutputDisplay.svelte +28 -33
  27. package/dist/components/preview/TabBar.svelte +106 -22
  28. package/dist/components/preview/TabBar.svelte.d.ts +1 -0
  29. package/dist/components/preview/TabContent.svelte +63 -57
  30. package/dist/components/preview/TabContent.svelte.d.ts +5 -1
  31. package/dist/components/preview/TabLayout.svelte +27 -5
  32. package/dist/components/preview/TabLayout.svelte.d.ts +5 -0
  33. package/dist/components/preview/inputs/CheckboxInput.svelte +7 -7
  34. package/dist/components/preview/inputs/CheckboxInput.svelte.d.ts +3 -0
  35. package/dist/components/preview/inputs/ChecklistInput.svelte +7 -2
  36. package/dist/components/preview/inputs/ChecklistInput.svelte.d.ts +2 -1
  37. package/dist/components/preview/inputs/ColorInput.svelte +4 -2
  38. package/dist/components/preview/inputs/ColorInput.svelte.d.ts +1 -0
  39. package/dist/components/preview/inputs/DropdownInput.svelte +19 -4
  40. package/dist/components/preview/inputs/DropdownInput.svelte.d.ts +2 -1
  41. package/dist/components/preview/inputs/FileInput.svelte +112 -108
  42. package/dist/components/preview/inputs/GeometryInput.svelte +128 -0
  43. package/dist/components/preview/inputs/GeometryInput.svelte.d.ts +21 -0
  44. package/dist/components/preview/inputs/NumberInput.svelte +123 -61
  45. package/dist/components/preview/inputs/NumberInput.svelte.d.ts +2 -0
  46. package/dist/components/preview/inputs/OptionGlyph.svelte +29 -0
  47. package/dist/components/preview/inputs/OptionGlyph.svelte.d.ts +8 -0
  48. package/dist/components/preview/inputs/SegmentedInput.svelte +44 -0
  49. package/dist/components/preview/inputs/SegmentedInput.svelte.d.ts +12 -0
  50. package/dist/components/preview/inputs/TextInput.svelte +8 -4
  51. package/dist/components/preview/inputs/TileInput.svelte +80 -0
  52. package/dist/components/preview/inputs/TileInput.svelte.d.ts +12 -0
  53. package/dist/components/preview/inputs/index.d.ts +3 -0
  54. package/dist/components/preview/inputs/index.js +3 -0
  55. package/dist/components/primitives/CalculateButton.svelte +56 -24
  56. package/dist/components/primitives/CalculateButton.svelte.d.ts +3 -0
  57. package/dist/components/primitives/Callout.svelte +11 -18
  58. package/dist/components/primitives/DataTable.svelte +38 -5
  59. package/dist/components/primitives/DataTable.svelte.d.ts +2 -0
  60. package/dist/components/primitives/FilterableDropdown.svelte +42 -129
  61. package/dist/components/primitives/FilterableDropdown.svelte.d.ts +1 -1
  62. package/dist/components/primitives/IssueList.svelte +56 -0
  63. package/dist/components/primitives/IssueList.svelte.d.ts +20 -0
  64. package/dist/components/primitives/SeverityIcon.svelte +15 -0
  65. package/dist/components/primitives/SeverityIcon.svelte.d.ts +8 -0
  66. package/dist/components/primitives/SolvingIndicator.svelte +43 -42
  67. package/dist/components/primitives/SolvingIndicator.svelte.d.ts +6 -0
  68. package/dist/components/primitives/StateDisplay.svelte +19 -79
  69. package/dist/components/primitives/ViewToggle.svelte +18 -33
  70. package/dist/components/primitives/alert-dialog/alert-dialog-action.svelte +9 -3
  71. package/dist/components/primitives/alert-dialog/alert-dialog-action.svelte.d.ts +6 -1
  72. package/dist/components/primitives/alert-dialog/alert-dialog-content.svelte +1 -1
  73. package/dist/components/primitives/alert-dialog/alert-dialog-overlay.svelte +1 -1
  74. package/dist/components/primitives/badge/badge.svelte +2 -2
  75. package/dist/components/primitives/badge/badge.svelte.d.ts +4 -4
  76. package/dist/components/primitives/button/button.svelte +6 -2
  77. package/dist/components/primitives/button/button.svelte.d.ts +10 -4
  78. package/dist/components/primitives/card/card-header.svelte +1 -1
  79. package/dist/components/primitives/card/card.svelte +21 -5
  80. package/dist/components/primitives/card/card.svelte.d.ts +25 -1
  81. package/dist/components/primitives/card/index.d.ts +1 -2
  82. package/dist/components/primitives/card/index.js +2 -3
  83. package/dist/components/primitives/checkbox/checkbox.svelte +1 -1
  84. package/dist/components/primitives/command/command-dialog.svelte +42 -0
  85. package/dist/components/primitives/command/command-dialog.svelte.d.ts +14 -0
  86. package/dist/components/primitives/command/command-empty.svelte +17 -0
  87. package/dist/components/primitives/command/command-empty.svelte.d.ts +4 -0
  88. package/dist/components/primitives/command/command-group.svelte +33 -0
  89. package/dist/components/primitives/command/command-group.svelte.d.ts +7 -0
  90. package/dist/components/primitives/command/command-input.svelte +36 -0
  91. package/dist/components/primitives/command/command-input.svelte.d.ts +4 -0
  92. package/dist/components/primitives/command/command-item.svelte +28 -0
  93. package/dist/components/primitives/command/command-item.svelte.d.ts +4 -0
  94. package/dist/components/primitives/command/command-link-item.svelte +21 -0
  95. package/dist/components/primitives/command/command-link-item.svelte.d.ts +4 -0
  96. package/dist/components/primitives/command/command-list.svelte +20 -0
  97. package/dist/components/primitives/command/command-list.svelte.d.ts +4 -0
  98. package/dist/components/primitives/command/command-loading.svelte +7 -0
  99. package/dist/components/primitives/command/command-loading.svelte.d.ts +4 -0
  100. package/dist/components/primitives/command/command-separator.svelte +17 -0
  101. package/dist/components/primitives/command/command-separator.svelte.d.ts +4 -0
  102. package/dist/components/primitives/command/command-shortcut.svelte +23 -0
  103. package/dist/components/primitives/command/command-shortcut.svelte.d.ts +5 -0
  104. package/dist/components/primitives/command/command.svelte +28 -0
  105. package/dist/components/primitives/command/command.svelte.d.ts +8 -0
  106. package/dist/components/primitives/command/index.d.ts +12 -0
  107. package/dist/components/primitives/command/index.js +14 -0
  108. package/dist/components/primitives/context-menu/context-menu-content.svelte +1 -1
  109. package/dist/components/primitives/context-menu/context-menu-sub-content.svelte +1 -1
  110. package/dist/components/primitives/dialog/dialog-content.svelte +11 -3
  111. package/dist/components/primitives/dialog/dialog-content.svelte.d.ts +2 -0
  112. package/dist/components/primitives/dialog/dialog-overlay.svelte +1 -1
  113. package/dist/components/primitives/dialog/dialog-title.svelte +6 -2
  114. package/dist/components/primitives/dialog/dialog-title.svelte.d.ts +5 -1
  115. package/dist/components/primitives/drawer/Drawer.svelte +2 -2
  116. package/dist/components/primitives/dropdown-menu/dropdown-menu-checkbox-group.svelte +16 -0
  117. package/dist/components/primitives/dropdown-menu/dropdown-menu-checkbox-group.svelte.d.ts +4 -0
  118. package/dist/components/primitives/dropdown-menu/dropdown-menu-checkbox-item.svelte +46 -0
  119. package/dist/components/primitives/dropdown-menu/dropdown-menu-checkbox-item.svelte.d.ts +9 -0
  120. package/dist/components/primitives/dropdown-menu/dropdown-menu-content.svelte +31 -0
  121. package/dist/components/primitives/dropdown-menu/dropdown-menu-content.svelte.d.ts +10 -0
  122. package/dist/components/primitives/dropdown-menu/dropdown-menu-group-heading.svelte +22 -0
  123. package/dist/components/primitives/dropdown-menu/dropdown-menu-group-heading.svelte.d.ts +8 -0
  124. package/dist/components/primitives/dropdown-menu/dropdown-menu-group.svelte +7 -0
  125. package/dist/components/primitives/dropdown-menu/dropdown-menu-group.svelte.d.ts +4 -0
  126. package/dist/components/primitives/dropdown-menu/dropdown-menu-item.svelte +27 -0
  127. package/dist/components/primitives/dropdown-menu/dropdown-menu-item.svelte.d.ts +8 -0
  128. package/dist/components/primitives/dropdown-menu/dropdown-menu-label.svelte +24 -0
  129. package/dist/components/primitives/dropdown-menu/dropdown-menu-label.svelte.d.ts +8 -0
  130. package/dist/components/primitives/dropdown-menu/dropdown-menu-portal.svelte +7 -0
  131. package/dist/components/primitives/dropdown-menu/dropdown-menu-portal.svelte.d.ts +3 -0
  132. package/dist/components/primitives/dropdown-menu/dropdown-menu-radio-group.svelte +16 -0
  133. package/dist/components/primitives/dropdown-menu/dropdown-menu-radio-group.svelte.d.ts +4 -0
  134. package/dist/components/primitives/dropdown-menu/dropdown-menu-radio-item.svelte +36 -0
  135. package/dist/components/primitives/dropdown-menu/dropdown-menu-radio-item.svelte.d.ts +4 -0
  136. package/dist/components/primitives/dropdown-menu/dropdown-menu-separator.svelte +17 -0
  137. package/dist/components/primitives/dropdown-menu/dropdown-menu-separator.svelte.d.ts +4 -0
  138. package/dist/components/primitives/dropdown-menu/dropdown-menu-shortcut.svelte +23 -0
  139. package/dist/components/primitives/dropdown-menu/dropdown-menu-shortcut.svelte.d.ts +5 -0
  140. package/dist/components/primitives/dropdown-menu/dropdown-menu-sub-content.svelte +31 -0
  141. package/dist/components/primitives/dropdown-menu/dropdown-menu-sub-content.svelte.d.ts +10 -0
  142. package/dist/components/primitives/dropdown-menu/dropdown-menu-sub-trigger.svelte +29 -0
  143. package/dist/components/primitives/dropdown-menu/dropdown-menu-sub-trigger.svelte.d.ts +7 -0
  144. package/dist/components/primitives/dropdown-menu/dropdown-menu-sub.svelte +7 -0
  145. package/dist/components/primitives/dropdown-menu/dropdown-menu-sub.svelte.d.ts +3 -0
  146. package/dist/components/primitives/dropdown-menu/dropdown-menu-trigger.svelte +7 -0
  147. package/dist/components/primitives/dropdown-menu/dropdown-menu-trigger.svelte.d.ts +4 -0
  148. package/dist/components/primitives/dropdown-menu/dropdown-menu.svelte +7 -0
  149. package/dist/components/primitives/dropdown-menu/dropdown-menu.svelte.d.ts +3 -0
  150. package/dist/components/primitives/dropdown-menu/index.d.ts +18 -0
  151. package/dist/components/primitives/dropdown-menu/index.js +18 -0
  152. package/dist/components/primitives/{alert/alert-description.svelte → empty/empty-content.svelte} +3 -3
  153. package/dist/components/primitives/empty/empty-content.svelte.d.ts +5 -0
  154. package/dist/components/primitives/empty/empty-description.svelte +23 -0
  155. package/dist/components/primitives/{alert/alert-description.svelte.d.ts → empty/empty-description.svelte.d.ts} +4 -4
  156. package/dist/components/primitives/{alert/alert-title.svelte → empty/empty-header.svelte} +3 -3
  157. package/dist/components/primitives/empty/empty-header.svelte.d.ts +5 -0
  158. package/dist/components/primitives/empty/empty-media.svelte +41 -0
  159. package/dist/components/primitives/empty/empty-media.svelte.d.ts +26 -0
  160. package/dist/components/primitives/{card/card-action.svelte → empty/empty-title.svelte} +2 -2
  161. package/dist/components/primitives/{card/card-action.svelte.d.ts → empty/empty-title.svelte.d.ts} +3 -3
  162. package/dist/components/primitives/empty/empty.svelte +23 -0
  163. package/dist/components/primitives/empty/empty.svelte.d.ts +5 -0
  164. package/dist/components/primitives/empty/index.d.ts +7 -0
  165. package/dist/components/primitives/empty/index.js +9 -0
  166. package/dist/components/primitives/index.d.ts +10 -1
  167. package/dist/components/primitives/index.js +10 -1
  168. package/dist/components/primitives/input/input.svelte +4 -4
  169. package/dist/components/primitives/input-group/index.d.ts +7 -0
  170. package/dist/components/primitives/input-group/index.js +9 -0
  171. package/dist/components/primitives/input-group/input-group-addon.svelte +53 -0
  172. package/dist/components/primitives/input-group/input-group-addon.svelte.d.ts +32 -0
  173. package/dist/components/primitives/input-group/input-group-button.svelte +49 -0
  174. package/dist/components/primitives/input-group/input-group-button.svelte.d.ts +32 -0
  175. package/dist/components/primitives/input-group/input-group-input.svelte +25 -0
  176. package/dist/components/primitives/input-group/input-group-input.svelte.d.ts +11 -0
  177. package/dist/components/primitives/input-group/input-group-text.svelte +22 -0
  178. package/dist/components/primitives/input-group/input-group-text.svelte.d.ts +5 -0
  179. package/dist/components/primitives/input-group/input-group-textarea.svelte +23 -0
  180. package/dist/components/primitives/input-group/input-group-textarea.svelte.d.ts +3 -0
  181. package/dist/components/primitives/input-group/input-group.svelte +24 -0
  182. package/dist/components/primitives/{alert/alert-title.svelte.d.ts → input-group/input-group.svelte.d.ts} +4 -4
  183. package/dist/components/primitives/mode-toggle/mode-toggle.svelte +6 -7
  184. package/dist/components/primitives/popover/index.d.ts +9 -0
  185. package/dist/components/primitives/popover/index.js +11 -0
  186. package/dist/components/primitives/popover/popover-close.svelte +7 -0
  187. package/dist/components/primitives/popover/popover-close.svelte.d.ts +4 -0
  188. package/dist/components/primitives/popover/popover-content.svelte +31 -0
  189. package/dist/components/primitives/popover/popover-content.svelte.d.ts +10 -0
  190. package/dist/components/primitives/popover/popover-description.svelte +20 -0
  191. package/dist/components/primitives/popover/popover-description.svelte.d.ts +5 -0
  192. package/dist/components/primitives/popover/popover-header.svelte +20 -0
  193. package/dist/components/primitives/popover/popover-header.svelte.d.ts +5 -0
  194. package/dist/components/primitives/popover/popover-portal.svelte +7 -0
  195. package/dist/components/primitives/popover/popover-portal.svelte.d.ts +3 -0
  196. package/dist/components/primitives/popover/popover-title.svelte +15 -0
  197. package/dist/components/primitives/popover/popover-title.svelte.d.ts +5 -0
  198. package/dist/components/primitives/popover/popover-trigger.svelte +17 -0
  199. package/dist/components/primitives/popover/popover-trigger.svelte.d.ts +4 -0
  200. package/dist/components/primitives/popover/popover.svelte +7 -0
  201. package/dist/components/primitives/popover/popover.svelte.d.ts +3 -0
  202. package/dist/components/primitives/resizable/resizable-handle.svelte +6 -2
  203. package/dist/components/primitives/resizable/resizable-handle.svelte.d.ts +2 -0
  204. package/dist/components/primitives/resizable/resizable-pane-group.svelte +1 -4
  205. package/dist/components/primitives/scroll-area/scroll-area.svelte +1 -1
  206. package/dist/components/primitives/search/search.svelte +3 -3
  207. package/dist/components/primitives/select/select-content.svelte +1 -1
  208. package/dist/components/primitives/select/select-trigger.svelte +1 -1
  209. package/dist/components/primitives/severity.d.ts +7 -0
  210. package/dist/components/primitives/severity.js +19 -0
  211. package/dist/components/primitives/slider/slider.svelte +8 -3
  212. package/dist/components/primitives/slider/slider.svelte.d.ts +5 -1
  213. package/dist/components/primitives/sonner/sonner.svelte +1 -1
  214. package/dist/components/primitives/spinner/index.d.ts +1 -0
  215. package/dist/components/primitives/spinner/index.js +1 -0
  216. package/dist/components/primitives/spinner/spinner.svelte +29 -0
  217. package/dist/components/primitives/spinner/spinner.svelte.d.ts +4 -0
  218. package/dist/components/primitives/switch/switch.svelte +2 -2
  219. package/dist/components/primitives/tabs/tabs-list.svelte +27 -5
  220. package/dist/components/primitives/tabs/tabs-list.svelte.d.ts +22 -1
  221. package/dist/components/primitives/tabs/tabs-trigger.svelte +23 -5
  222. package/dist/components/primitives/tabs/tabs-trigger.svelte.d.ts +22 -1
  223. package/dist/components/primitives/tabs/tabs.svelte +6 -2
  224. package/dist/components/primitives/tabs/tabs.svelte.d.ts +5 -1
  225. package/dist/components/primitives/textarea/textarea.svelte +1 -1
  226. package/dist/components/primitives/theme-switcher/ThemeSwitcher.svelte +1 -1
  227. package/dist/components/primitives/toggle/index.d.ts +3 -0
  228. package/dist/components/primitives/toggle/index.js +5 -0
  229. package/dist/components/primitives/toggle/toggle.svelte +54 -0
  230. package/dist/components/primitives/toggle/toggle.svelte.d.ts +46 -0
  231. package/dist/components/primitives/toggle-group/index.d.ts +3 -0
  232. package/dist/components/primitives/toggle-group/index.js +5 -0
  233. package/dist/components/primitives/toggle-group/toggle-group-item.svelte +35 -0
  234. package/dist/components/primitives/toggle-group/toggle-group-item.svelte.d.ts +6 -0
  235. package/dist/components/primitives/toggle-group/toggle-group.svelte +75 -0
  236. package/dist/components/primitives/toggle-group/toggle-group.svelte.d.ts +17 -0
  237. package/dist/components/viewer/MeshMetadataPanel.svelte +119 -0
  238. package/dist/components/viewer/MeshMetadataPanel.svelte.d.ts +9 -0
  239. package/dist/components/viewer/SceneManager.svelte +14 -5
  240. package/dist/components/viewer/Viewer.svelte +243 -221
  241. package/dist/components/viewer/Viewer.svelte.d.ts +3 -0
  242. package/dist/compute/run-panel-action.d.ts +8 -0
  243. package/dist/compute/run-panel-action.js +12 -0
  244. package/dist/compute/solving.svelte.d.ts +11 -7
  245. package/dist/compute/solving.svelte.js +64 -45
  246. package/dist/compute/useSolveSession.svelte.js +3 -0
  247. package/dist/constants.d.ts +6 -8
  248. package/dist/constants.js +7 -9
  249. package/dist/contexts/hostContext.svelte.d.ts +39 -0
  250. package/dist/contexts/hostContext.svelte.js +9 -0
  251. package/dist/i18n/localeContext.svelte.d.ts +10 -3
  252. package/dist/i18n/localeContext.svelte.js +27 -5
  253. package/dist/i18n/messages.d.ts +150 -2
  254. package/dist/i18n/messages.js +261 -11
  255. package/dist/index.d.ts +4 -1
  256. package/dist/index.js +3 -0
  257. package/dist/public.d.ts +1 -1
  258. package/dist/schema/host-support.d.ts +29 -0
  259. package/dist/schema/host-support.js +97 -0
  260. package/dist/schema/option-display.d.ts +12 -0
  261. package/dist/schema/option-display.js +29 -0
  262. package/dist/schema/param-exporter.d.ts +4 -1
  263. package/dist/schema/param-exporter.js +10 -6
  264. package/dist/schema/visibility-rules.js +21 -0
  265. package/dist/styles/base.css +80 -10
  266. package/dist/types/actionButton.d.ts +17 -3
  267. package/dist/types/presetLabels.d.ts +3 -2
  268. package/dist/types/presetLabels.js +9 -8
  269. package/dist/utils/file-download.js +10 -22
  270. package/dist/utils/host-files.d.ts +12 -0
  271. package/dist/utils/host-files.js +46 -0
  272. package/dist/utils/loadScript.d.ts +2 -0
  273. package/dist/utils/loadScript.js +2 -0
  274. package/dist/utils/webp-to-png.d.ts +10 -0
  275. package/dist/utils/webp-to-png.js +41 -0
  276. package/package.json +14 -14
  277. package/src/lib/components/ConfirmDialog.svelte +2 -10
  278. package/src/lib/components/ErrorScreen.svelte +21 -27
  279. package/src/lib/components/compute/AppLayout.svelte +286 -116
  280. package/src/lib/components/compute/ComputeApp.svelte +45 -24
  281. package/src/lib/components/compute/ComputeMessagesDialog.svelte +47 -83
  282. package/src/lib/components/compute/ParameterPresetManager.svelte +37 -130
  283. package/src/lib/components/compute/SolveMessages.svelte +131 -77
  284. package/src/lib/components/layout/AppShell.svelte +10 -6
  285. package/src/lib/components/layout/PageFooter.svelte +23 -11
  286. package/src/lib/components/layout/PageHeader.svelte +11 -7
  287. package/src/lib/components/layout/Pagination.svelte +2 -4
  288. package/src/lib/components/layout/SectionHeader.svelte +4 -2
  289. package/src/lib/components/layout/SideNav.svelte +56 -7
  290. package/src/lib/components/preview/ChartOutput.svelte +35 -25
  291. package/src/lib/components/preview/Group.svelte +92 -103
  292. package/src/lib/components/preview/HelpButton.svelte +36 -0
  293. package/src/lib/components/preview/ImageOutput.svelte +430 -71
  294. package/src/lib/components/preview/InputControl.svelte +163 -90
  295. package/src/lib/components/preview/OutputDisplay.svelte +28 -33
  296. package/src/lib/components/preview/TabBar.svelte +106 -22
  297. package/src/lib/components/preview/TabContent.svelte +63 -57
  298. package/src/lib/components/preview/TabLayout.svelte +27 -5
  299. package/src/lib/components/preview/inputs/CheckboxInput.svelte +7 -7
  300. package/src/lib/components/preview/inputs/ChecklistInput.svelte +7 -2
  301. package/src/lib/components/preview/inputs/ColorInput.svelte +4 -2
  302. package/src/lib/components/preview/inputs/DropdownInput.svelte +19 -4
  303. package/src/lib/components/preview/inputs/FileInput.svelte +112 -108
  304. package/src/lib/components/preview/inputs/GeometryInput.svelte +128 -0
  305. package/src/lib/components/preview/inputs/NumberInput.svelte +123 -61
  306. package/src/lib/components/preview/inputs/OptionGlyph.svelte +29 -0
  307. package/src/lib/components/preview/inputs/SegmentedInput.svelte +44 -0
  308. package/src/lib/components/preview/inputs/TextInput.svelte +8 -4
  309. package/src/lib/components/preview/inputs/TileInput.svelte +80 -0
  310. package/src/lib/components/preview/inputs/index.ts +3 -0
  311. package/src/lib/components/primitives/CalculateButton.svelte +56 -24
  312. package/src/lib/components/primitives/Callout.svelte +11 -18
  313. package/src/lib/components/primitives/DataTable.svelte +38 -5
  314. package/src/lib/components/primitives/FilterableDropdown.svelte +42 -129
  315. package/src/lib/components/primitives/IssueList.svelte +56 -0
  316. package/src/lib/components/primitives/SeverityIcon.svelte +15 -0
  317. package/src/lib/components/primitives/SolvingIndicator.svelte +43 -42
  318. package/src/lib/components/primitives/StateDisplay.svelte +19 -79
  319. package/src/lib/components/primitives/ViewToggle.svelte +18 -33
  320. package/src/lib/components/primitives/alert-dialog/alert-dialog-action.svelte +9 -3
  321. package/src/lib/components/primitives/alert-dialog/alert-dialog-content.svelte +1 -1
  322. package/src/lib/components/primitives/alert-dialog/alert-dialog-overlay.svelte +1 -1
  323. package/src/lib/components/primitives/badge/badge.svelte +2 -2
  324. package/src/lib/components/primitives/button/button.svelte +6 -2
  325. package/src/lib/components/primitives/card/card-header.svelte +1 -1
  326. package/src/lib/components/primitives/card/card.svelte +21 -5
  327. package/src/lib/components/primitives/card/index.ts +1 -4
  328. package/src/lib/components/primitives/checkbox/checkbox.svelte +1 -1
  329. package/src/lib/components/primitives/command/command-dialog.svelte +42 -0
  330. package/src/lib/components/primitives/command/command-empty.svelte +17 -0
  331. package/src/lib/components/primitives/command/command-group.svelte +33 -0
  332. package/src/lib/components/primitives/command/command-input.svelte +36 -0
  333. package/src/lib/components/primitives/command/command-item.svelte +28 -0
  334. package/src/lib/components/primitives/command/command-link-item.svelte +21 -0
  335. package/src/lib/components/primitives/command/command-list.svelte +20 -0
  336. package/src/lib/components/primitives/command/command-loading.svelte +7 -0
  337. package/src/lib/components/primitives/command/command-separator.svelte +17 -0
  338. package/src/lib/components/primitives/command/command-shortcut.svelte +23 -0
  339. package/src/lib/components/primitives/command/command.svelte +28 -0
  340. package/src/lib/components/primitives/command/index.ts +37 -0
  341. package/src/lib/components/primitives/context-menu/context-menu-content.svelte +1 -1
  342. package/src/lib/components/primitives/context-menu/context-menu-sub-content.svelte +1 -1
  343. package/src/lib/components/primitives/dialog/dialog-content.svelte +11 -3
  344. package/src/lib/components/primitives/dialog/dialog-overlay.svelte +1 -1
  345. package/src/lib/components/primitives/dialog/dialog-title.svelte +6 -2
  346. package/src/lib/components/primitives/drawer/Drawer.svelte +2 -2
  347. package/src/lib/components/primitives/dropdown-menu/dropdown-menu-checkbox-group.svelte +16 -0
  348. package/src/lib/components/primitives/dropdown-menu/dropdown-menu-checkbox-item.svelte +46 -0
  349. package/src/lib/components/primitives/dropdown-menu/dropdown-menu-content.svelte +31 -0
  350. package/src/lib/components/primitives/dropdown-menu/dropdown-menu-group-heading.svelte +22 -0
  351. package/src/lib/components/primitives/dropdown-menu/dropdown-menu-group.svelte +7 -0
  352. package/src/lib/components/primitives/dropdown-menu/dropdown-menu-item.svelte +27 -0
  353. package/src/lib/components/primitives/dropdown-menu/dropdown-menu-label.svelte +24 -0
  354. package/src/lib/components/primitives/dropdown-menu/dropdown-menu-portal.svelte +7 -0
  355. package/src/lib/components/primitives/dropdown-menu/dropdown-menu-radio-group.svelte +16 -0
  356. package/src/lib/components/primitives/dropdown-menu/dropdown-menu-radio-item.svelte +36 -0
  357. package/src/lib/components/primitives/dropdown-menu/dropdown-menu-separator.svelte +17 -0
  358. package/src/lib/components/primitives/dropdown-menu/dropdown-menu-shortcut.svelte +23 -0
  359. package/src/lib/components/primitives/dropdown-menu/dropdown-menu-sub-content.svelte +31 -0
  360. package/src/lib/components/primitives/dropdown-menu/dropdown-menu-sub-trigger.svelte +29 -0
  361. package/src/lib/components/primitives/dropdown-menu/dropdown-menu-sub.svelte +7 -0
  362. package/src/lib/components/primitives/dropdown-menu/dropdown-menu-trigger.svelte +7 -0
  363. package/src/lib/components/primitives/dropdown-menu/dropdown-menu.svelte +7 -0
  364. package/src/lib/components/primitives/dropdown-menu/index.ts +54 -0
  365. package/src/lib/components/primitives/{alert/alert-description.svelte → empty/empty-content.svelte} +3 -3
  366. package/src/lib/components/primitives/empty/empty-description.svelte +23 -0
  367. package/src/lib/components/primitives/{alert/alert-title.svelte → empty/empty-header.svelte} +3 -3
  368. package/src/lib/components/primitives/empty/empty-media.svelte +41 -0
  369. package/src/lib/components/primitives/{card/card-action.svelte → empty/empty-title.svelte} +2 -2
  370. package/src/lib/components/primitives/empty/empty.svelte +23 -0
  371. package/src/lib/components/primitives/empty/index.ts +22 -0
  372. package/src/lib/components/primitives/index.ts +10 -1
  373. package/src/lib/components/primitives/input/input.svelte +4 -4
  374. package/src/lib/components/primitives/input-group/index.ts +22 -0
  375. package/src/lib/components/primitives/input-group/input-group-addon.svelte +53 -0
  376. package/src/lib/components/primitives/input-group/input-group-button.svelte +49 -0
  377. package/src/lib/components/primitives/input-group/input-group-input.svelte +25 -0
  378. package/src/lib/components/primitives/input-group/input-group-text.svelte +22 -0
  379. package/src/lib/components/primitives/input-group/input-group-textarea.svelte +23 -0
  380. package/src/lib/components/primitives/input-group/input-group.svelte +24 -0
  381. package/src/lib/components/primitives/mode-toggle/mode-toggle.svelte +6 -7
  382. package/src/lib/components/primitives/popover/index.ts +28 -0
  383. package/src/lib/components/primitives/popover/popover-close.svelte +7 -0
  384. package/src/lib/components/primitives/popover/popover-content.svelte +31 -0
  385. package/src/lib/components/primitives/popover/popover-description.svelte +20 -0
  386. package/src/lib/components/primitives/popover/popover-header.svelte +20 -0
  387. package/src/lib/components/primitives/popover/popover-portal.svelte +7 -0
  388. package/src/lib/components/primitives/popover/popover-title.svelte +15 -0
  389. package/src/lib/components/primitives/popover/popover-trigger.svelte +17 -0
  390. package/src/lib/components/primitives/popover/popover.svelte +7 -0
  391. package/src/lib/components/primitives/resizable/resizable-handle.svelte +6 -2
  392. package/src/lib/components/primitives/resizable/resizable-pane-group.svelte +1 -4
  393. package/src/lib/components/primitives/scroll-area/scroll-area.svelte +1 -1
  394. package/src/lib/components/primitives/search/search.svelte +3 -3
  395. package/src/lib/components/primitives/select/select-content.svelte +1 -1
  396. package/src/lib/components/primitives/select/select-trigger.svelte +1 -1
  397. package/src/lib/components/primitives/severity.ts +26 -0
  398. package/src/lib/components/primitives/slider/slider.svelte +8 -3
  399. package/src/lib/components/primitives/sonner/sonner.svelte +1 -1
  400. package/src/lib/components/primitives/spinner/index.ts +1 -0
  401. package/src/lib/components/primitives/spinner/spinner.svelte +29 -0
  402. package/src/lib/components/primitives/switch/switch.svelte +2 -2
  403. package/src/lib/components/primitives/tabs/tabs-list.svelte +27 -5
  404. package/src/lib/components/primitives/tabs/tabs-trigger.svelte +23 -5
  405. package/src/lib/components/primitives/tabs/tabs.svelte +6 -2
  406. package/src/lib/components/primitives/textarea/textarea.svelte +1 -1
  407. package/src/lib/components/primitives/theme-switcher/ThemeSwitcher.svelte +1 -1
  408. package/src/lib/components/primitives/toggle/index.ts +13 -0
  409. package/src/lib/components/primitives/toggle/toggle.svelte +54 -0
  410. package/src/lib/components/primitives/toggle-group/index.ts +10 -0
  411. package/src/lib/components/primitives/toggle-group/toggle-group-item.svelte +35 -0
  412. package/src/lib/components/primitives/toggle-group/toggle-group.svelte +75 -0
  413. package/src/lib/components/viewer/MeshMetadataPanel.svelte +119 -0
  414. package/src/lib/components/viewer/SceneManager.svelte +14 -5
  415. package/src/lib/components/viewer/Viewer.svelte +243 -221
  416. package/src/lib/compute/run-panel-action.ts +16 -0
  417. package/src/lib/compute/solving.svelte.ts +66 -50
  418. package/src/lib/compute/useSolveSession.svelte.ts +3 -0
  419. package/src/lib/constants.ts +7 -9
  420. package/src/lib/contexts/hostContext.svelte.ts +51 -0
  421. package/src/lib/i18n/localeContext.svelte.ts +40 -5
  422. package/src/lib/i18n/messages.ts +453 -13
  423. package/src/lib/index.ts +21 -0
  424. package/src/lib/public.ts +1 -0
  425. package/src/lib/schema/host-support.ts +129 -0
  426. package/src/lib/schema/option-display.ts +44 -0
  427. package/src/lib/schema/param-exporter.ts +10 -7
  428. package/src/lib/schema/visibility-rules.ts +23 -0
  429. package/src/lib/styles/base.css +80 -10
  430. package/src/lib/types/actionButton.ts +16 -3
  431. package/src/lib/types/presetLabels.ts +13 -11
  432. package/src/lib/utils/file-download.ts +11 -21
  433. package/src/lib/utils/host-files.ts +61 -0
  434. package/src/lib/utils/loadScript.ts +3 -0
  435. package/src/lib/utils/webp-to-png.ts +48 -0
  436. package/dist/components/primitives/alert/alert.svelte +0 -44
  437. package/dist/components/primitives/alert/alert.svelte.d.ts +0 -26
  438. package/dist/components/primitives/alert/index.d.ts +0 -5
  439. package/dist/components/primitives/alert/index.js +0 -7
  440. package/dist/components/viewer/MeshMetadataDialog.svelte +0 -126
  441. package/dist/components/viewer/MeshMetadataDialog.svelte.d.ts +0 -10
  442. package/src/lib/components/primitives/alert/alert.svelte +0 -44
  443. package/src/lib/components/primitives/alert/index.ts +0 -14
  444. package/src/lib/components/viewer/MeshMetadataDialog.svelte +0 -126
@@ -3,21 +3,35 @@
3
3
  import { debounce } from '../../../utils/debounce';
4
4
  import { Input } from '../../primitives/input';
5
5
  import { Slider } from '../../primitives/slider';
6
+ import * as InputGroup from '../../primitives/input-group';
7
+ import { Separator } from '../../primitives/separator';
6
8
  import * as Field from '../../primitives/field';
9
+ import { getLocaleContext } from '../../../i18n/localeContext.svelte';
10
+ import { formatMessage } from '../../../i18n/messages';
7
11
 
8
12
  interface Props {
9
13
  inputId: string;
14
+ /** Id of the field's label, which also names the slider thumb. */
15
+ labelId?: string;
10
16
  value?: number;
11
17
  config?: NumberWidgetConfig;
12
18
  onChange: (value: SupportedTypes) => void;
13
19
  disabled?: boolean;
14
20
  }
15
21
 
16
- let { inputId, value = $bindable(), config, onChange, disabled = false }: Props = $props();
22
+ let {
23
+ inputId,
24
+ labelId,
25
+ value = $bindable(),
26
+ config,
27
+ onChange,
28
+ disabled = false
29
+ }: Props = $props();
30
+
31
+ const locale = getLocaleContext();
32
+ const t = $derived(locale.messages);
17
33
 
18
34
  let validationError = $state<string | null>(null);
19
- let sliderEditing = $state(false);
20
- let sliderInputValue = $state('');
21
35
 
22
36
  const min = $derived(config?.minimum ?? 0);
23
37
  const max = $derived(config?.maximum ?? 100);
@@ -29,9 +43,9 @@
29
43
 
30
44
  function validateNumber(val: number): string | null {
31
45
  if (config?.minimum !== undefined && val < config.minimum)
32
- return `Minimum value is ${config.minimum}`;
46
+ return formatMessage(t.minValue, { min: config.minimum });
33
47
  if (config?.maximum !== undefined && val > config.maximum)
34
- return `Maximum value is ${config.maximum}`;
48
+ return formatMessage(t.maxValue, { max: config.maximum });
35
49
  return null;
36
50
  }
37
51
 
@@ -44,77 +58,126 @@
44
58
  }
45
59
  }
46
60
 
47
- function handleSliderChange(newValue: number) {
61
+ // bits-ui builds an array of every step and rebuilds a tick object per step on each value
62
+ // change, so a fine-grained range freezes the drag. Past this many steps the track drives a
63
+ // coarse proxy scale instead; the number box next to it still sets any exact value.
64
+ const MAX_TRACK_STEPS = 1000;
65
+ const FINE_DRAG_FACTOR = 10;
66
+ const stepCount = $derived((max - min) / step);
67
+ const useProxyTrack = $derived(
68
+ step > 0 && Number.isFinite(stepCount) && stepCount > MAX_TRACK_STEPS
69
+ );
70
+ const trackMin = $derived(useProxyTrack ? 0 : min);
71
+ const trackMax = $derived(useProxyTrack ? MAX_TRACK_STEPS : max);
72
+ const stepPrecision = $derived((String(step).split('.')[1] ?? '').length);
73
+
74
+ let dragging = false;
75
+ let shiftHeld = false;
76
+ let lastTrack: number | null = null;
77
+ let fineAnchor: { track: number; value: number } | null = null;
78
+
79
+ function snapToStep(v: number): number {
80
+ const clamped = Math.min(max, Math.max(min, v));
81
+ if (!(step > 0)) return clamped;
82
+ const snapped = min + Math.round((clamped - min) / step) * step;
83
+ return Math.min(max, Number(snapped.toFixed(stepPrecision)));
84
+ }
85
+
86
+ function toTrack(v: number): number {
87
+ return useProxyTrack ? Math.round(((v - min) / (max - min)) * MAX_TRACK_STEPS) : v;
88
+ }
89
+
90
+ function trackSpanToValue(trackDelta: number): number {
91
+ return (trackDelta / (trackMax - trackMin)) * (max - min);
92
+ }
93
+
94
+ // bits-ui maps the pointer to an absolute track position, so fine drag works in deltas: the
95
+ // value moves FINE_DRAG_FACTOR times slower than the pointer from where Shift took effect.
96
+ function setFromTrack(track: number) {
97
+ if (max <= min) return;
98
+ let newValue: number;
99
+ if (dragging && shiftHeld) {
100
+ fineAnchor ??= { track: lastTrack ?? track, value: numValue };
101
+ newValue = snapToStep(
102
+ fineAnchor.value + trackSpanToValue(track - fineAnchor.track) / FINE_DRAG_FACTOR
103
+ );
104
+ } else {
105
+ fineAnchor = null;
106
+ newValue = snapToStep(min + trackSpanToValue(track - trackMin));
107
+ }
108
+ lastTrack = track;
48
109
  value = newValue;
49
110
  commitSliderDebounced(newValue);
50
111
  }
51
112
 
52
- function focusSliderInput(node: HTMLInputElement) {
53
- node.focus();
54
- node.select();
113
+ function startDrag(e: PointerEvent) {
114
+ dragging = true;
115
+ shiftHeld = e.shiftKey;
116
+ lastTrack = null;
117
+ fineAnchor = null;
55
118
  }
56
119
 
57
- function decimalPlaces(stepSize: number): number {
58
- return Math.max(0, -Math.floor(Math.log10(stepSize)));
120
+ function setShift(e: KeyboardEvent) {
121
+ if (e.key === 'Shift') shiftHeld = e.type === 'keydown';
122
+ }
123
+
124
+ const decimals = $derived(Math.max(0, -Math.floor(Math.log10(step))));
125
+
126
+ function commitTypedValue(input: HTMLInputElement) {
127
+ const parsed = parseFloat(input.value);
128
+ if (isNaN(parsed)) {
129
+ input.value = numValue.toFixed(decimals);
130
+ return;
131
+ }
132
+ const clamped = Math.min(max, Math.max(min, parsed));
133
+ input.value = clamped.toFixed(decimals);
134
+ if (clamped === value) return;
135
+ value = clamped;
136
+ onChange(clamped);
59
137
  }
60
138
  </script>
61
139
 
140
+ <svelte:window
141
+ onkeydown={setShift}
142
+ onkeyup={setShift}
143
+ onpointerup={() => (dragging = false)}
144
+ onblur={() => (shiftHeld = dragging = false)}
145
+ />
146
+
62
147
  {#if config?.renderAsSlider}
63
- {@const dp = decimalPlaces(step)}
64
- <div class="gap-4 flex items-center">
65
- <Slider
66
- type="single"
67
- value={numValue}
148
+ <!-- Value and track share one box, the height of a number input, so mixed rows line up and
149
+ a value can't be read as belonging to the neighbouring slider. -->
150
+ <InputGroup.Root>
151
+ <InputGroup.Input
152
+ id={inputId}
153
+ type="number"
154
+ class="w-18 flex-none"
155
+ value={numValue.toFixed(decimals)}
68
156
  {min}
69
157
  {max}
70
158
  {step}
71
- class="flex-1"
72
- onValueChange={handleSliderChange}
73
159
  {disabled}
160
+ onchange={(e) => commitTypedValue(e.currentTarget)}
161
+ onkeydown={(e) => {
162
+ if (e.key === 'Enter') e.currentTarget.blur();
163
+ }}
74
164
  />
75
- {#if sliderEditing}
76
- <input
77
- use:focusSliderInput
78
- type="number"
79
- {step}
80
- class="min-w-12 w-16 text-sm border-b border-border bg-transparent text-right outline-none focus:border-foreground"
81
- bind:value={sliderInputValue}
82
- onblur={() => {
83
- const parsed = parseFloat(sliderInputValue);
84
- if (!isNaN(parsed)) handleSliderChange(Math.min(max, Math.max(min, parsed)));
85
- sliderEditing = false;
86
- }}
87
- onkeydown={(e) => {
88
- if (e.key === 'Enter') {
89
- const parsed = parseFloat(sliderInputValue);
90
- if (!isNaN(parsed)) handleSliderChange(Math.min(max, Math.max(min, parsed)));
91
- sliderEditing = false;
92
- } else if (e.key === 'Escape') {
93
- sliderEditing = false;
94
- }
95
- }}
165
+ <Separator orientation="vertical" />
166
+ <div class="px-3.5 min-w-0 flex flex-1 items-center" onpointerdowncapture={startDrag}>
167
+ <!-- A function binding, not value + onValueChange: when a fine drag leaves the value
168
+ unchanged, the thumb must stay put instead of following the pointer. -->
169
+ <Slider
170
+ type="single"
171
+ bind:value={() => toTrack(numValue), setFromTrack}
172
+ min={trackMin}
173
+ max={trackMax}
174
+ step={useProxyTrack ? 1 : step}
175
+ title={t.fineDragHint}
176
+ thumbLabelledby={labelId}
177
+ {disabled}
96
178
  />
97
- {:else}
98
- <span
99
- role="button"
100
- tabindex={0}
101
- class="min-w-12 text-sm cursor-text text-right text-muted-foreground select-none"
102
- title="Double-click to edit"
103
- ondblclick={() => {
104
- sliderInputValue = numValue.toFixed(dp);
105
- sliderEditing = true;
106
- }}
107
- onkeydown={(e) => {
108
- if (e.key === 'Enter' || e.key === ' ') {
109
- sliderInputValue = numValue.toFixed(dp);
110
- sliderEditing = true;
111
- }
112
- }}
113
- >
114
- {numValue.toFixed(dp)}
115
- </span>
116
- {/if}
117
- </div>
179
+ </div>
180
+ </InputGroup.Root>
118
181
  {:else}
119
182
  <Input
120
183
  id={inputId}
@@ -126,7 +189,6 @@
126
189
  placeholder={config?.placeholder}
127
190
  data-invalid={validationError ? true : undefined}
128
191
  aria-invalid={validationError ? true : undefined}
129
- class={validationError ? 'border-destructive' : ''}
130
192
  {disabled}
131
193
  oninput={() => (validationError = null)}
132
194
  onchange={(e) => {
@@ -1,6 +1,8 @@
1
1
  import type { NumberWidgetConfig, SupportedTypes } from '@selvajs/schemas';
2
2
  interface Props {
3
3
  inputId: string;
4
+ /** Id of the field's label, which also names the slider thumb. */
5
+ labelId?: string;
4
6
  value?: number;
5
7
  config?: NumberWidgetConfig;
6
8
  onChange: (value: SupportedTypes) => void;
@@ -0,0 +1,29 @@
1
+ <script lang="ts">
2
+ import type { GlyphSource } from '../../../schema/option-display';
3
+ import { cn } from '../../../utils.js';
4
+
5
+ interface Props {
6
+ glyph: GlyphSource;
7
+ class?: string;
8
+ }
9
+
10
+ let { glyph, class: className }: Props = $props();
11
+ </script>
12
+
13
+ {#if glyph.kind === 'icon'}
14
+ <!-- Lucide's stroke defaults; the path is bound as an attribute, never parsed as markup. -->
15
+ <svg
16
+ viewBox="0 0 24 24"
17
+ fill="none"
18
+ stroke="currentColor"
19
+ stroke-width="2"
20
+ stroke-linecap="round"
21
+ stroke-linejoin="round"
22
+ aria-hidden="true"
23
+ class={cn('size-4 shrink-0', className)}
24
+ >
25
+ <path d={glyph.d} />
26
+ </svg>
27
+ {:else}
28
+ <img src={glyph.src} alt="" class={cn('size-4 shrink-0 rounded-sm object-cover', className)} />
29
+ {/if}
@@ -0,0 +1,8 @@
1
+ import type { GlyphSource } from '../../../schema/option-display';
2
+ interface Props {
3
+ glyph: GlyphSource;
4
+ class?: string;
5
+ }
6
+ declare const OptionGlyph: import("svelte").Component<Props, {}, "">;
7
+ type OptionGlyph = ReturnType<typeof OptionGlyph>;
8
+ export default OptionGlyph;
@@ -0,0 +1,44 @@
1
+ <script lang="ts">
2
+ import type { DropdownWidgetConfig, SupportedTypes, UISchema } from '@selvajs/schemas';
3
+ import * as ToggleGroup from '../../primitives/toggle-group';
4
+ import { optionGlyph } from '../../../schema/option-display';
5
+ import OptionGlyph from './OptionGlyph.svelte';
6
+
7
+ interface Props {
8
+ labelId: string;
9
+ value?: string;
10
+ config: DropdownWidgetConfig;
11
+ assets?: UISchema['assets'];
12
+ onChange: (value: SupportedTypes) => void;
13
+ disabled?: boolean;
14
+ }
15
+
16
+ let { labelId, value, config, assets, onChange, disabled = false }: Props = $props();
17
+
18
+ const options = $derived(Object.entries(config.options ?? {}));
19
+ const hasIcons = $derived(
20
+ options.some(([name]) => optionGlyph(config.optionMedia?.[name], assets))
21
+ );
22
+ </script>
23
+
24
+ <ToggleGroup.Root
25
+ type="single"
26
+ variant="outline"
27
+ size={hasIcons ? 'stacked' : 'default'}
28
+ class="w-full"
29
+ aria-labelledby={labelId}
30
+ value={value ?? ''}
31
+ onValueChange={(next) => {
32
+ // A single-select group emits '' when the active item is clicked again; keep the selection.
33
+ if (next) onChange(next);
34
+ }}
35
+ {disabled}
36
+ >
37
+ {#each options as [name, expr] (name)}
38
+ {@const glyph = optionGlyph(config.optionMedia?.[name], assets)}
39
+ <ToggleGroup.Item value={expr ?? name} class="min-w-0 flex-1" title={name}>
40
+ {#if glyph}<OptionGlyph {glyph} />{/if}
41
+ <span class="max-w-full truncate">{name}</span>
42
+ </ToggleGroup.Item>
43
+ {/each}
44
+ </ToggleGroup.Root>
@@ -0,0 +1,12 @@
1
+ import type { DropdownWidgetConfig, SupportedTypes, UISchema } from '@selvajs/schemas';
2
+ interface Props {
3
+ labelId: string;
4
+ value?: string;
5
+ config: DropdownWidgetConfig;
6
+ assets?: UISchema['assets'];
7
+ onChange: (value: SupportedTypes) => void;
8
+ disabled?: boolean;
9
+ }
10
+ declare const SegmentedInput: import("svelte").Component<Props, {}, "">;
11
+ type SegmentedInput = ReturnType<typeof SegmentedInput>;
12
+ export default SegmentedInput;
@@ -3,6 +3,8 @@
3
3
  import { debounce } from '../../../utils/debounce';
4
4
  import { Input } from '../../primitives/input';
5
5
  import * as Field from '../../primitives/field';
6
+ import { getLocaleContext } from '../../../i18n/localeContext.svelte';
7
+ import { formatMessage } from '../../../i18n/messages';
6
8
 
7
9
  interface Props {
8
10
  inputId: string;
@@ -14,6 +16,9 @@
14
16
 
15
17
  let { inputId, value = $bindable(), config, onChange, disabled = false }: Props = $props();
16
18
 
19
+ const locale = getLocaleContext();
20
+ const t = $derived(locale.messages);
21
+
17
22
  let validationError = $state<string | null>(null);
18
23
  let currentValue = $state(value || '');
19
24
 
@@ -21,13 +26,13 @@
21
26
 
22
27
  function validateText(val: string): string | null {
23
28
  if (config?.maxLength && val.length > config.maxLength)
24
- return `Maximum ${config.maxLength} characters allowed`;
29
+ return formatMessage(t.maxLength, { max: config.maxLength });
25
30
  if (config?.pattern) {
26
31
  try {
27
32
  if (!new RegExp(config.pattern).test(val))
28
- return config.customErrorMessage || 'Invalid format';
33
+ return config.customErrorMessage || t.invalidFormat;
29
34
  } catch {
30
- return 'Invalid validation pattern configured';
35
+ return t.invalidPattern;
31
36
  }
32
37
  }
33
38
  return null;
@@ -51,7 +56,6 @@
51
56
  maxlength={config?.maxLength}
52
57
  data-invalid={validationError ? true : undefined}
53
58
  aria-invalid={validationError ? true : undefined}
54
- class={validationError ? 'border-destructive' : ''}
55
59
  {disabled}
56
60
  oninput={() => {
57
61
  validationError = null;
@@ -0,0 +1,80 @@
1
+ <script lang="ts">
2
+ import type { DropdownWidgetConfig, SupportedTypes, UISchema } from '@selvajs/schemas';
3
+ import { optionGlyph } from '../../../schema/option-display';
4
+ import OptionGlyph from './OptionGlyph.svelte';
5
+
6
+ interface Props {
7
+ labelId: string;
8
+ value?: string;
9
+ config: DropdownWidgetConfig;
10
+ assets?: UISchema['assets'];
11
+ onChange: (value: SupportedTypes) => void;
12
+ disabled?: boolean;
13
+ }
14
+
15
+ let { labelId, value, config, assets, onChange, disabled = false }: Props = $props();
16
+
17
+ const options = $derived(
18
+ Object.entries(config.options ?? {}).map(([name, expr]) => ({ name, value: expr ?? name }))
19
+ );
20
+ // With nothing selected the first tile takes focus, so the group is still reachable by Tab.
21
+ const focusIndex = $derived(
22
+ Math.max(
23
+ 0,
24
+ options.findIndex((o) => o.value === value)
25
+ )
26
+ );
27
+
28
+ let tiles: HTMLButtonElement[] = $state([]);
29
+
30
+ function onKeydown(event: KeyboardEvent, index: number) {
31
+ const step = { ArrowRight: 1, ArrowDown: 1, ArrowLeft: -1, ArrowUp: -1 }[event.key];
32
+ if (!step) return;
33
+ event.preventDefault();
34
+ const next = (index + step + options.length) % options.length;
35
+ onChange(options[next].value);
36
+ tiles[next]?.focus();
37
+ }
38
+ </script>
39
+
40
+ <div role="radiogroup" aria-labelledby={labelId} class="gap-2 tile-grid grid">
41
+ {#each options as option, index (option.name)}
42
+ {@const glyph = optionGlyph(config.optionMedia?.[option.name], assets)}
43
+ {@const selected = option.value === value}
44
+ <button
45
+ bind:this={tiles[index]}
46
+ type="button"
47
+ role="radio"
48
+ aria-checked={selected}
49
+ tabindex={index === focusIndex ? 0 : -1}
50
+ {disabled}
51
+ onclick={() => onChange(option.value)}
52
+ onkeydown={(e) => onKeydown(e, index)}
53
+ class="gap-1.5 p-1.5 min-w-0 flex flex-col rounded-lg border text-left transition-colors outline-none focus-visible:ring-2 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50 {selected
54
+ ? 'border-primary bg-primary/5 ring-1 ring-primary'
55
+ : 'border-input hover:bg-accent/40'}"
56
+ >
57
+ <span
58
+ class="flex aspect-square w-full items-center justify-center overflow-hidden rounded-md bg-muted text-muted-foreground"
59
+ >
60
+ {#if glyph?.kind === 'image'}
61
+ <OptionGlyph {glyph} class="size-full" />
62
+ {:else if glyph}
63
+ <OptionGlyph {glyph} class="size-7" />
64
+ {:else}
65
+ <span class="text-lg font-medium" aria-hidden="true">{option.name.charAt(0)}</span>
66
+ {/if}
67
+ </span>
68
+ <span class="px-0.5 text-xs leading-tight truncate" class:font-medium={selected}>
69
+ {option.name}
70
+ </span>
71
+ </button>
72
+ {/each}
73
+ </div>
74
+
75
+ <style>
76
+ /* Two or three tiles a row as the panel narrows; a fixed count shrinks them to unreadable. */
77
+ .tile-grid {
78
+ grid-template-columns: repeat(auto-fill, minmax(5.5rem, 1fr));
79
+ }
80
+ </style>
@@ -0,0 +1,12 @@
1
+ import type { DropdownWidgetConfig, SupportedTypes, UISchema } from '@selvajs/schemas';
2
+ interface Props {
3
+ labelId: string;
4
+ value?: string;
5
+ config: DropdownWidgetConfig;
6
+ assets?: UISchema['assets'];
7
+ onChange: (value: SupportedTypes) => void;
8
+ disabled?: boolean;
9
+ }
10
+ declare const TileInput: import("svelte").Component<Props, {}, "">;
11
+ type TileInput = ReturnType<typeof TileInput>;
12
+ export default TileInput;
@@ -3,5 +3,8 @@ export { default as ChecklistInput } from './ChecklistInput.svelte';
3
3
  export { default as ColorInput } from './ColorInput.svelte';
4
4
  export { default as DropdownInput } from './DropdownInput.svelte';
5
5
  export { default as FileInput } from './FileInput.svelte';
6
+ export { default as GeometryInput } from './GeometryInput.svelte';
6
7
  export { default as NumberInput } from './NumberInput.svelte';
8
+ export { default as SegmentedInput } from './SegmentedInput.svelte';
7
9
  export { default as TextInput } from './TextInput.svelte';
10
+ export { default as TileInput } from './TileInput.svelte';
@@ -3,5 +3,8 @@ export { default as ChecklistInput } from './ChecklistInput.svelte';
3
3
  export { default as ColorInput } from './ColorInput.svelte';
4
4
  export { default as DropdownInput } from './DropdownInput.svelte';
5
5
  export { default as FileInput } from './FileInput.svelte';
6
+ export { default as GeometryInput } from './GeometryInput.svelte';
6
7
  export { default as NumberInput } from './NumberInput.svelte';
8
+ export { default as SegmentedInput } from './SegmentedInput.svelte';
7
9
  export { default as TextInput } from './TextInput.svelte';
10
+ export { default as TileInput } from './TileInput.svelte';
@@ -1,4 +1,5 @@
1
1
  <script lang="ts">
2
+ import { untrack, type Snippet } from 'svelte';
2
3
  import { Button } from './button';
3
4
  import { Zap, Check, Loader, Play } from '@lucide/svelte';
4
5
  import { getLocaleContext } from '../../i18n/localeContext.svelte';
@@ -11,34 +12,65 @@
11
12
  hasNeverSolved?: boolean;
12
13
  isSolving: boolean;
13
14
  oncalculate: () => void;
15
+ /** Beside the button, sharing its row: the panel footer's actions menu. */
16
+ trailing?: Snippet;
14
17
  }
15
18
 
16
- let { hasPendingChanges, hasNeverSolved = false, isSolving, oncalculate }: Props = $props();
19
+ let {
20
+ hasPendingChanges,
21
+ hasNeverSolved = false,
22
+ isSolving,
23
+ oncalculate,
24
+ trailing
25
+ }: Props = $props();
26
+
27
+ // The label below changes too, but a screen reader doesn't read a label change on a button
28
+ // that has lost focus, so start and end of a solve go through a live region as well.
29
+ let announcement = $state('');
30
+ let wasSolving = false;
31
+ $effect(() => {
32
+ const solving = isSolving;
33
+ untrack(() => {
34
+ if (solving) announcement = t.solvingEllipsis;
35
+ else if (wasSolving) announcement = hasPendingChanges ? '' : t.upToDate;
36
+ wasSolving = solving;
37
+ });
38
+ });
17
39
  </script>
18
40
 
19
41
  <div class="bottom-0 mt-3 pb-3 pt-2 backdrop-blur-sm px-2 sticky border-t border-border/50">
20
- <Button
21
- variant={hasPendingChanges ? 'default' : 'ghost'}
22
- size="lg"
23
- onclick={() => !isSolving && oncalculate()}
24
- disabled={!hasPendingChanges && !isSolving}
25
- aria-busy={isSolving}
26
- class="gap-2 font-medium w-full transition-all duration-200
27
- {hasPendingChanges && !isSolving ? 'selva-pending-pulse shadow-md' : ''}
42
+ <span class="sr-only" role="status" aria-live="polite">{announcement}</span>
43
+ <div class="gap-2 flex">
44
+ <Button
45
+ variant={hasPendingChanges ? 'default' : 'ghost'}
46
+ size="lg"
47
+ onclick={() => !isSolving && oncalculate()}
48
+ disabled={!hasPendingChanges && !isSolving}
49
+ aria-busy={isSolving}
50
+ class="gap-2 font-medium min-w-0 flex-1 transition-all duration-200
51
+ {hasPendingChanges && !isSolving ? 'shadow-md' : ''}
28
52
  {!hasPendingChanges && !isSolving ? 'text-muted-foreground' : ''}"
29
- >
30
- {#if isSolving}
31
- <Loader class="h-4 w-4 animate-spin" />
32
- {t.solvingEllipsis}
33
- {:else if hasNeverSolved}
34
- <Play class="h-4 w-4" />
35
- {t.pressToCalculate}
36
- {:else if hasPendingChanges}
37
- <Zap class="h-4 w-4" />
38
- {t.calculate}
39
- {:else}
40
- <Check class="h-4 w-4" />
41
- {t.upToDate}
42
- {/if}
43
- </Button>
53
+ >
54
+ {#if isSolving}
55
+ <Loader class="h-4 w-4 animate-spin" />
56
+ {t.solvingEllipsis}
57
+ <kbd
58
+ class="px-1 font-sans rounded border border-current/30 text-2xs opacity-70"
59
+ title={t.solveMessagesEscHint}
60
+ >
61
+ Esc
62
+ </kbd>
63
+ {:else if hasNeverSolved}
64
+ <Play class="h-4 w-4" />
65
+ {t.pressToCalculate}
66
+ {:else if hasPendingChanges}
67
+ <Zap class="h-4 w-4" />
68
+ {t.calculate}
69
+ {:else}
70
+ <Check class="h-4 w-4" />
71
+ {t.upToDate}
72
+ {/if}
73
+ </Button>
74
+ {@render trailing?.()}
75
+ </div>
44
76
  </div>
@@ -1,8 +1,11 @@
1
+ import { type Snippet } from 'svelte';
1
2
  interface Props {
2
3
  hasPendingChanges: boolean;
3
4
  hasNeverSolved?: boolean;
4
5
  isSolving: boolean;
5
6
  oncalculate: () => void;
7
+ /** Beside the button, sharing its row: the panel footer's actions menu. */
8
+ trailing?: Snippet;
6
9
  }
7
10
  declare const CalculateButton: import("svelte").Component<Props, {}, "">;
8
11
  type CalculateButton = ReturnType<typeof CalculateButton>;
@@ -1,7 +1,7 @@
1
1
  <script lang="ts" module>
2
2
  import { type VariantProps, tv } from 'tailwind-variants';
3
- import { Info, TriangleAlert, CircleCheck, CircleX, Lightbulb } from '@lucide/svelte';
4
3
  import type { Component } from 'svelte';
4
+ import { SEVERITY_ICON, SEVERITY_TEXT, type Severity } from './severity';
5
5
 
6
6
  export const calloutVariants = tv({
7
7
  base: 'flex items-start gap-2.5 rounded-lg border px-3.5 py-3 text-sm',
@@ -19,20 +19,12 @@
19
19
 
20
20
  export type CalloutTone = NonNullable<VariantProps<typeof calloutVariants>['tone']>;
21
21
 
22
- const TONE_ICON: Record<CalloutTone, Component> = {
23
- info: Info,
24
- tip: Lightbulb,
25
- success: CircleCheck,
26
- warning: TriangleAlert,
27
- danger: CircleX
28
- };
29
-
30
- const TONE_ACCENT: Record<CalloutTone, string> = {
31
- info: 'text-info',
32
- tip: 'text-muted-foreground',
33
- success: 'text-success',
34
- warning: 'text-warning',
35
- danger: 'text-destructive'
22
+ const TONE_SEVERITY: Record<CalloutTone, Severity> = {
23
+ info: 'info',
24
+ tip: 'note',
25
+ success: 'success',
26
+ warning: 'warning',
27
+ danger: 'error'
36
28
  };
37
29
  </script>
38
30
 
@@ -51,7 +43,8 @@
51
43
 
52
44
  let { tone = 'info', title, icon, class: className, children, ...restProps }: Props = $props();
53
45
 
54
- const Icon = $derived(icon === undefined ? TONE_ICON[tone] : icon);
46
+ const Icon = $derived(icon === undefined ? SEVERITY_ICON[TONE_SEVERITY[tone]] : icon);
47
+ const accent = $derived(SEVERITY_TEXT[TONE_SEVERITY[tone]]);
55
48
  </script>
56
49
 
57
50
  <div
@@ -60,11 +53,11 @@
60
53
  {...restProps}
61
54
  >
62
55
  {#if Icon}
63
- <Icon class={cn('mt-0.5 h-4 w-4 shrink-0', TONE_ACCENT[tone])} />
56
+ <Icon class={cn('mt-0.5 h-4 w-4 shrink-0', accent)} />
64
57
  {/if}
65
58
  <div class="min-w-0 space-y-1">
66
59
  {#if title}
67
- <p class={cn('leading-tight font-medium', TONE_ACCENT[tone])}>{title}</p>
60
+ <p class={cn('leading-tight font-medium', accent)}>{title}</p>
68
61
  {/if}
69
62
  <div class="leading-relaxed text-muted-foreground [&_a]:underline [&_strong]:text-foreground">
70
63
  {@render children()}