@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,8 +1,11 @@
1
1
  <script lang="ts">
2
2
  import type { OutputChartLayoutItem } from '@selvajs/schemas';
3
- import { onMount } from 'svelte';
3
+ import { onMount, tick } from 'svelte';
4
+ import { mode } from 'mode-watcher';
4
5
  import { Loader, Maximize, Minimize } from '@lucide/svelte';
5
6
  import { loadScript } from '$lib/utils/loadScript';
7
+ import { getLocaleContext } from '$lib/i18n/localeContext.svelte';
8
+ import { formatMessage } from '$lib/i18n/messages';
6
9
 
7
10
  interface Props {
8
11
  item: OutputChartLayoutItem;
@@ -11,6 +14,9 @@
11
14
 
12
15
  let { item: _item, value }: Props = $props();
13
16
 
17
+ const locale = getLocaleContext();
18
+ const t = $derived(locale.messages);
19
+
14
20
  const MAP_TYPE_SET = new Set(['scattermap', 'scattermapbox', 'choropleth', 'scattergeo']);
15
21
 
16
22
  type PlotlyTrace = Record<string, unknown>;
@@ -40,20 +46,40 @@
40
46
  // @ts-expect-error — Plotly is loaded dynamically onto window
41
47
  if (window.Plotly) return window.Plotly;
42
48
 
43
- await loadScript('https://cdn.plot.ly/plotly-3.4.0.min.js', { crossOrigin: 'anonymous' });
49
+ // Pinned by hash: the plugin's web UI runs this on the origin that holds its bridge secret.
50
+ await loadScript('https://cdn.plot.ly/plotly-3.4.0.min.js', {
51
+ crossOrigin: 'anonymous',
52
+ integrity: 'sha384-pFOQ7loGBChmUyS4Tszy+he8OWeYkwTFjc2xii4aJUWWiGwf2u2OEc04T5iDRpMp'
53
+ });
44
54
  // @ts-expect-error — Plotly is loaded dynamically onto window
45
55
  return window.Plotly;
46
56
  }
47
57
 
58
+ // Some embedded WebViews (WKWebView in the Rhino panel) ship without the Fullscreen API at all.
59
+ const fullscreenSupported = typeof document !== 'undefined' && !!document.fullscreenEnabled;
60
+
61
+ // `Plots.resize()`/`relayout({autosize: true})` ask Plotly to re-measure the container itself,
62
+ // which it silently fails to do across a Fullscreen transition — _fullLayout keeps the
63
+ // pre-toggle width/height even though clientWidth/clientHeight are already correct. Passing
64
+ // the measured size explicitly is the only call that actually takes.
65
+ function resizeChart() {
66
+ // @ts-expect-error — Plotly is loaded dynamically onto window
67
+ if (!containerEl || !window.Plotly) return;
68
+ const { width, height } = containerEl.getBoundingClientRect();
69
+ if (width === 0 || height === 0) return;
70
+ // @ts-expect-error — Plotly is loaded dynamically onto window
71
+ window.Plotly.relayout(containerEl, { width, height });
72
+ }
73
+
48
74
  function toggleFullscreen() {
49
75
  if (!wrapperEl) return;
50
76
  if (!document.fullscreenElement) {
51
77
  wrapperEl.requestFullscreen().catch((err) => {
52
- error = `Fullscreen unavailable: ${err.message}`;
78
+ error = formatMessage(t.fullscreenUnavailable, { error: err.message });
53
79
  });
54
80
  } else {
55
81
  document.exitFullscreen().catch((err) => {
56
- error = `Exit fullscreen failed: ${err.message}`;
82
+ error = formatMessage(t.exitFullscreenFailed, { error: err.message });
57
83
  });
58
84
  }
59
85
  }
@@ -61,26 +87,41 @@
61
87
  $effect(() => {
62
88
  function onFullscreenChange() {
63
89
  isFullscreen = !!document.fullscreenElement;
64
- Promise.resolve().then(() => {
65
- // @ts-expect-error — Plotly is loaded dynamically onto window
66
- if (containerEl && window.Plotly) {
67
- // @ts-expect-error — Plotly is loaded dynamically onto window
68
- window.Plotly.Plots.resize(containerEl);
69
- }
70
- });
90
+ // `tick()` waits for the h-dvh/h-95 class swap this state drives to actually reach the
91
+ // DOM before resizeChart measures it.
92
+ tick().then(resizeChart);
71
93
  }
72
94
  document.addEventListener('fullscreenchange', onFullscreenChange);
73
95
  return () => document.removeEventListener('fullscreenchange', onFullscreenChange);
74
96
  });
75
97
 
98
+ // Chromium's getComputedStyle returns color values in whatever function the CSS used to
99
+ // declare them — oklch() here, since base.css's theme tokens are oklch(). Plotly's own color
100
+ // parser doesn't recognize oklch() and silently falls back to its #444 default instead of
101
+ // erroring, so every chart read dark axis text even in dark mode. `fillStyle` alone just
102
+ // echoes the oklch() string back unconverted; actually rasterizing a pixel and reading its
103
+ // bytes is what forces a real rgb() value Plotly can parse.
104
+ function toRgb(cssColor: string): string {
105
+ const canvas = document.createElement('canvas');
106
+ canvas.width = 1;
107
+ canvas.height = 1;
108
+ const ctx = canvas.getContext('2d');
109
+ if (!ctx) return cssColor;
110
+ ctx.fillStyle = cssColor;
111
+ ctx.fillRect(0, 0, 1, 1);
112
+ const [r, g, b, a] = ctx.getImageData(0, 0, 1, 1).data;
113
+ return a === 255 ? `rgb(${r}, ${g}, ${b})` : `rgba(${r}, ${g}, ${b}, ${(a / 255).toFixed(3)})`;
114
+ }
115
+
76
116
  function getThemeColors(): { textColor: string; gridColor: string } {
77
117
  if (!containerEl) return { textColor: '#333', gridColor: '#eee' };
78
118
  const style = getComputedStyle(containerEl);
79
- const textColor = style.getPropertyValue('color').trim() || '#333';
80
- const gridColor =
119
+ const textColor = toRgb(style.getPropertyValue('color').trim() || '#333');
120
+ const gridColor = toRgb(
81
121
  style.getPropertyValue('--border')?.trim() ||
82
- style.getPropertyValue('--color-border')?.trim() ||
83
- 'rgba(128,128,128,0.2)';
122
+ style.getPropertyValue('--color-border')?.trim() ||
123
+ 'rgba(128,128,128,0.2)'
124
+ );
84
125
  return { textColor, gridColor };
85
126
  }
86
127
 
@@ -113,11 +154,15 @@
113
154
  font: { color: textColor },
114
155
  paper_bgcolor: layoutRest.paper_bgcolor ?? 'transparent',
115
156
  plot_bgcolor: layoutRest.plot_bgcolor ?? 'transparent',
116
- ...(!isMapFigure && layoutRest.xaxis
117
- ? { xaxis: { ...(layoutRest.xaxis as object), gridcolor: gridColor, color: textColor } }
118
- : {}),
119
- ...(!isMapFigure && layoutRest.yaxis
120
- ? { yaxis: { ...(layoutRest.yaxis as object), gridcolor: gridColor, color: textColor } }
157
+ // Plotly's axis tick/label color doesn't inherit the top-level `font.color`, so this
158
+ // has to be set even when the figure's own JSON never declared an xaxis/yaxis —
159
+ // which the mock's figures don't. Gating on `layoutRest.xaxis` existing left every
160
+ // axis on Plotly's built-in #444 default, light or dark mode.
161
+ ...(!isMapFigure
162
+ ? {
163
+ xaxis: { ...(layoutRest.xaxis as object), gridcolor: gridColor, color: textColor },
164
+ yaxis: { ...(layoutRest.yaxis as object), gridcolor: gridColor, color: textColor }
165
+ }
121
166
  : {})
122
167
  };
123
168
 
@@ -129,7 +174,7 @@
129
174
  ...figData.config
130
175
  });
131
176
  } catch (e) {
132
- error = e instanceof Error ? e.message : 'Failed to render chart';
177
+ error = e instanceof Error ? e.message : t.chartRenderFailed;
133
178
  } finally {
134
179
  loading = false;
135
180
  }
@@ -142,11 +187,7 @@
142
187
  const ro = new ResizeObserver(() => {
143
188
  if (resizeTimer) clearTimeout(resizeTimer);
144
189
  resizeTimer = setTimeout(() => {
145
- // @ts-expect-error — Plotly is loaded dynamically onto window
146
- if (containerEl && window.Plotly) {
147
- // @ts-expect-error — Plotly is loaded dynamically onto window
148
- window.Plotly.Plots.resize(containerEl);
149
- }
190
+ resizeChart();
150
191
  resizeTimer = null;
151
192
  }, 150);
152
193
  });
@@ -163,6 +204,10 @@
163
204
  let renderTimeout: ReturnType<typeof setTimeout> | null = null;
164
205
 
165
206
  $effect(() => {
207
+ // Re-reads mode.current so a theme toggle re-renders with the new axis/font colors —
208
+ // getThemeColors() only reads the DOM once, at render time, and nothing else repaints an
209
+ // already-drawn chart when the page's color scheme changes under it.
210
+ void mode.current;
166
211
  if (!value || !mounted || !containerEl) return;
167
212
  if (renderTimeout) clearTimeout(renderTimeout);
168
213
  renderTimeout = setTimeout(() => {
@@ -177,25 +222,20 @@
177
222
 
178
223
  <div
179
224
  bind:this={wrapperEl}
180
- class="group rounded relative overflow-hidden border border-border {isFullscreen
225
+ class="group relative overflow-hidden rounded-lg border border-border {isFullscreen
181
226
  ? 'bg-background'
182
227
  : ''}"
183
228
  >
184
229
  {#if error}
185
230
  <div class="px-4 py-3 text-sm text-destructive">{error}</div>
186
- {:else if !figData && value}
187
- <div class="px-4 py-8 text-sm text-center text-muted-foreground">Receiving chart data...</div>
188
231
  {:else if !figData}
189
- <div class="px-4 py-8 text-sm text-center text-muted-foreground">Waiting for chart data...</div>
232
+ <!-- The layout hides this output while it has no data, so this is data that doesn't parse yet. -->
233
+ <div class="px-4 py-8 text-sm text-center text-muted-foreground">{t.chartReceiving}</div>
190
234
  {:else}
191
- <div
192
- bind:this={containerEl}
193
- class="w-full"
194
- style="height: {isFullscreen ? '100vh' : '380px'};"
195
- ></div>
235
+ <div bind:this={containerEl} class="w-full {isFullscreen ? 'h-dvh' : 'h-95'}"></div>
196
236
 
197
237
  <div
198
- class="gap-1 left-2 top-2 absolute z-10 flex items-center opacity-0 transition-opacity group-hover:opacity-100 focus-within:opacity-100 {isFullscreen
238
+ class="gap-1 left-2 top-2 absolute z-10 flex items-center opacity-0 transition-opacity group-hover:opacity-100 focus-within:opacity-100 pointer-coarse:opacity-100 {isFullscreen
199
239
  ? 'opacity-100'
200
240
  : ''}"
201
241
  >
@@ -207,18 +247,21 @@
207
247
  </div>
208
248
  {/if}
209
249
 
210
- <button
211
- onclick={toggleFullscreen}
212
- disabled={loading}
213
- title={isFullscreen ? 'Exit fullscreen' : 'Fullscreen'}
214
- class="rounded p-1.5 backdrop-blur-sm flex items-center border border-border bg-background/80 text-foreground transition-colors hover:bg-background disabled:cursor-not-allowed disabled:opacity-50"
215
- >
216
- {#if isFullscreen}
217
- <Minimize size={14} />
218
- {:else}
219
- <Maximize size={14} />
220
- {/if}
221
- </button>
250
+ {#if fullscreenSupported}
251
+ <button
252
+ onclick={toggleFullscreen}
253
+ disabled={loading}
254
+ title={isFullscreen ? t.exitFullscreen : t.fullscreen}
255
+ aria-label={isFullscreen ? t.exitFullscreen : t.fullscreen}
256
+ class="rounded p-1.5 backdrop-blur-sm flex items-center border border-border bg-background/80 text-foreground transition-colors hover:bg-background disabled:cursor-not-allowed disabled:opacity-50"
257
+ >
258
+ {#if isFullscreen}
259
+ <Minimize size={14} />
260
+ {:else}
261
+ <Maximize size={14} />
262
+ {/if}
263
+ </button>
264
+ {/if}
222
265
  </div>
223
266
  {/if}
224
267
  </div>
@@ -1,7 +1,6 @@
1
1
  <script lang="ts">
2
2
  import type { LayoutItem, InputLayoutItem, OutputLayoutItem } from '@selvajs/schemas';
3
3
  import type { Snippet } from 'svelte';
4
- import * as Card from '$lib/components/primitives/card';
5
4
  import { ChevronDown } from '@lucide/svelte';
6
5
  import { buildVisibilityMap, itemKey } from '$lib/schema/visibility-rules';
7
6
 
@@ -20,7 +19,7 @@
20
19
  ]
21
20
  >;
22
21
  outputSnippet: Snippet<[layoutItem: OutputLayoutItem]>;
23
- /** When true, renders items flat without the Card wrapper, header, or collapse toggle. */
22
+ /** When true, renders items without the header or collapse toggle. */
24
23
  flat?: boolean;
25
24
  }
26
25
 
@@ -37,110 +36,99 @@
37
36
  flat = false
38
37
  }: Props = $props();
39
38
 
40
- function handleKeydown(e: KeyboardEvent) {
41
- if (e.key === 'Enter' || e.key === ' ') {
42
- e.preventDefault();
43
- onToggle();
44
- }
45
- }
46
-
47
- // One visibility evaluation per item per render; columnStarts and gridItem both read it.
48
39
  const visibilityMap = $derived(buildVisibilityMap(items, values));
49
40
 
50
- // Hidden items must not consume a slot here, because gridItem skips them entirely —
51
- // counting them would offset every following item's column.
52
- const columnStarts = $derived.by(() => {
53
- const positions: number[] = [];
54
- let col = 0;
55
- for (const item of items) {
56
- if (item.type === 'linebreak') {
57
- positions.push(0);
58
- col = 0;
59
- continue;
60
- }
61
- const visibility = visibilityMap[itemKey(item)];
62
- if (!visibility.visible) {
63
- positions.push(0);
64
- continue;
65
- }
66
- const span = Math.min(Math.max(1, item.span ?? 1), columns);
67
- if (col + span > columns) col = 0;
68
- positions.push(col);
69
- col = (col + span) % columns;
70
- }
71
- return positions;
72
- });
41
+ const uid = $props.id();
42
+ const descriptionId = `${uid}-description`;
43
+
44
+ // Below this a label and its control stop fitting side by side, so a wide group
45
+ // sheds columns as its panel narrows instead of squeezing every input.
46
+ const MIN_COLUMN_WIDTH = 160;
47
+ const COLUMN_GAP = 16;
48
+
49
+ let gridWidth = $state(0);
50
+ const effectiveColumns = $derived(
51
+ gridWidth === 0
52
+ ? columns
53
+ : Math.max(
54
+ 1,
55
+ Math.min(columns, Math.floor((gridWidth + COLUMN_GAP) / (MIN_COLUMN_WIDTH + COLUMN_GAP)))
56
+ )
57
+ );
73
58
  </script>
74
59
 
75
- {#if flat}
76
- <div class="p-6">
77
- <div class="schema-grid gap-6 grid" style="--schema-cols: {columns};">
78
- {#each items as layoutItem, i (layoutItem.type === 'linebreak' ? layoutItem.id : layoutItem.paramId)}
79
- {@render gridItem(layoutItem, columns, columnStarts[i] === 0)}
80
- {/each}
81
- </div>
60
+ {#snippet grid()}
61
+ <div
62
+ class="schema-grid"
63
+ style="--schema-cols: {effectiveColumns}; --column-gap: {COLUMN_GAP}px;"
64
+ bind:clientWidth={gridWidth}
65
+ >
66
+ {#each items as layoutItem (layoutItem.type === 'linebreak' ? layoutItem.id : layoutItem.paramId)}
67
+ {@render gridItem(layoutItem)}
68
+ {/each}
82
69
  </div>
83
- {:else}
84
- <Card.Root class="gap-0 py-0 pt-0 overflow-hidden">
85
- <Card.Header
86
- class="pt-4 pb-4! cursor-pointer border-b border-border bg-muted transition-colors select-none hover:bg-muted/50 focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:outline-none"
87
- role="button"
88
- tabindex={0}
89
- aria-expanded={!collapsed}
90
- onclick={onToggle}
91
- onkeydown={handleKeydown}
92
- >
93
- <Card.Title>{label}</Card.Title>
94
- {#if description}
95
- <Card.Description>{description}</Card.Description>
96
- {/if}
97
- <Card.Action>
70
+ {/snippet}
71
+
72
+ <section class="shadow-xs rounded-xl border bg-card">
73
+ {#if flat}
74
+ <div class="p-4">
75
+ {@render grid()}
76
+ </div>
77
+ {:else}
78
+ <!-- The host's page owns the h1 and the panel holds the h2. The description sits outside the
79
+ heading's button, so the heading and the button are named by the label alone. -->
80
+ <h3>
81
+ <button
82
+ type="button"
83
+ class="gap-3 px-4 pt-3.5 flex w-full items-start text-left outline-none select-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-inset {description
84
+ ? 'pb-0'
85
+ : 'pb-3.5'}"
86
+ aria-expanded={!collapsed}
87
+ aria-describedby={description ? descriptionId : undefined}
88
+ onclick={onToggle}
89
+ >
90
+ <span class="min-w-0 text-base font-semibold leading-snug flex-1 text-foreground"
91
+ >{label}</span
92
+ >
98
93
  <ChevronDown
99
- class="h-4 w-4 text-muted-foreground transition-transform duration-200 {collapsed
100
- ? ''
101
- : 'rotate-180'}"
94
+ class="mt-1 h-4 w-4 shrink-0 text-muted-foreground transition-transform duration-200 {collapsed
95
+ ? '-rotate-90'
96
+ : ''}"
102
97
  />
103
- </Card.Action>
104
- </Card.Header>
105
- <div class="content-wrapper" class:collapsed>
98
+ </button>
99
+ </h3>
100
+ {#if description}
101
+ <p
102
+ id={descriptionId}
103
+ class="pl-4 pr-11 pt-0.5 pb-3.5 text-xs leading-snug text-muted-foreground"
104
+ >
105
+ {description}
106
+ </p>
107
+ {/if}
108
+ <div class="content-wrapper" class:collapsed inert={collapsed}>
106
109
  <div class="content-inner">
107
- <Card.Content class="p-6">
108
- <div class="schema-grid gap-6 grid" style="--schema-cols: {columns};">
109
- {#each items as layoutItem, i (layoutItem.type === 'linebreak' ? layoutItem.id : layoutItem.paramId)}
110
- {@render gridItem(layoutItem, columns, columnStarts[i] === 0)}
111
- {/each}
112
- </div>
113
- </Card.Content>
110
+ <div class="px-4 pt-1 pb-5">
111
+ {@render grid()}
112
+ </div>
114
113
  </div>
115
114
  </div>
116
- </Card.Root>
117
- {/if}
115
+ {/if}
116
+ </section>
118
117
 
119
- {#snippet gridItem(layoutItem: LayoutItem, cols: number, isFirstInRow: boolean)}
118
+ {#snippet gridItem(layoutItem: LayoutItem)}
120
119
  {#if layoutItem.type === 'linebreak'}
121
- <div style="grid-column: 1 / -1" class="h-px bg-border" aria-hidden="true"></div>
120
+ <div class="grid-break" aria-hidden="true"></div>
122
121
  {:else}
123
122
  {@const visibility = visibilityMap[itemKey(layoutItem)]}
124
- {@const span = Math.min(Math.max(1, layoutItem.span ?? 1), cols)}
123
+ {@const span = Math.min(Math.max(1, layoutItem.span ?? 1), effectiveColumns)}
125
124
  {#if visibility.visible}
126
- {#if layoutItem.type === 'input'}
127
- <div
128
- class="grid-cell min-w-0 flex items-center"
129
- class:opacity-50={visibility.disabled}
130
- class:col-divider={!isFirstInRow && cols > 1}
131
- style="grid-column: span {span} / span {span}"
132
- >
125
+ <div class="grid-cell min-w-0" class:opacity-50={visibility.disabled} style="--span: {span}">
126
+ {#if layoutItem.type === 'input'}
133
127
  {@render inputSnippet(layoutItem, visibility)}
134
- </div>
135
- {:else if layoutItem.type === 'output'}
136
- <div
137
- class="grid-cell"
138
- class:col-divider={!isFirstInRow && cols > 1}
139
- style="grid-column: span {span} / span {span}"
140
- >
128
+ {:else if layoutItem.type === 'output'}
141
129
  {@render outputSnippet(layoutItem)}
142
- </div>
143
- {/if}
130
+ {/if}
131
+ </div>
144
132
  {/if}
145
133
  {/if}
146
134
  {/snippet}
@@ -158,27 +146,28 @@
158
146
 
159
147
  .content-inner {
160
148
  min-height: 0;
149
+ overflow: hidden;
161
150
  }
162
151
 
163
152
  .schema-grid {
153
+ display: grid;
164
154
  grid-template-columns: repeat(var(--schema-cols), minmax(0, 1fr));
155
+ gap: 1rem var(--column-gap);
156
+ align-items: start;
157
+ }
158
+
159
+ .grid-cell {
160
+ grid-column: span var(--span) / span var(--span);
165
161
  }
166
162
 
167
- /* Vertical divider painted in the column gap. `gap-6` is 24px, so a 12px
168
- negative margin + 12px padding centres the 1px line in the gutter. */
169
- .col-divider {
170
- border-left: 1px solid var(--border);
171
- padding-left: 12px;
172
- margin-left: -12px;
163
+ /* A control with no label above it lines up with the controls beside it, not their labels. */
164
+ .grid-cell:has(:global([data-control-line])) {
165
+ align-self: end;
173
166
  }
174
167
 
175
- /* When the container collapses the grid to 1 visual column, the items are
176
- stacked and the divider would float on the left of every row. Hide it. */
177
- @container (max-width: 320px) {
178
- .col-divider {
179
- border-left: 0;
180
- padding-left: 0;
181
- margin-left: 0;
182
- }
168
+ /* An empty full-width row: the two row gaps around it already read as a break. */
169
+ .grid-break {
170
+ grid-column: 1 / -1;
171
+ margin-block: -0.25rem;
183
172
  }
184
173
  </style>
@@ -0,0 +1,36 @@
1
+ <script lang="ts">
2
+ import { HelpCircle } from '@lucide/svelte';
3
+ import * as Dialog from '$lib/components/primitives/dialog';
4
+
5
+ interface Props {
6
+ /** The field's label: the dialog title and the button's accessible name. */
7
+ label: string;
8
+ description: string;
9
+ }
10
+
11
+ let { label, description }: Props = $props();
12
+ </script>
13
+
14
+ <!-- Every field has one, so a column of them is noise. Where a fine pointer can hover, it shows
15
+ only while the pointer or focus is inside the enclosing `group/field`; touch keeps it visible.
16
+ The box is 24px, touch gets a 44px hit area, and the negative margin keeps the label row from
17
+ growing. -->
18
+ <Dialog.Root>
19
+ <Dialog.Trigger>
20
+ {#snippet child({ props })}
21
+ <button
22
+ {...props}
23
+ class="-m-1 size-6 pointer-coarse:after:-inset-2.5 relative flex shrink-0 cursor-help items-center justify-center rounded-sm text-muted-foreground transition hover:text-foreground pointer-coarse:after:absolute pointer-fine:opacity-0 pointer-fine:group-focus-within/field:opacity-100 pointer-fine:group-hover/field:opacity-100 pointer-fine:focus-visible:opacity-100"
24
+ aria-label={label}
25
+ >
26
+ <HelpCircle class="size-3.5" />
27
+ </button>
28
+ {/snippet}
29
+ </Dialog.Trigger>
30
+ <Dialog.Content class="sm:max-w-md">
31
+ <Dialog.Header>
32
+ <Dialog.Title>{label}</Dialog.Title>
33
+ <Dialog.Description>{description}</Dialog.Description>
34
+ </Dialog.Header>
35
+ </Dialog.Content>
36
+ </Dialog.Root>