@selvajs/ui 6.6.0-beta.8 → 7.0.0

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 (373) hide show
  1. package/README.md +0 -3
  2. package/dist/components/ErrorScreen.svelte +1 -1
  3. package/dist/components/compute/AppLayout.svelte +95 -37
  4. package/dist/components/compute/AppLayout.svelte.d.ts +18 -1
  5. package/dist/components/compute/CollapsedPanelStrip.svelte +4 -2
  6. package/dist/components/compute/ComputeApp.svelte +6 -2
  7. package/dist/components/compute/ComputeApp.svelte.d.ts +1 -1
  8. package/dist/components/compute/ComputeMessagesDialog.svelte +3 -3
  9. package/dist/components/compute/ParameterPresetManager.svelte +9 -21
  10. package/dist/components/compute/SolveMessages.svelte +101 -87
  11. package/dist/components/compute/SolveMessages.svelte.d.ts +12 -0
  12. package/dist/components/layout/AppShell.svelte +2 -2
  13. package/dist/components/layout/FooterItemRenderer.svelte +2 -2
  14. package/dist/components/layout/FooterItemRenderer.svelte.d.ts +1 -1
  15. package/dist/components/layout/PageContent.svelte +3 -2
  16. package/dist/components/layout/PageFooter.svelte +8 -6
  17. package/dist/components/layout/PageHeader.svelte +3 -3
  18. package/dist/components/layout/SideNav.svelte +56 -15
  19. package/dist/components/layout/SubNav.svelte +2 -2
  20. package/dist/components/preview/ChartOutput.svelte +158 -62
  21. package/dist/components/preview/Group.svelte +14 -9
  22. package/dist/components/preview/HelpButton.svelte +1 -1
  23. package/dist/components/preview/ImageOutput.svelte +16 -11
  24. package/dist/components/preview/InputControl.svelte +115 -50
  25. package/dist/components/preview/InputControl.svelte.d.ts +5 -1
  26. package/dist/components/preview/OutputDisplay.svelte +26 -17
  27. package/dist/components/preview/TabBar.svelte +8 -6
  28. package/dist/components/preview/TabBar.svelte.d.ts +2 -0
  29. package/dist/components/preview/TabContent.svelte +65 -33
  30. package/dist/components/preview/TabContent.svelte.d.ts +5 -1
  31. package/dist/components/preview/TabLayout.svelte +29 -8
  32. package/dist/components/preview/TabLayout.svelte.d.ts +5 -0
  33. package/dist/components/preview/inputs/CheckboxInput.svelte +1 -1
  34. package/dist/components/preview/inputs/ChecklistInput.svelte +11 -6
  35. package/dist/components/preview/inputs/ChecklistInput.svelte.d.ts +2 -1
  36. package/dist/components/preview/inputs/ColorInput.svelte +356 -14
  37. package/dist/components/preview/inputs/ColorInput.svelte.d.ts +1 -0
  38. package/dist/components/preview/inputs/DropdownInput.svelte +18 -6
  39. package/dist/components/preview/inputs/DropdownInput.svelte.d.ts +2 -1
  40. package/dist/components/preview/inputs/FileInput.svelte +71 -75
  41. package/dist/components/preview/inputs/GeometryInput.svelte +128 -0
  42. package/dist/components/preview/inputs/GeometryInput.svelte.d.ts +21 -0
  43. package/dist/components/preview/inputs/NumberInput.svelte +8 -8
  44. package/dist/components/preview/inputs/OptionGlyph.svelte +29 -0
  45. package/dist/components/preview/inputs/OptionGlyph.svelte.d.ts +8 -0
  46. package/dist/components/preview/inputs/SegmentedInput.svelte +45 -0
  47. package/dist/components/preview/inputs/SegmentedInput.svelte.d.ts +12 -0
  48. package/dist/components/preview/inputs/TextInput.svelte +5 -5
  49. package/dist/components/preview/inputs/TileInput.svelte +83 -0
  50. package/dist/components/preview/inputs/TileInput.svelte.d.ts +12 -0
  51. package/dist/components/preview/inputs/index.d.ts +3 -0
  52. package/dist/components/preview/inputs/index.js +3 -0
  53. package/dist/components/primitives/CalculateButton.svelte +10 -4
  54. package/dist/components/primitives/Callout.svelte +8 -6
  55. package/dist/components/primitives/Callout.svelte.d.ts +4 -4
  56. package/dist/components/primitives/DataTable.svelte +1 -1
  57. package/dist/components/primitives/FilterableDropdown.svelte +13 -1
  58. package/dist/components/primitives/FilterableDropdown.svelte.d.ts +5 -0
  59. package/dist/components/primitives/ImageUploadField.svelte +1 -1
  60. package/dist/components/primitives/SolvingIndicator.svelte +245 -19
  61. package/dist/components/primitives/SolvingIndicator.svelte.d.ts +15 -0
  62. package/dist/components/primitives/alert-dialog/alert-dialog-content.svelte +1 -1
  63. package/dist/components/primitives/badge/badge.svelte +2 -2
  64. package/dist/components/primitives/badge/badge.svelte.d.ts +6 -6
  65. package/dist/components/primitives/button/button.svelte +9 -7
  66. package/dist/components/primitives/button/button.svelte.d.ts +19 -16
  67. package/dist/components/primitives/card/card.svelte +1 -1
  68. package/dist/components/primitives/card/card.svelte.d.ts +1 -1
  69. package/dist/components/primitives/checkbox/checkbox.svelte +1 -1
  70. package/dist/components/primitives/command/command-input.svelte +1 -1
  71. package/dist/components/primitives/command/command-item.svelte +1 -1
  72. package/dist/components/primitives/command/command-link-item.svelte +1 -1
  73. package/dist/components/primitives/command/command.svelte +1 -1
  74. package/dist/components/primitives/context-menu/context-menu-checkbox-item.svelte +1 -1
  75. package/dist/components/primitives/context-menu/context-menu-content.svelte +1 -1
  76. package/dist/components/primitives/context-menu/context-menu-item.svelte +1 -1
  77. package/dist/components/primitives/context-menu/context-menu-radio-item.svelte +1 -1
  78. package/dist/components/primitives/context-menu/context-menu-sub-content.svelte +1 -1
  79. package/dist/components/primitives/context-menu/context-menu-sub-trigger.svelte +1 -1
  80. package/dist/components/primitives/dialog/dialog-content.svelte +3 -3
  81. package/dist/components/primitives/drawer/Drawer.svelte +1 -1
  82. package/dist/components/primitives/dropdown-menu/dropdown-menu-checkbox-item.svelte +31 -11
  83. package/dist/components/primitives/dropdown-menu/dropdown-menu-checkbox-item.svelte.d.ts +2 -0
  84. package/dist/components/primitives/dropdown-menu/dropdown-menu-content.svelte +5 -1
  85. package/dist/components/primitives/dropdown-menu/dropdown-menu-content.svelte.d.ts +2 -0
  86. package/dist/components/primitives/dropdown-menu/dropdown-menu-item.svelte +4 -2
  87. package/dist/components/primitives/dropdown-menu/dropdown-menu-item.svelte.d.ts +2 -1
  88. package/dist/components/primitives/dropdown-menu/dropdown-menu-radio-item.svelte +1 -1
  89. package/dist/components/primitives/dropdown-menu/dropdown-menu-shortcut.svelte +1 -1
  90. package/dist/components/primitives/dropdown-menu/dropdown-menu-sub-content.svelte +1 -1
  91. package/dist/components/primitives/dropdown-menu/dropdown-menu-sub-trigger.svelte +1 -1
  92. package/dist/components/primitives/index.d.ts +1 -1
  93. package/dist/components/primitives/index.js +1 -1
  94. package/dist/components/primitives/input/input.svelte +2 -2
  95. package/dist/components/primitives/input-group/input-group-input.svelte.d.ts +1 -1
  96. package/dist/components/primitives/input-group/input-group.svelte +1 -1
  97. package/dist/components/primitives/mode-toggle/mode-toggle.svelte +2 -2
  98. package/dist/components/primitives/popover/popover-content.svelte +1 -1
  99. package/dist/components/primitives/resizable/resizable-handle.svelte +2 -2
  100. package/dist/components/primitives/search/search.svelte +1 -1
  101. package/dist/components/primitives/select/select-content.svelte +1 -1
  102. package/dist/components/primitives/select/select-item.svelte +1 -1
  103. package/dist/components/primitives/select/select-trigger.svelte +1 -1
  104. package/dist/components/primitives/slider/slider.svelte +1 -1
  105. package/dist/components/primitives/switch/switch.svelte +1 -1
  106. package/dist/components/primitives/tabs/tabs-list.svelte +2 -2
  107. package/dist/components/primitives/tabs/tabs-list.svelte.d.ts +6 -6
  108. package/dist/components/primitives/tabs/tabs-trigger.svelte +2 -2
  109. package/dist/components/primitives/tabs/tabs-trigger.svelte.d.ts +6 -6
  110. package/dist/components/primitives/textarea/textarea.svelte +1 -1
  111. package/dist/components/primitives/toggle/toggle.svelte +11 -3
  112. package/dist/components/primitives/toggle/toggle.svelte.d.ts +13 -4
  113. package/dist/components/primitives/toggle-group/toggle-group-item.svelte +1 -1
  114. package/dist/components/primitives/toggle-group/toggle-group.svelte +1 -1
  115. package/dist/components/primitives/tooltip/index.d.ts +6 -0
  116. package/dist/components/primitives/tooltip/index.js +8 -0
  117. package/dist/components/primitives/tooltip/tooltip-content.svelte +34 -0
  118. package/dist/components/primitives/tooltip/tooltip-content.svelte.d.ts +10 -0
  119. package/dist/components/primitives/tooltip/tooltip-portal.svelte +7 -0
  120. package/dist/components/primitives/tooltip/tooltip-portal.svelte.d.ts +4 -0
  121. package/dist/components/primitives/tooltip/tooltip-provider.svelte +7 -0
  122. package/dist/components/primitives/tooltip/tooltip-provider.svelte.d.ts +4 -0
  123. package/dist/components/primitives/tooltip/tooltip-trigger.svelte +7 -0
  124. package/dist/components/primitives/tooltip/tooltip-trigger.svelte.d.ts +4 -0
  125. package/dist/components/primitives/tooltip/tooltip.svelte +7 -0
  126. package/dist/components/primitives/tooltip/tooltip.svelte.d.ts +4 -0
  127. package/dist/components/viewer/MeshMetadataPanel.svelte +2 -2
  128. package/dist/components/viewer/SceneManager.svelte +32 -21
  129. package/dist/components/viewer/SceneManager.svelte.d.ts +3 -1
  130. package/dist/components/viewer/Viewer.svelte +135 -185
  131. package/dist/components/viewer/Viewer.svelte.d.ts +7 -2
  132. package/dist/components/viewer/ViewerDock.svelte +404 -0
  133. package/dist/components/viewer/ViewerDock.svelte.d.ts +42 -0
  134. package/dist/composables/useFooterItem.svelte.d.ts +1 -1
  135. package/dist/composables/useFooterItem.svelte.js +1 -1
  136. package/dist/compute/liveProgress.svelte.d.ts +16 -0
  137. package/dist/compute/liveProgress.svelte.js +90 -0
  138. package/dist/compute/solving.svelte.d.ts +11 -7
  139. package/dist/compute/solving.svelte.js +64 -45
  140. package/dist/constants.d.ts +6 -8
  141. package/dist/constants.js +8 -11
  142. package/dist/contexts/hostContext.svelte.d.ts +39 -0
  143. package/dist/contexts/hostContext.svelte.js +9 -0
  144. package/dist/features/chart/plotly-compat.d.ts +15 -0
  145. package/dist/features/chart/plotly-compat.js +124 -0
  146. package/dist/i18n/messages.d.ts +50 -0
  147. package/dist/i18n/messages.js +84 -0
  148. package/dist/index.d.ts +5 -0
  149. package/dist/index.js +5 -0
  150. package/dist/public.d.ts +1 -0
  151. package/dist/public.js +1 -0
  152. package/dist/schema/host-support.d.ts +29 -0
  153. package/dist/schema/host-support.js +97 -0
  154. package/dist/schema/option-display.d.ts +12 -0
  155. package/dist/schema/option-display.js +29 -0
  156. package/dist/schema/param-exporter.d.ts +4 -1
  157. package/dist/schema/param-exporter.js +10 -6
  158. package/dist/schema/visibility-rules.d.ts +7 -1
  159. package/dist/schema/visibility-rules.js +17 -0
  160. package/dist/styles/base.css +94 -84
  161. package/dist/utils/color-space.d.ts +21 -0
  162. package/dist/utils/color-space.js +90 -0
  163. package/dist/utils/file-download.js +6 -10
  164. package/dist/utils/host-files.d.ts +12 -0
  165. package/dist/utils/host-files.js +46 -0
  166. package/dist/utils/webp-to-png.d.ts +10 -0
  167. package/dist/utils/webp-to-png.js +41 -0
  168. package/package.json +31 -23
  169. package/src/lib/components/ErrorScreen.svelte +1 -1
  170. package/src/lib/components/compute/AppLayout.svelte +96 -38
  171. package/src/lib/components/compute/CollapsedPanelStrip.svelte +4 -2
  172. package/src/lib/components/compute/ComputeApp.svelte +6 -2
  173. package/src/lib/components/compute/ComputeMessagesDialog.svelte +4 -4
  174. package/src/lib/components/compute/ParameterPresetManager.svelte +9 -21
  175. package/src/lib/components/compute/SolveMessages.svelte +103 -89
  176. package/src/lib/components/layout/AppShell.svelte +2 -2
  177. package/src/lib/components/layout/FooterItemRenderer.svelte +2 -2
  178. package/src/lib/components/layout/PageContent.svelte +3 -2
  179. package/src/lib/components/layout/PageFooter.svelte +8 -6
  180. package/src/lib/components/layout/PageHeader.svelte +3 -3
  181. package/src/lib/components/layout/SideNav.svelte +56 -15
  182. package/src/lib/components/layout/SubNav.svelte +2 -2
  183. package/src/lib/components/preview/ChartOutput.svelte +158 -62
  184. package/src/lib/components/preview/Group.svelte +14 -9
  185. package/src/lib/components/preview/HelpButton.svelte +1 -1
  186. package/src/lib/components/preview/ImageOutput.svelte +16 -11
  187. package/src/lib/components/preview/InputControl.svelte +115 -50
  188. package/src/lib/components/preview/OutputDisplay.svelte +26 -17
  189. package/src/lib/components/preview/TabBar.svelte +8 -6
  190. package/src/lib/components/preview/TabContent.svelte +65 -33
  191. package/src/lib/components/preview/TabLayout.svelte +29 -8
  192. package/src/lib/components/preview/inputs/CheckboxInput.svelte +1 -1
  193. package/src/lib/components/preview/inputs/ChecklistInput.svelte +11 -6
  194. package/src/lib/components/preview/inputs/ColorInput.svelte +356 -14
  195. package/src/lib/components/preview/inputs/DropdownInput.svelte +18 -6
  196. package/src/lib/components/preview/inputs/FileInput.svelte +71 -75
  197. package/src/lib/components/preview/inputs/GeometryInput.svelte +128 -0
  198. package/src/lib/components/preview/inputs/NumberInput.svelte +8 -8
  199. package/src/lib/components/preview/inputs/OptionGlyph.svelte +29 -0
  200. package/src/lib/components/preview/inputs/SegmentedInput.svelte +45 -0
  201. package/src/lib/components/preview/inputs/TextInput.svelte +5 -5
  202. package/src/lib/components/preview/inputs/TileInput.svelte +83 -0
  203. package/src/lib/components/preview/inputs/index.ts +3 -0
  204. package/src/lib/components/primitives/CalculateButton.svelte +10 -4
  205. package/src/lib/components/primitives/Callout.svelte +9 -7
  206. package/src/lib/components/primitives/DataTable.svelte +1 -1
  207. package/src/lib/components/primitives/FilterableDropdown.svelte +14 -2
  208. package/src/lib/components/primitives/ImageUploadField.svelte +1 -1
  209. package/src/lib/components/primitives/IssueList.svelte +1 -1
  210. package/src/lib/components/primitives/SeverityIcon.svelte +1 -1
  211. package/src/lib/components/primitives/SolvingIndicator.svelte +245 -19
  212. package/src/lib/components/primitives/StateDisplay.svelte +1 -1
  213. package/src/lib/components/primitives/alert-dialog/alert-dialog-action.svelte +2 -2
  214. package/src/lib/components/primitives/alert-dialog/alert-dialog-cancel.svelte +2 -2
  215. package/src/lib/components/primitives/alert-dialog/alert-dialog-content.svelte +2 -2
  216. package/src/lib/components/primitives/alert-dialog/alert-dialog-description.svelte +1 -1
  217. package/src/lib/components/primitives/alert-dialog/alert-dialog-footer.svelte +1 -1
  218. package/src/lib/components/primitives/alert-dialog/alert-dialog-header.svelte +1 -1
  219. package/src/lib/components/primitives/alert-dialog/alert-dialog-overlay.svelte +1 -1
  220. package/src/lib/components/primitives/alert-dialog/alert-dialog-title.svelte +1 -1
  221. package/src/lib/components/primitives/badge/badge.svelte +3 -3
  222. package/src/lib/components/primitives/button/button.svelte +9 -7
  223. package/src/lib/components/primitives/button-group/button-group-separator.svelte +2 -2
  224. package/src/lib/components/primitives/button-group/button-group-text.svelte +1 -1
  225. package/src/lib/components/primitives/button-group/button-group.svelte +1 -1
  226. package/src/lib/components/primitives/card/card-content.svelte +1 -1
  227. package/src/lib/components/primitives/card/card-description.svelte +1 -1
  228. package/src/lib/components/primitives/card/card-footer.svelte +1 -1
  229. package/src/lib/components/primitives/card/card-header.svelte +1 -1
  230. package/src/lib/components/primitives/card/card-title.svelte +1 -1
  231. package/src/lib/components/primitives/card/card.svelte +2 -2
  232. package/src/lib/components/primitives/checkbox/checkbox.svelte +2 -2
  233. package/src/lib/components/primitives/command/command-dialog.svelte +2 -2
  234. package/src/lib/components/primitives/command/command-empty.svelte +1 -1
  235. package/src/lib/components/primitives/command/command-group.svelte +1 -1
  236. package/src/lib/components/primitives/command/command-input.svelte +3 -3
  237. package/src/lib/components/primitives/command/command-item.svelte +2 -2
  238. package/src/lib/components/primitives/command/command-link-item.svelte +2 -2
  239. package/src/lib/components/primitives/command/command-list.svelte +1 -1
  240. package/src/lib/components/primitives/command/command-separator.svelte +1 -1
  241. package/src/lib/components/primitives/command/command-shortcut.svelte +1 -1
  242. package/src/lib/components/primitives/command/command.svelte +2 -2
  243. package/src/lib/components/primitives/context-menu/context-menu-checkbox-item.svelte +2 -2
  244. package/src/lib/components/primitives/context-menu/context-menu-content.svelte +2 -2
  245. package/src/lib/components/primitives/context-menu/context-menu-group-heading.svelte +1 -1
  246. package/src/lib/components/primitives/context-menu/context-menu-item.svelte +2 -2
  247. package/src/lib/components/primitives/context-menu/context-menu-label.svelte +1 -1
  248. package/src/lib/components/primitives/context-menu/context-menu-radio-item.svelte +2 -2
  249. package/src/lib/components/primitives/context-menu/context-menu-separator.svelte +1 -1
  250. package/src/lib/components/primitives/context-menu/context-menu-shortcut.svelte +1 -1
  251. package/src/lib/components/primitives/context-menu/context-menu-sub-content.svelte +2 -2
  252. package/src/lib/components/primitives/context-menu/context-menu-sub-trigger.svelte +2 -2
  253. package/src/lib/components/primitives/dialog/dialog-content.svelte +4 -4
  254. package/src/lib/components/primitives/dialog/dialog-description.svelte +1 -1
  255. package/src/lib/components/primitives/dialog/dialog-footer.svelte +1 -1
  256. package/src/lib/components/primitives/dialog/dialog-header.svelte +1 -1
  257. package/src/lib/components/primitives/dialog/dialog-overlay.svelte +1 -1
  258. package/src/lib/components/primitives/dialog/dialog-title.svelte +1 -1
  259. package/src/lib/components/primitives/drawer/Drawer.svelte +1 -1
  260. package/src/lib/components/primitives/dropdown-menu/dropdown-menu-checkbox-item.svelte +32 -12
  261. package/src/lib/components/primitives/dropdown-menu/dropdown-menu-content.svelte +6 -2
  262. package/src/lib/components/primitives/dropdown-menu/dropdown-menu-group-heading.svelte +1 -1
  263. package/src/lib/components/primitives/dropdown-menu/dropdown-menu-item.svelte +5 -3
  264. package/src/lib/components/primitives/dropdown-menu/dropdown-menu-label.svelte +1 -1
  265. package/src/lib/components/primitives/dropdown-menu/dropdown-menu-radio-item.svelte +2 -2
  266. package/src/lib/components/primitives/dropdown-menu/dropdown-menu-separator.svelte +1 -1
  267. package/src/lib/components/primitives/dropdown-menu/dropdown-menu-shortcut.svelte +2 -2
  268. package/src/lib/components/primitives/dropdown-menu/dropdown-menu-sub-content.svelte +2 -2
  269. package/src/lib/components/primitives/dropdown-menu/dropdown-menu-sub-trigger.svelte +2 -2
  270. package/src/lib/components/primitives/empty/empty-content.svelte +1 -1
  271. package/src/lib/components/primitives/empty/empty-description.svelte +1 -1
  272. package/src/lib/components/primitives/empty/empty-header.svelte +1 -1
  273. package/src/lib/components/primitives/empty/empty-media.svelte +1 -1
  274. package/src/lib/components/primitives/empty/empty-title.svelte +1 -1
  275. package/src/lib/components/primitives/empty/empty.svelte +1 -1
  276. package/src/lib/components/primitives/field/field-content.svelte +1 -1
  277. package/src/lib/components/primitives/field/field-description.svelte +1 -1
  278. package/src/lib/components/primitives/field/field-error.svelte +1 -1
  279. package/src/lib/components/primitives/field/field-group.svelte +1 -1
  280. package/src/lib/components/primitives/field/field-label.svelte +2 -2
  281. package/src/lib/components/primitives/field/field-legend.svelte +1 -1
  282. package/src/lib/components/primitives/field/field-separator.svelte +2 -2
  283. package/src/lib/components/primitives/field/field-set.svelte +1 -1
  284. package/src/lib/components/primitives/field/field-title.svelte +1 -1
  285. package/src/lib/components/primitives/field/field.svelte +1 -1
  286. package/src/lib/components/primitives/index.ts +1 -1
  287. package/src/lib/components/primitives/input/input.svelte +3 -3
  288. package/src/lib/components/primitives/input-group/input-group-addon.svelte +1 -1
  289. package/src/lib/components/primitives/input-group/input-group-button.svelte +2 -2
  290. package/src/lib/components/primitives/input-group/input-group-input.svelte +2 -2
  291. package/src/lib/components/primitives/input-group/input-group-text.svelte +1 -1
  292. package/src/lib/components/primitives/input-group/input-group-textarea.svelte +2 -2
  293. package/src/lib/components/primitives/input-group/input-group.svelte +2 -2
  294. package/src/lib/components/primitives/label/label.svelte +1 -1
  295. package/src/lib/components/primitives/mode-toggle/mode-toggle.svelte +2 -2
  296. package/src/lib/components/primitives/popover/popover-content.svelte +2 -2
  297. package/src/lib/components/primitives/popover/popover-description.svelte +1 -1
  298. package/src/lib/components/primitives/popover/popover-header.svelte +1 -1
  299. package/src/lib/components/primitives/popover/popover-title.svelte +1 -1
  300. package/src/lib/components/primitives/popover/popover-trigger.svelte +1 -1
  301. package/src/lib/components/primitives/resizable/resizable-handle.svelte +3 -3
  302. package/src/lib/components/primitives/resizable/resizable-pane-group.svelte +1 -1
  303. package/src/lib/components/primitives/scroll-area/scroll-area-scrollbar.svelte +1 -1
  304. package/src/lib/components/primitives/scroll-area/scroll-area.svelte +1 -1
  305. package/src/lib/components/primitives/search/search.svelte +2 -2
  306. package/src/lib/components/primitives/select/select-content.svelte +2 -2
  307. package/src/lib/components/primitives/select/select-group-heading.svelte +1 -1
  308. package/src/lib/components/primitives/select/select-item.svelte +2 -2
  309. package/src/lib/components/primitives/select/select-label.svelte +1 -1
  310. package/src/lib/components/primitives/select/select-scroll-down-button.svelte +1 -1
  311. package/src/lib/components/primitives/select/select-scroll-up-button.svelte +1 -1
  312. package/src/lib/components/primitives/select/select-separator.svelte +2 -2
  313. package/src/lib/components/primitives/select/select-trigger.svelte +2 -2
  314. package/src/lib/components/primitives/separator/separator.svelte +1 -1
  315. package/src/lib/components/primitives/slider/slider.svelte +2 -2
  316. package/src/lib/components/primitives/spinner/spinner.svelte +1 -1
  317. package/src/lib/components/primitives/switch/switch.svelte +2 -2
  318. package/src/lib/components/primitives/tabs/tabs-content.svelte +1 -1
  319. package/src/lib/components/primitives/tabs/tabs-list.svelte +3 -3
  320. package/src/lib/components/primitives/tabs/tabs-trigger.svelte +3 -3
  321. package/src/lib/components/primitives/tabs/tabs.svelte +1 -1
  322. package/src/lib/components/primitives/textarea/textarea.svelte +2 -2
  323. package/src/lib/components/primitives/toggle/toggle.svelte +12 -4
  324. package/src/lib/components/primitives/toggle-group/toggle-group-item.svelte +3 -3
  325. package/src/lib/components/primitives/toggle-group/toggle-group.svelte +3 -3
  326. package/src/lib/components/primitives/tooltip/index.ts +19 -0
  327. package/src/lib/components/primitives/tooltip/tooltip-content.svelte +34 -0
  328. package/src/lib/components/primitives/tooltip/tooltip-portal.svelte +7 -0
  329. package/src/lib/components/primitives/tooltip/tooltip-provider.svelte +7 -0
  330. package/src/lib/components/primitives/tooltip/tooltip-trigger.svelte +7 -0
  331. package/src/lib/components/primitives/tooltip/tooltip.svelte +7 -0
  332. package/src/lib/components/viewer/MeshMetadataPanel.svelte +2 -2
  333. package/src/lib/components/viewer/SceneManager.svelte +32 -21
  334. package/src/lib/components/viewer/Viewer.svelte +136 -186
  335. package/src/lib/components/viewer/ViewerDock.svelte +404 -0
  336. package/src/lib/composables/useFooterItem.svelte.ts +1 -1
  337. package/src/lib/compute/liveProgress.svelte.ts +103 -0
  338. package/src/lib/compute/solving.svelte.ts +66 -50
  339. package/src/lib/constants.ts +8 -11
  340. package/src/lib/contexts/hostContext.svelte.ts +51 -0
  341. package/src/lib/features/chart/plotly-compat.ts +141 -0
  342. package/src/lib/i18n/messages.ts +139 -0
  343. package/src/lib/index.ts +22 -0
  344. package/src/lib/public.ts +1 -0
  345. package/src/lib/schema/host-support.ts +129 -0
  346. package/src/lib/schema/option-display.ts +44 -0
  347. package/src/lib/schema/param-exporter.ts +10 -7
  348. package/src/lib/schema/visibility-rules.ts +27 -1
  349. package/src/lib/styles/base.css +94 -84
  350. package/src/lib/utils/color-space.ts +107 -0
  351. package/src/lib/utils/file-download.ts +7 -11
  352. package/src/lib/utils/host-files.ts +61 -0
  353. package/src/lib/utils/webp-to-png.ts +48 -0
  354. package/dist/components/primitives/theme-switcher/ThemeSwitcher.svelte +0 -39
  355. package/dist/components/primitives/theme-switcher/ThemeSwitcher.svelte.d.ts +0 -3
  356. package/dist/components/primitives/theme-switcher/index.d.ts +0 -1
  357. package/dist/components/primitives/theme-switcher/index.js +0 -1
  358. package/dist/styles/themes/cyberpunk.css +0 -98
  359. package/dist/styles/themes/neutral.css +0 -72
  360. package/dist/styles/themes/ocean.css +0 -75
  361. package/dist/styles/themes/selva.css +0 -105
  362. package/dist/theme/themeStore.svelte.d.ts +0 -12
  363. package/dist/theme/themeStore.svelte.js +0 -40
  364. package/dist/theme/themes.d.ts +0 -5
  365. package/dist/theme/themes.js +0 -13
  366. package/src/lib/components/primitives/theme-switcher/ThemeSwitcher.svelte +0 -39
  367. package/src/lib/components/primitives/theme-switcher/index.ts +0 -1
  368. package/src/lib/styles/themes/cyberpunk.css +0 -98
  369. package/src/lib/styles/themes/neutral.css +0 -72
  370. package/src/lib/styles/themes/ocean.css +0 -75
  371. package/src/lib/styles/themes/selva.css +0 -105
  372. package/src/lib/theme/themeStore.svelte.ts +0 -50
  373. package/src/lib/theme/themes.ts +0 -18
@@ -1,6 +1,7 @@
1
1
  import { decodeBase64ToBinary, downloadFileDataByRoot } from '@selvajs/compute/core';
2
2
  import { SvelteMap } from 'svelte/reactivity';
3
3
  import { APP_DEFAULTS } from '../constants';
4
+ import { saveBlob } from './host-files';
4
5
  export const MIME_BY_EXT = {
5
6
  '.png': 'image/png',
6
7
  '.jpg': 'image/jpeg',
@@ -23,12 +24,7 @@ function saveSingleFile(file) {
23
24
  const content = file.isBase64Encoded ? decodeBase64ToBinary(file.data) : file.data;
24
25
  // decodeBase64ToBinary returns an ArrayBuffer-backed copy, never a SharedArrayBuffer view.
25
26
  const blob = new Blob([content], { type: mime });
26
- const fullName = `${file.fileName}${file.fileType ?? ''}`;
27
- const a = document.createElement('a');
28
- a.href = URL.createObjectURL(blob);
29
- a.download = fullName;
30
- a.click();
31
- URL.revokeObjectURL(a.href);
27
+ return saveBlob(blob, `${file.fileName}${file.fileType ?? ''}`);
32
28
  }
33
29
  export async function downloadFiles(fileData, fileName = 'grasshopper-output') {
34
30
  try {
@@ -37,13 +33,13 @@ export async function downloadFiles(fileData, fileName = 'grasshopper-output') {
37
33
  console.warn('[FileDownload] No files to download');
38
34
  return;
39
35
  }
40
- // A lone file is saved as itself rather than zipped — the one case that needs the DOM
41
- // directly. Everything else, including the per-root archive split, belongs to compute.
36
+ // A lone file is saved as itself rather than zipped. Everything else, including the
37
+ // per-root archive split, belongs to compute.
42
38
  if (filesArray.length === 1) {
43
- saveSingleFile(filesArray[0]);
39
+ await saveSingleFile(filesArray[0]);
44
40
  return;
45
41
  }
46
- await downloadFileDataByRoot(filesArray, fileName);
42
+ await downloadFileDataByRoot(filesArray, fileName, null, { saveBlob });
47
43
  }
48
44
  catch (error) {
49
45
  console.error('[FileDownload] Error downloading files:', error);
@@ -0,0 +1,12 @@
1
+ /** Resolves false when the user cancelled. An anchor download always resolves true: it can't tell. */
2
+ export type BlobSaver = (blob: Blob, fileName: string) => Promise<boolean>;
3
+ /** `accept` is what `<input accept>` takes: `.slvp,.sps`, `image/*`. Resolves null on cancel. */
4
+ export type FilePicker = (options: {
5
+ accept: string;
6
+ }) => Promise<File | null>;
7
+ export declare function setBlobSaver(next: BlobSaver): void;
8
+ export declare function setFilePicker(next: FilePicker): void;
9
+ export declare function saveBlob(blob: Blob, fileName: string): Promise<boolean>;
10
+ export declare function pickFile(options: {
11
+ accept: string;
12
+ }): Promise<File | null>;
@@ -0,0 +1,46 @@
1
+ // Where a file the page offers goes, and where a file the page asks for comes from. A browser
2
+ // gets an <a download> click and a hidden <input type=file>. A host whose WebView can't do
3
+ // either safely (the Rhino panel) installs its own once at start-up, before the first save or pick.
4
+ let saver = saveWithAnchor;
5
+ let picker = pickWithInput;
6
+ export function setBlobSaver(next) {
7
+ saver = next;
8
+ }
9
+ export function setFilePicker(next) {
10
+ picker = next;
11
+ }
12
+ export function saveBlob(blob, fileName) {
13
+ return saver(blob, fileName);
14
+ }
15
+ export function pickFile(options) {
16
+ return picker(options);
17
+ }
18
+ async function saveWithAnchor(blob, fileName) {
19
+ const url = URL.createObjectURL(blob);
20
+ const a = document.createElement('a');
21
+ a.href = url;
22
+ a.download = fileName;
23
+ // Firefox only downloads from an anchor that is in the document.
24
+ document.body.appendChild(a);
25
+ a.click();
26
+ a.remove();
27
+ // Revoking synchronously can abort the download: the browser pins the blob only once it starts.
28
+ setTimeout(() => URL.revokeObjectURL(url), 10_000);
29
+ return true;
30
+ }
31
+ function pickWithInput({ accept }) {
32
+ return new Promise((resolve) => {
33
+ const input = document.createElement('input');
34
+ input.type = 'file';
35
+ input.accept = accept;
36
+ input.style.display = 'none';
37
+ const settle = (file) => {
38
+ input.remove();
39
+ resolve(file);
40
+ };
41
+ input.addEventListener('change', () => settle(input.files?.[0] ?? null), { once: true });
42
+ input.addEventListener('cancel', () => settle(null), { once: true });
43
+ document.body.appendChild(input);
44
+ input.click();
45
+ });
46
+ }
@@ -0,0 +1,10 @@
1
+ /** True when a WebP should go out as PNG: the input takes PNG, so a PNG is a valid value. */
2
+ export declare function shouldConvertWebp(fileEnding: string, acceptedFormats: readonly string[]): boolean;
3
+ /** Whether the input takes a file with this ending, counting a WebP it would get as PNG. */
4
+ export declare function acceptsFileEnding(fileEnding: string, acceptedFormats: readonly string[]): boolean;
5
+ /**
6
+ * By content, not name: image CDNs serve WebP from URLs with no extension or one naming another
7
+ * format. A WebP file starts `RIFF`, a 4-byte size, then `WEBP`.
8
+ */
9
+ export declare function isWebp(blob: Blob): Promise<boolean>;
10
+ export declare function webpToPng(blob: Blob): Promise<Blob>;
@@ -0,0 +1,41 @@
1
+ // Grasshopper's PDF export can't read WebP: the plugin's PDF library has no WebP decoder, and
2
+ // nothing on Windows or Rhino.Compute decodes it reliably. The browser can, so a WebP picked for
3
+ // an input that also takes PNG is re-encoded here. PNG rather than JPEG keeps transparency.
4
+ /** True when a WebP should go out as PNG: the input takes PNG, so a PNG is a valid value. */
5
+ export function shouldConvertWebp(fileEnding, acceptedFormats) {
6
+ return fileEnding === '.webp' && acceptedFormats.includes('.png');
7
+ }
8
+ /** Whether the input takes a file with this ending, counting a WebP it would get as PNG. */
9
+ export function acceptsFileEnding(fileEnding, acceptedFormats) {
10
+ const ending = fileEnding.toLowerCase();
11
+ if (acceptedFormats.length === 0 || acceptedFormats.includes(ending))
12
+ return true;
13
+ return shouldConvertWebp(ending, acceptedFormats);
14
+ }
15
+ const ascii = (bytes, start, end) => String.fromCharCode(...bytes.subarray(start, end));
16
+ /**
17
+ * By content, not name: image CDNs serve WebP from URLs with no extension or one naming another
18
+ * format. A WebP file starts `RIFF`, a 4-byte size, then `WEBP`.
19
+ */
20
+ export async function isWebp(blob) {
21
+ if (blob.type === 'image/webp')
22
+ return true;
23
+ const head = new Uint8Array(await blob.slice(0, 12).arrayBuffer());
24
+ return head.length === 12 && ascii(head, 0, 4) === 'RIFF' && ascii(head, 8, 12) === 'WEBP';
25
+ }
26
+ export async function webpToPng(blob) {
27
+ const bitmap = await createImageBitmap(blob);
28
+ try {
29
+ const canvas = document.createElement('canvas');
30
+ canvas.width = bitmap.width;
31
+ canvas.height = bitmap.height;
32
+ const context = canvas.getContext('2d');
33
+ if (!context)
34
+ throw new Error('Canvas 2D context unavailable');
35
+ context.drawImage(bitmap, 0, 0);
36
+ return await new Promise((resolve, reject) => canvas.toBlob((png) => (png ? resolve(png) : reject(new Error('PNG encoding failed'))), 'image/png'));
37
+ }
38
+ finally {
39
+ bitmap.close();
40
+ }
41
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@selvajs/ui",
3
- "version": "6.6.0-beta.8",
3
+ "version": "7.0.0",
4
4
  "description": "Shared UI components and utilities for Selva applications",
5
5
  "license": "MIT",
6
6
  "author": "VektorNode",
@@ -31,17 +31,20 @@
31
31
  ".": {
32
32
  "selva-source": {
33
33
  "types": "./dist/index.d.ts",
34
- "svelte": "./dist/index.js"
34
+ "svelte": "./src/lib/index.ts"
35
35
  },
36
36
  "types": "./dist/public.d.ts",
37
37
  "svelte": "./dist/public.js"
38
38
  },
39
39
  "./external": {
40
+ "selva-source": {
41
+ "types": "./dist/external/storage.d.ts",
42
+ "svelte": "./src/lib/external/storage.ts"
43
+ },
40
44
  "types": "./dist/external/storage.d.ts",
41
45
  "svelte": "./dist/external/storage.js"
42
46
  },
43
- "./styles/base.css": "./src/lib/styles/base.css",
44
- "./styles/themes/*": "./src/lib/styles/themes/*"
47
+ "./styles/base.css": "./src/lib/styles/base.css"
45
48
  },
46
49
  "files": [
47
50
  "dist",
@@ -58,11 +61,11 @@
58
61
  "bits-ui": "^2.18.0",
59
62
  "svelte": "^5",
60
63
  "tailwind-variants": "^3.3.1",
61
- "three": "^0.186.1",
62
- "@selvajs/schemas": "^5.3.0-beta.0",
63
- "@selvajs/compute": "^5.0.0-beta.2",
64
- "@selvajs/visualization": "^1.6.0-beta.0",
65
- "@selvajs/solve": "^2.0.0-beta.4"
64
+ "three": "^0.187.0",
65
+ "@selvajs/solve": "^2.0.0",
66
+ "@selvajs/schemas": "^5.3.0",
67
+ "@selvajs/visualization": "^1.6.0",
68
+ "@selvajs/compute": "^5.0.0"
66
69
  },
67
70
  "peerDependenciesMeta": {
68
71
  "three": {
@@ -71,35 +74,40 @@
71
74
  },
72
75
  "dependencies": {
73
76
  "@floating-ui/dom": "^1.8.0",
74
- "@iconify/svelte": "^5.2.1",
75
- "@lucide/svelte": "^1.48.0",
77
+ "@fontsource-variable/hanken-grotesk": "^5.3.0",
78
+ "@iconify/svelte": "^5.2.4",
79
+ "@lucide/svelte": "^1.66.0",
76
80
  "clsx": "^2.1.1",
77
81
  "mode-watcher": "^1.1.0",
78
82
  "paneforge": "^1.0.2",
79
- "svelte-sonner": "^1.2.1",
83
+ "svelte-sonner": "^1.2.2",
80
84
  "tailwind-merge": "^3.7.0",
81
85
  "tw-animate-css": "^1.4.0"
82
86
  },
83
87
  "devDependencies": {
84
88
  "@internationalized/date": "^3.12.4",
85
- "@sveltejs/kit": "2.70.3",
89
+ "@sveltejs/kit": "3.1.1",
86
90
  "@sveltejs/vite-plugin-svelte": "^7.3.1",
87
- "@types/three": "^0.186.0",
88
- "bits-ui": "^2.19.3",
91
+ "@types/three": "^0.187.0",
92
+ "bits-ui": "^2.20.2",
89
93
  "rimraf": "^6.1.3",
90
- "svelte": "5.57.1",
94
+ "svelte": "5.57.3",
91
95
  "tailwind-variants": "^3.3.1",
92
- "vitest": "^5.0.2",
96
+ "vitest": "^5.0.5",
97
+ "@selvajs/compute": "5.0.0",
98
+ "@selvajs/schemas": "5.3.0",
93
99
  "@selvajs/config": "0.0.4",
94
- "@selvajs/solve": "2.0.0-beta.4",
95
- "@selvajs/visualization": "1.6.0-beta.0",
96
- "@selvajs/compute": "5.0.0-beta.2",
97
- "@selvajs/schemas": "5.3.0-beta.0"
100
+ "@selvajs/solve": "2.0.0",
101
+ "@selvajs/visualization": "1.6.0"
102
+ },
103
+ "imports": {
104
+ "#lib": "./src/lib/index.js",
105
+ "#lib/*": "./src/lib/*"
98
106
  },
99
107
  "scripts": {
100
- "predev": "node ../../scripts/sync-shared-assets.js",
108
+ "predev": "node ../../scripts/develop/sync-shared-assets.js",
101
109
  "dev": "vite dev",
102
- "prebuild": "node ../../scripts/sync-shared-assets.js",
110
+ "prebuild": "node ../../scripts/develop/sync-shared-assets.js",
103
111
  "build": "rimraf dist && pnpm prepack",
104
112
  "build:fast": "svelte-kit sync && svelte-package",
105
113
  "build:watch": "svelte-kit sync && svelte-package --watch",
@@ -3,7 +3,7 @@
3
3
  import * as Card from './primitives/card/index.js';
4
4
  import { Button } from './primitives/button/index.js';
5
5
  import Callout from './primitives/Callout.svelte';
6
- import { getLocaleContext } from '$lib/i18n/localeContext.svelte';
6
+ import { getLocaleContext } from '#lib/i18n/localeContext.svelte.js';
7
7
 
8
8
  interface Props {
9
9
  status?: number;
@@ -1,6 +1,7 @@
1
1
  <script lang="ts">
2
+ import type { Snippet } from 'svelte';
2
3
  import type { UISchema, SupportedTypes, ParameterPreset } from '@selvajs/schemas';
3
- import type { SolveSettlement } from '@selvajs/solve/client';
4
+ import type { LiveSolveState, SolveSettlement } from '@selvajs/solve/client';
4
5
  import type { ActionButton } from '../../types/actionButton';
5
6
  import type { PresetLabels } from '../../types/presetLabels';
6
7
  import { ChevronUp, Download, Ellipsis, Upload } from '@lucide/svelte';
@@ -10,9 +11,9 @@
10
11
  import SolvingIndicator from '../primitives/SolvingIndicator.svelte';
11
12
  import TabLayout from '../preview/TabLayout.svelte';
12
13
  import CollapsedPanelStrip from './CollapsedPanelStrip.svelte';
13
- import * as Resizable from '$lib/components/primitives/resizable';
14
- import * as DropdownMenu from '$lib/components/primitives/dropdown-menu/index.js';
15
- import { Button } from '$lib';
14
+ import * as Resizable from '#lib/components/primitives/resizable/index.js';
15
+ import * as DropdownMenu from '#lib/components/primitives/dropdown-menu/index.js';
16
+ import { Button } from '#lib';
16
17
  import ParameterPresetManager from './ParameterPresetManager.svelte';
17
18
  import { runPanelAction } from '../../compute/run-panel-action';
18
19
  import { getLocaleContext } from '../../i18n/localeContext.svelte';
@@ -33,7 +34,23 @@
33
34
  showViewer: boolean;
34
35
  meshes?: any[];
35
36
  isSolving: boolean;
37
+ /**
38
+ * `createSolvingIndicator(...).show`, not `isSolving`: grows the action row's solve status,
39
+ * which would otherwise flash on every sub-second solve.
40
+ */
36
41
  showSolvingIndicator?: boolean;
42
+ /** `createSolvingIndicator(...).slow`: the solve status grows into a card with progress. */
43
+ solveIsSlow?: boolean;
44
+ /** The session's live channel: step, count and bar for that card. */
45
+ live?: LiveSolveState;
46
+ /** Abort in that card. The host's `SolveMessages` should then take `progressShownByHost`. */
47
+ onabort?: () => void;
48
+ /** As passed to `createSolvingIndicator`. */
49
+ freezesDuringSolve?: boolean;
50
+ /** @deprecated Ignored: the solving status always sits in the action row. */
51
+ solvingIndicatorPlacement?: 'floating' | 'inline';
52
+ /** Rendered above the action row, for a host that keeps the solve's messages in the flow. */
53
+ solveMessages?: Snippet;
37
54
  hasPendingChanges?: boolean;
38
55
  hasNeverSolved?: boolean;
39
56
  isViewerFullscreen?: boolean;
@@ -63,6 +80,11 @@
63
80
  meshes = [],
64
81
  isSolving,
65
82
  showSolvingIndicator = false,
83
+ solveIsSlow = false,
84
+ live,
85
+ onabort,
86
+ freezesDuringSolve = false,
87
+ solveMessages,
66
88
  hasPendingChanges = false,
67
89
  hasNeverSolved = false,
68
90
  isViewerFullscreen = $bindable(false),
@@ -143,6 +165,14 @@
143
165
  return () => mqMobile.removeEventListener('change', update);
144
166
  });
145
167
 
168
+ // Without a viewer there's nothing to sit beside, so a narrow host (a docked Rhino panel) gets
169
+ // the phone's single edge-to-edge column instead of a card floating in its own margins.
170
+ const STACK_BELOW_WIDTH = 900;
171
+ let rootWidth = $state(0);
172
+ const stacked = $derived(
173
+ isMobile || (!hasViewer && rootWidth > 0 && rootWidth < STACK_BELOW_WIDTH)
174
+ );
175
+
146
176
  let leftCollapsed = $state(false);
147
177
  let rightCollapsed = $state(false);
148
178
  let leftPaneRef = $state<{ expand: () => void } | null>(null);
@@ -248,6 +278,9 @@
248
278
  <!-- One primary action and one menu. A definition that solves on every change has no Calculate,
249
279
  so the menu sits alone at the end of the row. -->
250
280
  {#snippet footer()}
281
+ <!-- No wrapper: it would always render (the messages' live region is never empty) and pick up
282
+ the drawer footer's row padding, leaving a gap above Calculate with nothing in it. -->
283
+ {@render solveMessages?.()}
251
284
  {#if schema.instanceSolve === false}
252
285
  <CalculateButton
253
286
  {hasPendingChanges}
@@ -256,9 +289,19 @@
256
289
  {oncalculate}
257
290
  trailing={hasMenu ? actionsMenu : undefined}
258
291
  />
259
- {:else if hasMenu}
260
- <div class="mt-3 pb-3 pt-2 px-2 flex justify-end border-t border-border/50">
261
- {@render actionsMenu()}
292
+ {:else}
293
+ <div class="mt-3 pb-3 pt-2 px-2 gap-2 flex items-center border-t border-border">
294
+ <SolvingIndicator
295
+ {isSolving}
296
+ show={showSolvingIndicator}
297
+ slow={solveIsSlow}
298
+ {live}
299
+ {onabort}
300
+ {freezesDuringSolve}
301
+ />
302
+ {#if hasMenu}
303
+ {@render actionsMenu()}
304
+ {/if}
262
305
  </div>
263
306
  {/if}
264
307
  {/snippet}
@@ -272,9 +315,9 @@
272
315
  )}
273
316
  <div class="panel-content-wrapper">
274
317
  {#if schema.layout.type === 'tabbed'}
275
- <TabLayout {schema} {values} {onValueChange} {panelFilter} {requestedTabId} />
318
+ <TabLayout {schema} {values} {onValueChange} {panelFilter} {requestedTabId} bare={stacked} />
276
319
  {/if}
277
- {#if hostsFooter && !isMobile}
320
+ {#if hostsFooter && !stacked}
278
321
  <div class="panel-footer px-1">
279
322
  {@render footer()}
280
323
  </div>
@@ -291,15 +334,16 @@
291
334
 
292
335
  <main
293
336
  data-layout-root
294
- class="min-h-0 sm:flex-row sm:py-(--page-py) flex flex-1 flex-col overflow-hidden {leftCollapsed
295
- ? 'sm:pl-0'
296
- : 'sm:pl-(--page-px)'} {rightCollapsed ? 'sm:pr-0' : 'sm:pr-(--page-px)'}"
337
+ class="min-h-0 flex flex-1 flex-col overflow-hidden {stacked
338
+ ? ''
339
+ : `sm:flex-row sm:py-2 ${leftCollapsed ? 'sm:pl-0' : 'sm:pl-2'} ${rightCollapsed ? 'sm:pr-0' : 'sm:pr-2'}`}"
297
340
  class:fullscreen-layout={isViewerFullscreen}
298
341
  class:relative={isMobile}
299
- class:mobile-root={isMobile}
342
+ class:mobile-root={stacked}
343
+ bind:clientWidth={rootWidth}
300
344
  >
301
- {#if isMobile}
302
- {#if hasViewer}
345
+ {#if stacked}
346
+ {#if isMobile && hasViewer}
303
347
  <!-- Ends above the drawer rather than behind it, so the model stays centred in what is
304
348
  visible. It jumps straight to its new size: animating it would resize the canvas,
305
349
  and its render targets, on every frame of the drawer's slide. -->
@@ -307,20 +351,20 @@
307
351
  <Viewer
308
352
  {meshes}
309
353
  bind:isFullscreen={isViewerFullscreen}
310
- {isSolving}
311
354
  drawerOpen={drawer === 'full'}
312
355
  {logoUrl}
313
356
  {onViewerReady}
314
357
  viewerConfig={{
315
358
  ...viewerConfig,
316
- backgroundColor: schema?.viewerOptions?.backgroundColor,
359
+ backgroundColor: schema?.viewerOptions?.backgroundColor ?? viewerConfig.backgroundColor,
360
+ look: schema?.viewerOptions?.look ?? viewerConfig.look,
317
361
  showSceneManager: false
318
362
  }}
319
363
  />
320
364
  </div>
321
365
 
322
366
  <div
323
- class="drawer-container rounded-t-2xl z-40 border-t bg-background shadow-sheet drawer-{drawer}"
367
+ class="drawer-container z-40 rounded-t-xl border-t bg-background shadow-sheet drawer-{drawer}"
324
368
  >
325
369
  <!-- Named by its visible label; aria-expanded carries the open/closed state. -->
326
370
  <button
@@ -344,7 +388,7 @@
344
388
  <!-- Inert while closed: the fields are clipped out of view, and tabbing into them
345
389
  would scroll the drawer's insides around behind the handle. -->
346
390
  <div class="drawer-content" inert={drawer === 'closed'}>
347
- <div class="px-3 pb-6">
391
+ <div class="px-2 pb-4">
348
392
  {#if hasLeftPanel}
349
393
  {@render panelContent(hasRightPanel ? 'left' : undefined, requestedLeftTabId, false)}
350
394
  {/if}
@@ -366,7 +410,7 @@
366
410
  </div>
367
411
  {:else}
368
412
  <div class="flex flex-1 flex-col overflow-hidden">
369
- <div class="px-3 pt-3 flex-1 overflow-y-auto">
413
+ <div class="px-3 pt-3 sm:px-5 flex-1 overflow-y-auto">
370
414
  {#if hasLeftPanel}
371
415
  {@render panelContent(hasRightPanel ? 'left' : undefined, requestedLeftTabId, false)}
372
416
  {/if}
@@ -386,7 +430,7 @@
386
430
  {/if}
387
431
  {:else if !hasViewer && !isTwoPanelMode && hasLeftPanel !== hasRightPanel}
388
432
  <!-- Single centered panel (left-only or right-only), no viewer -->
389
- <div class="min-h-0 flex h-full flex-1 justify-center">
433
+ <div class="min-h-0 p-1 flex h-full flex-1 justify-center">
390
434
  <div class="min-h-0 flex h-full w-4/5 flex-col">
391
435
  {@render panelContent(
392
436
  hasRightPanel ? 'right' : undefined,
@@ -413,7 +457,7 @@
413
457
  <Resizable.PaneGroup
414
458
  direction="horizontal"
415
459
  autoSaveId="selva-layout-{layoutKey}"
416
- class="min-h-0 flex-1"
460
+ class="min-h-0 m-1 flex-1"
417
461
  >
418
462
  {#if hasLeftPanel}
419
463
  <Resizable.Pane
@@ -426,7 +470,6 @@
426
470
  collapsedSize={0}
427
471
  onCollapse={() => (leftCollapsed = true)}
428
472
  onExpand={() => (leftCollapsed = false)}
429
- class="ml-1"
430
473
  >
431
474
  <div
432
475
  class="min-h-0 flex h-full flex-col {isViewerFullscreen || leftCollapsed
@@ -439,6 +482,7 @@
439
482
  <Resizable.Handle
440
483
  withHandle
441
484
  line={false}
485
+ class="translate-x-1.5 z-20"
442
486
  data-collapsed={leftCollapsed}
443
487
  onclick={() => {
444
488
  if (leftCollapsed) leftPaneRef?.expand();
@@ -447,30 +491,34 @@
447
491
  {/if}
448
492
 
449
493
  {#if hasViewer}
450
- <Resizable.Pane order={2} minSize={20} class="min-h-0 mx-1 flex flex-col">
494
+ <Resizable.Pane order={2} minSize={20} class="min-h-0 flex flex-col">
451
495
  <Viewer
452
496
  {meshes}
453
497
  bind:isFullscreen={isViewerFullscreen}
454
- {isSolving}
455
498
  {logoUrl}
456
499
  {onViewerReady}
457
500
  viewerConfig={{
458
501
  ...viewerConfig,
459
- backgroundColor: schema?.viewerOptions?.backgroundColor
502
+ backgroundColor:
503
+ schema?.viewerOptions?.backgroundColor ?? viewerConfig.backgroundColor,
504
+ look: schema?.viewerOptions?.look ?? viewerConfig.look
460
505
  }}
461
506
  />
462
507
  </Resizable.Pane>
463
508
  {/if}
464
509
 
465
510
  {#if hasRightPanel}
466
- <Resizable.Handle
467
- withHandle
468
- line={false}
469
- data-collapsed={rightCollapsed}
470
- onclick={() => {
471
- if (rightCollapsed) rightPaneRef?.expand();
472
- }}
473
- />
511
+ {#if hasViewer || !hasLeftPanel}
512
+ <Resizable.Handle
513
+ withHandle
514
+ line={false}
515
+ class="-translate-x-1.5 z-20"
516
+ data-collapsed={rightCollapsed}
517
+ onclick={() => {
518
+ if (rightCollapsed) rightPaneRef?.expand();
519
+ }}
520
+ />
521
+ {/if}
474
522
  <Resizable.Pane
475
523
  bind:this={rightPaneRef}
476
524
  order={3}
@@ -481,7 +529,6 @@
481
529
  collapsedSize={0}
482
530
  onCollapse={() => (rightCollapsed = true)}
483
531
  onExpand={() => (rightCollapsed = false)}
484
- class="mr-1"
485
532
  >
486
533
  <div
487
534
  class="min-h-0 flex h-full flex-col {isViewerFullscreen || rightCollapsed
@@ -508,8 +555,6 @@
508
555
  {/if}
509
556
  </div>
510
557
  {/if}
511
-
512
- <SolvingIndicator show={showSolvingIndicator} />
513
558
  </main>
514
559
 
515
560
  <!-- The save, load and validation dialogs; the footer's menu opens them. -->
@@ -555,7 +600,13 @@
555
600
 
556
601
  .mobile-root {
557
602
  --drawer-closed-h: 60px;
558
- --drawer-half-h: 50%;
603
+ --drawer-half-h: 60%;
604
+ }
605
+
606
+ /* On a phone the panels stack in one scroller. Held at the scroller's height, a long left
607
+ panel would spill over the right panel below it. */
608
+ .mobile-root .panel-content-wrapper {
609
+ height: auto;
559
610
  }
560
611
 
561
612
  .viewer-region {
@@ -633,6 +684,13 @@
633
684
  padding: 0rem 1rem;
634
685
  }
635
686
 
687
+ /* The sheet's top edge already separates it from the model; the desktop footer's extra
688
+ spacing only takes rows from the fields. */
689
+ .drawer-footer :global(> div) {
690
+ margin-top: 0;
691
+ padding-block: 0.5rem;
692
+ }
693
+
636
694
  /* Touch gets 44px targets on the panel's controls; a fine pointer keeps the denser sizes. */
637
695
  @media (pointer: coarse) {
638
696
  .panel-content-wrapper
@@ -20,12 +20,14 @@
20
20
  [
21
21
  'gap-1 py-2 lg:py-3 lg:flex-col lg:w-auto px-2 lg:px-0',
22
22
  'flex w-full shrink-0 flex-row items-center',
23
- 'backdrop-blur-sm bg-background/90 cursor-pointer'
23
+ 'backdrop-blur-sm bg-background/90 cursor-pointer',
24
+ side === 'left' ? 'lg:border-r' : 'lg:border-l',
25
+ 'border-border'
24
26
  ].join(' ')
25
27
  );
26
28
 
27
29
  const tabButtonClass =
28
- 'w-8 h-8 rounded cursor-pointer flex shrink-0 items-center justify-center text-muted-foreground transition-colors hover:bg-accent hover:text-foreground';
30
+ 'w-8 h-8 rounded-md cursor-pointer flex shrink-0 items-center justify-center text-muted-foreground transition-colors hover:bg-hover hover:text-foreground';
29
31
  </script>
30
32
 
31
33
  <div
@@ -57,7 +57,7 @@
57
57
  footerText?: string;
58
58
  /**
59
59
  * How long one solve may take before the client aborts it (ms). Pass the same value the
60
- * server enforces (`COMPUTE_SOLVE_DEADLINE_MS`), or the client aborts solves that would
60
+ * server enforces for this definition's compute server, or the client aborts solves that would
61
61
  * have finished.
62
62
  */
63
63
  solveDeadlineMs: number;
@@ -286,7 +286,10 @@
286
286
  showViewer={!!schema.viewerOptions?.enableRemote}
287
287
  meshes={session.meshes}
288
288
  isSolving={session.isSolving}
289
- showSolvingIndicator={schema.instanceSolve !== false && solvingIndicator.show}
289
+ showSolvingIndicator={solvingIndicator.show}
290
+ solveIsSlow={solvingIndicator.slow}
291
+ live={session.live}
292
+ onabort={() => session.abort()}
290
293
  hasPendingChanges={session.hasPendingChanges}
291
294
  hasNeverSolved={session.hasNeverSolved}
292
295
  bind:isViewerFullscreen
@@ -317,4 +320,5 @@
317
320
  onabort={() => session.abort()}
318
321
  onconfirm={() => session.acknowledge()}
319
322
  ondiscard={() => session.discard()}
323
+ progressShownByHost={schema?.instanceSolve !== false}
320
324
  />
@@ -8,10 +8,10 @@
8
8
 
9
9
  import type { Snippet } from 'svelte';
10
10
  import type { SolveDiagnostic } from '@selvajs/solve/shared';
11
- import * as Dialog from '$lib/components/primitives/dialog';
12
- import IssueList, { type Issue } from '$lib/components/primitives/IssueList.svelte';
13
- import { getLocaleContext } from '$lib/i18n/localeContext.svelte';
14
- import { formatCount } from '$lib/i18n/messages';
11
+ import * as Dialog from '#lib/components/primitives/dialog/index.js';
12
+ import IssueList, { type Issue } from '#lib/components/primitives/IssueList.svelte';
13
+ import { getLocaleContext } from '#lib/i18n/localeContext.svelte.js';
14
+ import { formatCount } from '#lib/i18n/messages.js';
15
15
 
16
16
  interface Props {
17
17
  /** The last solve's messages. Preferred over `errors`/`warnings` when both are given. */