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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (444) hide show
  1. package/dist/components/ConfirmDialog.svelte +2 -10
  2. package/dist/components/ErrorScreen.svelte +21 -27
  3. package/dist/components/compute/AppLayout.svelte +286 -116
  4. package/dist/components/compute/AppLayout.svelte.d.ts +22 -0
  5. package/dist/components/compute/ComputeApp.svelte +45 -24
  6. package/dist/components/compute/ComputeApp.svelte.d.ts +19 -2
  7. package/dist/components/compute/ComputeMessagesDialog.svelte +47 -83
  8. package/dist/components/compute/ParameterPresetManager.svelte +37 -130
  9. package/dist/components/compute/ParameterPresetManager.svelte.d.ts +4 -5
  10. package/dist/components/compute/SolveMessages.svelte +131 -77
  11. package/dist/components/compute/SolveMessages.svelte.d.ts +7 -12
  12. package/dist/components/layout/AppShell.svelte +10 -6
  13. package/dist/components/layout/PageFooter.svelte +23 -11
  14. package/dist/components/layout/PageHeader.svelte +11 -7
  15. package/dist/components/layout/Pagination.svelte +2 -4
  16. package/dist/components/layout/SectionHeader.svelte +4 -2
  17. package/dist/components/layout/SideNav.svelte +56 -7
  18. package/dist/components/preview/ChartOutput.svelte +35 -25
  19. package/dist/components/preview/Group.svelte +92 -103
  20. package/dist/components/preview/Group.svelte.d.ts +1 -1
  21. package/dist/components/preview/HelpButton.svelte +36 -0
  22. package/dist/components/preview/HelpButton.svelte.d.ts +8 -0
  23. package/dist/components/preview/ImageOutput.svelte +430 -71
  24. package/dist/components/preview/InputControl.svelte +163 -90
  25. package/dist/components/preview/InputControl.svelte.d.ts +5 -1
  26. package/dist/components/preview/OutputDisplay.svelte +28 -33
  27. package/dist/components/preview/TabBar.svelte +106 -22
  28. package/dist/components/preview/TabBar.svelte.d.ts +1 -0
  29. package/dist/components/preview/TabContent.svelte +63 -57
  30. package/dist/components/preview/TabContent.svelte.d.ts +5 -1
  31. package/dist/components/preview/TabLayout.svelte +27 -5
  32. package/dist/components/preview/TabLayout.svelte.d.ts +5 -0
  33. package/dist/components/preview/inputs/CheckboxInput.svelte +7 -7
  34. package/dist/components/preview/inputs/CheckboxInput.svelte.d.ts +3 -0
  35. package/dist/components/preview/inputs/ChecklistInput.svelte +7 -2
  36. package/dist/components/preview/inputs/ChecklistInput.svelte.d.ts +2 -1
  37. package/dist/components/preview/inputs/ColorInput.svelte +4 -2
  38. package/dist/components/preview/inputs/ColorInput.svelte.d.ts +1 -0
  39. package/dist/components/preview/inputs/DropdownInput.svelte +19 -4
  40. package/dist/components/preview/inputs/DropdownInput.svelte.d.ts +2 -1
  41. package/dist/components/preview/inputs/FileInput.svelte +112 -108
  42. package/dist/components/preview/inputs/GeometryInput.svelte +128 -0
  43. package/dist/components/preview/inputs/GeometryInput.svelte.d.ts +21 -0
  44. package/dist/components/preview/inputs/NumberInput.svelte +123 -61
  45. package/dist/components/preview/inputs/NumberInput.svelte.d.ts +2 -0
  46. package/dist/components/preview/inputs/OptionGlyph.svelte +29 -0
  47. package/dist/components/preview/inputs/OptionGlyph.svelte.d.ts +8 -0
  48. package/dist/components/preview/inputs/SegmentedInput.svelte +44 -0
  49. package/dist/components/preview/inputs/SegmentedInput.svelte.d.ts +12 -0
  50. package/dist/components/preview/inputs/TextInput.svelte +8 -4
  51. package/dist/components/preview/inputs/TileInput.svelte +80 -0
  52. package/dist/components/preview/inputs/TileInput.svelte.d.ts +12 -0
  53. package/dist/components/preview/inputs/index.d.ts +3 -0
  54. package/dist/components/preview/inputs/index.js +3 -0
  55. package/dist/components/primitives/CalculateButton.svelte +56 -24
  56. package/dist/components/primitives/CalculateButton.svelte.d.ts +3 -0
  57. package/dist/components/primitives/Callout.svelte +11 -18
  58. package/dist/components/primitives/DataTable.svelte +38 -5
  59. package/dist/components/primitives/DataTable.svelte.d.ts +2 -0
  60. package/dist/components/primitives/FilterableDropdown.svelte +42 -129
  61. package/dist/components/primitives/FilterableDropdown.svelte.d.ts +1 -1
  62. package/dist/components/primitives/IssueList.svelte +56 -0
  63. package/dist/components/primitives/IssueList.svelte.d.ts +20 -0
  64. package/dist/components/primitives/SeverityIcon.svelte +15 -0
  65. package/dist/components/primitives/SeverityIcon.svelte.d.ts +8 -0
  66. package/dist/components/primitives/SolvingIndicator.svelte +43 -42
  67. package/dist/components/primitives/SolvingIndicator.svelte.d.ts +6 -0
  68. package/dist/components/primitives/StateDisplay.svelte +19 -79
  69. package/dist/components/primitives/ViewToggle.svelte +18 -33
  70. package/dist/components/primitives/alert-dialog/alert-dialog-action.svelte +9 -3
  71. package/dist/components/primitives/alert-dialog/alert-dialog-action.svelte.d.ts +6 -1
  72. package/dist/components/primitives/alert-dialog/alert-dialog-content.svelte +1 -1
  73. package/dist/components/primitives/alert-dialog/alert-dialog-overlay.svelte +1 -1
  74. package/dist/components/primitives/badge/badge.svelte +2 -2
  75. package/dist/components/primitives/badge/badge.svelte.d.ts +4 -4
  76. package/dist/components/primitives/button/button.svelte +6 -2
  77. package/dist/components/primitives/button/button.svelte.d.ts +10 -4
  78. package/dist/components/primitives/card/card-header.svelte +1 -1
  79. package/dist/components/primitives/card/card.svelte +21 -5
  80. package/dist/components/primitives/card/card.svelte.d.ts +25 -1
  81. package/dist/components/primitives/card/index.d.ts +1 -2
  82. package/dist/components/primitives/card/index.js +2 -3
  83. package/dist/components/primitives/checkbox/checkbox.svelte +1 -1
  84. package/dist/components/primitives/command/command-dialog.svelte +42 -0
  85. package/dist/components/primitives/command/command-dialog.svelte.d.ts +14 -0
  86. package/dist/components/primitives/command/command-empty.svelte +17 -0
  87. package/dist/components/primitives/command/command-empty.svelte.d.ts +4 -0
  88. package/dist/components/primitives/command/command-group.svelte +33 -0
  89. package/dist/components/primitives/command/command-group.svelte.d.ts +7 -0
  90. package/dist/components/primitives/command/command-input.svelte +36 -0
  91. package/dist/components/primitives/command/command-input.svelte.d.ts +4 -0
  92. package/dist/components/primitives/command/command-item.svelte +28 -0
  93. package/dist/components/primitives/command/command-item.svelte.d.ts +4 -0
  94. package/dist/components/primitives/command/command-link-item.svelte +21 -0
  95. package/dist/components/primitives/command/command-link-item.svelte.d.ts +4 -0
  96. package/dist/components/primitives/command/command-list.svelte +20 -0
  97. package/dist/components/primitives/command/command-list.svelte.d.ts +4 -0
  98. package/dist/components/primitives/command/command-loading.svelte +7 -0
  99. package/dist/components/primitives/command/command-loading.svelte.d.ts +4 -0
  100. package/dist/components/primitives/command/command-separator.svelte +17 -0
  101. package/dist/components/primitives/command/command-separator.svelte.d.ts +4 -0
  102. package/dist/components/primitives/command/command-shortcut.svelte +23 -0
  103. package/dist/components/primitives/command/command-shortcut.svelte.d.ts +5 -0
  104. package/dist/components/primitives/command/command.svelte +28 -0
  105. package/dist/components/primitives/command/command.svelte.d.ts +8 -0
  106. package/dist/components/primitives/command/index.d.ts +12 -0
  107. package/dist/components/primitives/command/index.js +14 -0
  108. package/dist/components/primitives/context-menu/context-menu-content.svelte +1 -1
  109. package/dist/components/primitives/context-menu/context-menu-sub-content.svelte +1 -1
  110. package/dist/components/primitives/dialog/dialog-content.svelte +11 -3
  111. package/dist/components/primitives/dialog/dialog-content.svelte.d.ts +2 -0
  112. package/dist/components/primitives/dialog/dialog-overlay.svelte +1 -1
  113. package/dist/components/primitives/dialog/dialog-title.svelte +6 -2
  114. package/dist/components/primitives/dialog/dialog-title.svelte.d.ts +5 -1
  115. package/dist/components/primitives/drawer/Drawer.svelte +2 -2
  116. package/dist/components/primitives/dropdown-menu/dropdown-menu-checkbox-group.svelte +16 -0
  117. package/dist/components/primitives/dropdown-menu/dropdown-menu-checkbox-group.svelte.d.ts +4 -0
  118. package/dist/components/primitives/dropdown-menu/dropdown-menu-checkbox-item.svelte +46 -0
  119. package/dist/components/primitives/dropdown-menu/dropdown-menu-checkbox-item.svelte.d.ts +9 -0
  120. package/dist/components/primitives/dropdown-menu/dropdown-menu-content.svelte +31 -0
  121. package/dist/components/primitives/dropdown-menu/dropdown-menu-content.svelte.d.ts +10 -0
  122. package/dist/components/primitives/dropdown-menu/dropdown-menu-group-heading.svelte +22 -0
  123. package/dist/components/primitives/dropdown-menu/dropdown-menu-group-heading.svelte.d.ts +8 -0
  124. package/dist/components/primitives/dropdown-menu/dropdown-menu-group.svelte +7 -0
  125. package/dist/components/primitives/dropdown-menu/dropdown-menu-group.svelte.d.ts +4 -0
  126. package/dist/components/primitives/dropdown-menu/dropdown-menu-item.svelte +27 -0
  127. package/dist/components/primitives/dropdown-menu/dropdown-menu-item.svelte.d.ts +8 -0
  128. package/dist/components/primitives/dropdown-menu/dropdown-menu-label.svelte +24 -0
  129. package/dist/components/primitives/dropdown-menu/dropdown-menu-label.svelte.d.ts +8 -0
  130. package/dist/components/primitives/dropdown-menu/dropdown-menu-portal.svelte +7 -0
  131. package/dist/components/primitives/dropdown-menu/dropdown-menu-portal.svelte.d.ts +3 -0
  132. package/dist/components/primitives/dropdown-menu/dropdown-menu-radio-group.svelte +16 -0
  133. package/dist/components/primitives/dropdown-menu/dropdown-menu-radio-group.svelte.d.ts +4 -0
  134. package/dist/components/primitives/dropdown-menu/dropdown-menu-radio-item.svelte +36 -0
  135. package/dist/components/primitives/dropdown-menu/dropdown-menu-radio-item.svelte.d.ts +4 -0
  136. package/dist/components/primitives/dropdown-menu/dropdown-menu-separator.svelte +17 -0
  137. package/dist/components/primitives/dropdown-menu/dropdown-menu-separator.svelte.d.ts +4 -0
  138. package/dist/components/primitives/dropdown-menu/dropdown-menu-shortcut.svelte +23 -0
  139. package/dist/components/primitives/dropdown-menu/dropdown-menu-shortcut.svelte.d.ts +5 -0
  140. package/dist/components/primitives/dropdown-menu/dropdown-menu-sub-content.svelte +31 -0
  141. package/dist/components/primitives/dropdown-menu/dropdown-menu-sub-content.svelte.d.ts +10 -0
  142. package/dist/components/primitives/dropdown-menu/dropdown-menu-sub-trigger.svelte +29 -0
  143. package/dist/components/primitives/dropdown-menu/dropdown-menu-sub-trigger.svelte.d.ts +7 -0
  144. package/dist/components/primitives/dropdown-menu/dropdown-menu-sub.svelte +7 -0
  145. package/dist/components/primitives/dropdown-menu/dropdown-menu-sub.svelte.d.ts +3 -0
  146. package/dist/components/primitives/dropdown-menu/dropdown-menu-trigger.svelte +7 -0
  147. package/dist/components/primitives/dropdown-menu/dropdown-menu-trigger.svelte.d.ts +4 -0
  148. package/dist/components/primitives/dropdown-menu/dropdown-menu.svelte +7 -0
  149. package/dist/components/primitives/dropdown-menu/dropdown-menu.svelte.d.ts +3 -0
  150. package/dist/components/primitives/dropdown-menu/index.d.ts +18 -0
  151. package/dist/components/primitives/dropdown-menu/index.js +18 -0
  152. package/dist/components/primitives/{alert/alert-description.svelte → empty/empty-content.svelte} +3 -3
  153. package/dist/components/primitives/empty/empty-content.svelte.d.ts +5 -0
  154. package/dist/components/primitives/empty/empty-description.svelte +23 -0
  155. package/dist/components/primitives/{alert/alert-description.svelte.d.ts → empty/empty-description.svelte.d.ts} +4 -4
  156. package/dist/components/primitives/{alert/alert-title.svelte → empty/empty-header.svelte} +3 -3
  157. package/dist/components/primitives/empty/empty-header.svelte.d.ts +5 -0
  158. package/dist/components/primitives/empty/empty-media.svelte +41 -0
  159. package/dist/components/primitives/empty/empty-media.svelte.d.ts +26 -0
  160. package/dist/components/primitives/{card/card-action.svelte → empty/empty-title.svelte} +2 -2
  161. package/dist/components/primitives/{card/card-action.svelte.d.ts → empty/empty-title.svelte.d.ts} +3 -3
  162. package/dist/components/primitives/empty/empty.svelte +23 -0
  163. package/dist/components/primitives/empty/empty.svelte.d.ts +5 -0
  164. package/dist/components/primitives/empty/index.d.ts +7 -0
  165. package/dist/components/primitives/empty/index.js +9 -0
  166. package/dist/components/primitives/index.d.ts +10 -1
  167. package/dist/components/primitives/index.js +10 -1
  168. package/dist/components/primitives/input/input.svelte +4 -4
  169. package/dist/components/primitives/input-group/index.d.ts +7 -0
  170. package/dist/components/primitives/input-group/index.js +9 -0
  171. package/dist/components/primitives/input-group/input-group-addon.svelte +53 -0
  172. package/dist/components/primitives/input-group/input-group-addon.svelte.d.ts +32 -0
  173. package/dist/components/primitives/input-group/input-group-button.svelte +49 -0
  174. package/dist/components/primitives/input-group/input-group-button.svelte.d.ts +32 -0
  175. package/dist/components/primitives/input-group/input-group-input.svelte +25 -0
  176. package/dist/components/primitives/input-group/input-group-input.svelte.d.ts +11 -0
  177. package/dist/components/primitives/input-group/input-group-text.svelte +22 -0
  178. package/dist/components/primitives/input-group/input-group-text.svelte.d.ts +5 -0
  179. package/dist/components/primitives/input-group/input-group-textarea.svelte +23 -0
  180. package/dist/components/primitives/input-group/input-group-textarea.svelte.d.ts +3 -0
  181. package/dist/components/primitives/input-group/input-group.svelte +24 -0
  182. package/dist/components/primitives/{alert/alert-title.svelte.d.ts → input-group/input-group.svelte.d.ts} +4 -4
  183. package/dist/components/primitives/mode-toggle/mode-toggle.svelte +6 -7
  184. package/dist/components/primitives/popover/index.d.ts +9 -0
  185. package/dist/components/primitives/popover/index.js +11 -0
  186. package/dist/components/primitives/popover/popover-close.svelte +7 -0
  187. package/dist/components/primitives/popover/popover-close.svelte.d.ts +4 -0
  188. package/dist/components/primitives/popover/popover-content.svelte +31 -0
  189. package/dist/components/primitives/popover/popover-content.svelte.d.ts +10 -0
  190. package/dist/components/primitives/popover/popover-description.svelte +20 -0
  191. package/dist/components/primitives/popover/popover-description.svelte.d.ts +5 -0
  192. package/dist/components/primitives/popover/popover-header.svelte +20 -0
  193. package/dist/components/primitives/popover/popover-header.svelte.d.ts +5 -0
  194. package/dist/components/primitives/popover/popover-portal.svelte +7 -0
  195. package/dist/components/primitives/popover/popover-portal.svelte.d.ts +3 -0
  196. package/dist/components/primitives/popover/popover-title.svelte +15 -0
  197. package/dist/components/primitives/popover/popover-title.svelte.d.ts +5 -0
  198. package/dist/components/primitives/popover/popover-trigger.svelte +17 -0
  199. package/dist/components/primitives/popover/popover-trigger.svelte.d.ts +4 -0
  200. package/dist/components/primitives/popover/popover.svelte +7 -0
  201. package/dist/components/primitives/popover/popover.svelte.d.ts +3 -0
  202. package/dist/components/primitives/resizable/resizable-handle.svelte +6 -2
  203. package/dist/components/primitives/resizable/resizable-handle.svelte.d.ts +2 -0
  204. package/dist/components/primitives/resizable/resizable-pane-group.svelte +1 -4
  205. package/dist/components/primitives/scroll-area/scroll-area.svelte +1 -1
  206. package/dist/components/primitives/search/search.svelte +3 -3
  207. package/dist/components/primitives/select/select-content.svelte +1 -1
  208. package/dist/components/primitives/select/select-trigger.svelte +1 -1
  209. package/dist/components/primitives/severity.d.ts +7 -0
  210. package/dist/components/primitives/severity.js +19 -0
  211. package/dist/components/primitives/slider/slider.svelte +8 -3
  212. package/dist/components/primitives/slider/slider.svelte.d.ts +5 -1
  213. package/dist/components/primitives/sonner/sonner.svelte +1 -1
  214. package/dist/components/primitives/spinner/index.d.ts +1 -0
  215. package/dist/components/primitives/spinner/index.js +1 -0
  216. package/dist/components/primitives/spinner/spinner.svelte +29 -0
  217. package/dist/components/primitives/spinner/spinner.svelte.d.ts +4 -0
  218. package/dist/components/primitives/switch/switch.svelte +2 -2
  219. package/dist/components/primitives/tabs/tabs-list.svelte +27 -5
  220. package/dist/components/primitives/tabs/tabs-list.svelte.d.ts +22 -1
  221. package/dist/components/primitives/tabs/tabs-trigger.svelte +23 -5
  222. package/dist/components/primitives/tabs/tabs-trigger.svelte.d.ts +22 -1
  223. package/dist/components/primitives/tabs/tabs.svelte +6 -2
  224. package/dist/components/primitives/tabs/tabs.svelte.d.ts +5 -1
  225. package/dist/components/primitives/textarea/textarea.svelte +1 -1
  226. package/dist/components/primitives/theme-switcher/ThemeSwitcher.svelte +1 -1
  227. package/dist/components/primitives/toggle/index.d.ts +3 -0
  228. package/dist/components/primitives/toggle/index.js +5 -0
  229. package/dist/components/primitives/toggle/toggle.svelte +54 -0
  230. package/dist/components/primitives/toggle/toggle.svelte.d.ts +46 -0
  231. package/dist/components/primitives/toggle-group/index.d.ts +3 -0
  232. package/dist/components/primitives/toggle-group/index.js +5 -0
  233. package/dist/components/primitives/toggle-group/toggle-group-item.svelte +35 -0
  234. package/dist/components/primitives/toggle-group/toggle-group-item.svelte.d.ts +6 -0
  235. package/dist/components/primitives/toggle-group/toggle-group.svelte +75 -0
  236. package/dist/components/primitives/toggle-group/toggle-group.svelte.d.ts +17 -0
  237. package/dist/components/viewer/MeshMetadataPanel.svelte +119 -0
  238. package/dist/components/viewer/MeshMetadataPanel.svelte.d.ts +9 -0
  239. package/dist/components/viewer/SceneManager.svelte +14 -5
  240. package/dist/components/viewer/Viewer.svelte +243 -221
  241. package/dist/components/viewer/Viewer.svelte.d.ts +3 -0
  242. package/dist/compute/run-panel-action.d.ts +8 -0
  243. package/dist/compute/run-panel-action.js +12 -0
  244. package/dist/compute/solving.svelte.d.ts +11 -7
  245. package/dist/compute/solving.svelte.js +64 -45
  246. package/dist/compute/useSolveSession.svelte.js +3 -0
  247. package/dist/constants.d.ts +6 -8
  248. package/dist/constants.js +7 -9
  249. package/dist/contexts/hostContext.svelte.d.ts +39 -0
  250. package/dist/contexts/hostContext.svelte.js +9 -0
  251. package/dist/i18n/localeContext.svelte.d.ts +10 -3
  252. package/dist/i18n/localeContext.svelte.js +27 -5
  253. package/dist/i18n/messages.d.ts +150 -2
  254. package/dist/i18n/messages.js +261 -11
  255. package/dist/index.d.ts +4 -1
  256. package/dist/index.js +3 -0
  257. package/dist/public.d.ts +1 -1
  258. package/dist/schema/host-support.d.ts +29 -0
  259. package/dist/schema/host-support.js +97 -0
  260. package/dist/schema/option-display.d.ts +12 -0
  261. package/dist/schema/option-display.js +29 -0
  262. package/dist/schema/param-exporter.d.ts +4 -1
  263. package/dist/schema/param-exporter.js +10 -6
  264. package/dist/schema/visibility-rules.js +21 -0
  265. package/dist/styles/base.css +80 -10
  266. package/dist/types/actionButton.d.ts +17 -3
  267. package/dist/types/presetLabels.d.ts +3 -2
  268. package/dist/types/presetLabels.js +9 -8
  269. package/dist/utils/file-download.js +10 -22
  270. package/dist/utils/host-files.d.ts +12 -0
  271. package/dist/utils/host-files.js +46 -0
  272. package/dist/utils/loadScript.d.ts +2 -0
  273. package/dist/utils/loadScript.js +2 -0
  274. package/dist/utils/webp-to-png.d.ts +10 -0
  275. package/dist/utils/webp-to-png.js +41 -0
  276. package/package.json +14 -14
  277. package/src/lib/components/ConfirmDialog.svelte +2 -10
  278. package/src/lib/components/ErrorScreen.svelte +21 -27
  279. package/src/lib/components/compute/AppLayout.svelte +286 -116
  280. package/src/lib/components/compute/ComputeApp.svelte +45 -24
  281. package/src/lib/components/compute/ComputeMessagesDialog.svelte +47 -83
  282. package/src/lib/components/compute/ParameterPresetManager.svelte +37 -130
  283. package/src/lib/components/compute/SolveMessages.svelte +131 -77
  284. package/src/lib/components/layout/AppShell.svelte +10 -6
  285. package/src/lib/components/layout/PageFooter.svelte +23 -11
  286. package/src/lib/components/layout/PageHeader.svelte +11 -7
  287. package/src/lib/components/layout/Pagination.svelte +2 -4
  288. package/src/lib/components/layout/SectionHeader.svelte +4 -2
  289. package/src/lib/components/layout/SideNav.svelte +56 -7
  290. package/src/lib/components/preview/ChartOutput.svelte +35 -25
  291. package/src/lib/components/preview/Group.svelte +92 -103
  292. package/src/lib/components/preview/HelpButton.svelte +36 -0
  293. package/src/lib/components/preview/ImageOutput.svelte +430 -71
  294. package/src/lib/components/preview/InputControl.svelte +163 -90
  295. package/src/lib/components/preview/OutputDisplay.svelte +28 -33
  296. package/src/lib/components/preview/TabBar.svelte +106 -22
  297. package/src/lib/components/preview/TabContent.svelte +63 -57
  298. package/src/lib/components/preview/TabLayout.svelte +27 -5
  299. package/src/lib/components/preview/inputs/CheckboxInput.svelte +7 -7
  300. package/src/lib/components/preview/inputs/ChecklistInput.svelte +7 -2
  301. package/src/lib/components/preview/inputs/ColorInput.svelte +4 -2
  302. package/src/lib/components/preview/inputs/DropdownInput.svelte +19 -4
  303. package/src/lib/components/preview/inputs/FileInput.svelte +112 -108
  304. package/src/lib/components/preview/inputs/GeometryInput.svelte +128 -0
  305. package/src/lib/components/preview/inputs/NumberInput.svelte +123 -61
  306. package/src/lib/components/preview/inputs/OptionGlyph.svelte +29 -0
  307. package/src/lib/components/preview/inputs/SegmentedInput.svelte +44 -0
  308. package/src/lib/components/preview/inputs/TextInput.svelte +8 -4
  309. package/src/lib/components/preview/inputs/TileInput.svelte +80 -0
  310. package/src/lib/components/preview/inputs/index.ts +3 -0
  311. package/src/lib/components/primitives/CalculateButton.svelte +56 -24
  312. package/src/lib/components/primitives/Callout.svelte +11 -18
  313. package/src/lib/components/primitives/DataTable.svelte +38 -5
  314. package/src/lib/components/primitives/FilterableDropdown.svelte +42 -129
  315. package/src/lib/components/primitives/IssueList.svelte +56 -0
  316. package/src/lib/components/primitives/SeverityIcon.svelte +15 -0
  317. package/src/lib/components/primitives/SolvingIndicator.svelte +43 -42
  318. package/src/lib/components/primitives/StateDisplay.svelte +19 -79
  319. package/src/lib/components/primitives/ViewToggle.svelte +18 -33
  320. package/src/lib/components/primitives/alert-dialog/alert-dialog-action.svelte +9 -3
  321. package/src/lib/components/primitives/alert-dialog/alert-dialog-content.svelte +1 -1
  322. package/src/lib/components/primitives/alert-dialog/alert-dialog-overlay.svelte +1 -1
  323. package/src/lib/components/primitives/badge/badge.svelte +2 -2
  324. package/src/lib/components/primitives/button/button.svelte +6 -2
  325. package/src/lib/components/primitives/card/card-header.svelte +1 -1
  326. package/src/lib/components/primitives/card/card.svelte +21 -5
  327. package/src/lib/components/primitives/card/index.ts +1 -4
  328. package/src/lib/components/primitives/checkbox/checkbox.svelte +1 -1
  329. package/src/lib/components/primitives/command/command-dialog.svelte +42 -0
  330. package/src/lib/components/primitives/command/command-empty.svelte +17 -0
  331. package/src/lib/components/primitives/command/command-group.svelte +33 -0
  332. package/src/lib/components/primitives/command/command-input.svelte +36 -0
  333. package/src/lib/components/primitives/command/command-item.svelte +28 -0
  334. package/src/lib/components/primitives/command/command-link-item.svelte +21 -0
  335. package/src/lib/components/primitives/command/command-list.svelte +20 -0
  336. package/src/lib/components/primitives/command/command-loading.svelte +7 -0
  337. package/src/lib/components/primitives/command/command-separator.svelte +17 -0
  338. package/src/lib/components/primitives/command/command-shortcut.svelte +23 -0
  339. package/src/lib/components/primitives/command/command.svelte +28 -0
  340. package/src/lib/components/primitives/command/index.ts +37 -0
  341. package/src/lib/components/primitives/context-menu/context-menu-content.svelte +1 -1
  342. package/src/lib/components/primitives/context-menu/context-menu-sub-content.svelte +1 -1
  343. package/src/lib/components/primitives/dialog/dialog-content.svelte +11 -3
  344. package/src/lib/components/primitives/dialog/dialog-overlay.svelte +1 -1
  345. package/src/lib/components/primitives/dialog/dialog-title.svelte +6 -2
  346. package/src/lib/components/primitives/drawer/Drawer.svelte +2 -2
  347. package/src/lib/components/primitives/dropdown-menu/dropdown-menu-checkbox-group.svelte +16 -0
  348. package/src/lib/components/primitives/dropdown-menu/dropdown-menu-checkbox-item.svelte +46 -0
  349. package/src/lib/components/primitives/dropdown-menu/dropdown-menu-content.svelte +31 -0
  350. package/src/lib/components/primitives/dropdown-menu/dropdown-menu-group-heading.svelte +22 -0
  351. package/src/lib/components/primitives/dropdown-menu/dropdown-menu-group.svelte +7 -0
  352. package/src/lib/components/primitives/dropdown-menu/dropdown-menu-item.svelte +27 -0
  353. package/src/lib/components/primitives/dropdown-menu/dropdown-menu-label.svelte +24 -0
  354. package/src/lib/components/primitives/dropdown-menu/dropdown-menu-portal.svelte +7 -0
  355. package/src/lib/components/primitives/dropdown-menu/dropdown-menu-radio-group.svelte +16 -0
  356. package/src/lib/components/primitives/dropdown-menu/dropdown-menu-radio-item.svelte +36 -0
  357. package/src/lib/components/primitives/dropdown-menu/dropdown-menu-separator.svelte +17 -0
  358. package/src/lib/components/primitives/dropdown-menu/dropdown-menu-shortcut.svelte +23 -0
  359. package/src/lib/components/primitives/dropdown-menu/dropdown-menu-sub-content.svelte +31 -0
  360. package/src/lib/components/primitives/dropdown-menu/dropdown-menu-sub-trigger.svelte +29 -0
  361. package/src/lib/components/primitives/dropdown-menu/dropdown-menu-sub.svelte +7 -0
  362. package/src/lib/components/primitives/dropdown-menu/dropdown-menu-trigger.svelte +7 -0
  363. package/src/lib/components/primitives/dropdown-menu/dropdown-menu.svelte +7 -0
  364. package/src/lib/components/primitives/dropdown-menu/index.ts +54 -0
  365. package/src/lib/components/primitives/{alert/alert-description.svelte → empty/empty-content.svelte} +3 -3
  366. package/src/lib/components/primitives/empty/empty-description.svelte +23 -0
  367. package/src/lib/components/primitives/{alert/alert-title.svelte → empty/empty-header.svelte} +3 -3
  368. package/src/lib/components/primitives/empty/empty-media.svelte +41 -0
  369. package/src/lib/components/primitives/{card/card-action.svelte → empty/empty-title.svelte} +2 -2
  370. package/src/lib/components/primitives/empty/empty.svelte +23 -0
  371. package/src/lib/components/primitives/empty/index.ts +22 -0
  372. package/src/lib/components/primitives/index.ts +10 -1
  373. package/src/lib/components/primitives/input/input.svelte +4 -4
  374. package/src/lib/components/primitives/input-group/index.ts +22 -0
  375. package/src/lib/components/primitives/input-group/input-group-addon.svelte +53 -0
  376. package/src/lib/components/primitives/input-group/input-group-button.svelte +49 -0
  377. package/src/lib/components/primitives/input-group/input-group-input.svelte +25 -0
  378. package/src/lib/components/primitives/input-group/input-group-text.svelte +22 -0
  379. package/src/lib/components/primitives/input-group/input-group-textarea.svelte +23 -0
  380. package/src/lib/components/primitives/input-group/input-group.svelte +24 -0
  381. package/src/lib/components/primitives/mode-toggle/mode-toggle.svelte +6 -7
  382. package/src/lib/components/primitives/popover/index.ts +28 -0
  383. package/src/lib/components/primitives/popover/popover-close.svelte +7 -0
  384. package/src/lib/components/primitives/popover/popover-content.svelte +31 -0
  385. package/src/lib/components/primitives/popover/popover-description.svelte +20 -0
  386. package/src/lib/components/primitives/popover/popover-header.svelte +20 -0
  387. package/src/lib/components/primitives/popover/popover-portal.svelte +7 -0
  388. package/src/lib/components/primitives/popover/popover-title.svelte +15 -0
  389. package/src/lib/components/primitives/popover/popover-trigger.svelte +17 -0
  390. package/src/lib/components/primitives/popover/popover.svelte +7 -0
  391. package/src/lib/components/primitives/resizable/resizable-handle.svelte +6 -2
  392. package/src/lib/components/primitives/resizable/resizable-pane-group.svelte +1 -4
  393. package/src/lib/components/primitives/scroll-area/scroll-area.svelte +1 -1
  394. package/src/lib/components/primitives/search/search.svelte +3 -3
  395. package/src/lib/components/primitives/select/select-content.svelte +1 -1
  396. package/src/lib/components/primitives/select/select-trigger.svelte +1 -1
  397. package/src/lib/components/primitives/severity.ts +26 -0
  398. package/src/lib/components/primitives/slider/slider.svelte +8 -3
  399. package/src/lib/components/primitives/sonner/sonner.svelte +1 -1
  400. package/src/lib/components/primitives/spinner/index.ts +1 -0
  401. package/src/lib/components/primitives/spinner/spinner.svelte +29 -0
  402. package/src/lib/components/primitives/switch/switch.svelte +2 -2
  403. package/src/lib/components/primitives/tabs/tabs-list.svelte +27 -5
  404. package/src/lib/components/primitives/tabs/tabs-trigger.svelte +23 -5
  405. package/src/lib/components/primitives/tabs/tabs.svelte +6 -2
  406. package/src/lib/components/primitives/textarea/textarea.svelte +1 -1
  407. package/src/lib/components/primitives/theme-switcher/ThemeSwitcher.svelte +1 -1
  408. package/src/lib/components/primitives/toggle/index.ts +13 -0
  409. package/src/lib/components/primitives/toggle/toggle.svelte +54 -0
  410. package/src/lib/components/primitives/toggle-group/index.ts +10 -0
  411. package/src/lib/components/primitives/toggle-group/toggle-group-item.svelte +35 -0
  412. package/src/lib/components/primitives/toggle-group/toggle-group.svelte +75 -0
  413. package/src/lib/components/viewer/MeshMetadataPanel.svelte +119 -0
  414. package/src/lib/components/viewer/SceneManager.svelte +14 -5
  415. package/src/lib/components/viewer/Viewer.svelte +243 -221
  416. package/src/lib/compute/run-panel-action.ts +16 -0
  417. package/src/lib/compute/solving.svelte.ts +66 -50
  418. package/src/lib/compute/useSolveSession.svelte.ts +3 -0
  419. package/src/lib/constants.ts +7 -9
  420. package/src/lib/contexts/hostContext.svelte.ts +51 -0
  421. package/src/lib/i18n/localeContext.svelte.ts +40 -5
  422. package/src/lib/i18n/messages.ts +453 -13
  423. package/src/lib/index.ts +21 -0
  424. package/src/lib/public.ts +1 -0
  425. package/src/lib/schema/host-support.ts +129 -0
  426. package/src/lib/schema/option-display.ts +44 -0
  427. package/src/lib/schema/param-exporter.ts +10 -7
  428. package/src/lib/schema/visibility-rules.ts +23 -0
  429. package/src/lib/styles/base.css +80 -10
  430. package/src/lib/types/actionButton.ts +16 -3
  431. package/src/lib/types/presetLabels.ts +13 -11
  432. package/src/lib/utils/file-download.ts +11 -21
  433. package/src/lib/utils/host-files.ts +61 -0
  434. package/src/lib/utils/loadScript.ts +3 -0
  435. package/src/lib/utils/webp-to-png.ts +48 -0
  436. package/dist/components/primitives/alert/alert.svelte +0 -44
  437. package/dist/components/primitives/alert/alert.svelte.d.ts +0 -26
  438. package/dist/components/primitives/alert/index.d.ts +0 -5
  439. package/dist/components/primitives/alert/index.js +0 -7
  440. package/dist/components/viewer/MeshMetadataDialog.svelte +0 -126
  441. package/dist/components/viewer/MeshMetadataDialog.svelte.d.ts +0 -10
  442. package/src/lib/components/primitives/alert/alert.svelte +0 -44
  443. package/src/lib/components/primitives/alert/index.ts +0 -14
  444. package/src/lib/components/viewer/MeshMetadataDialog.svelte +0 -126
@@ -5,6 +5,10 @@
5
5
  import { toast } from '../../primitives/sonner';
6
6
  import { FileUp, Link, CircleAlert, CircleCheck } from '@lucide/svelte';
7
7
  import { APP_DEFAULTS } from '../../../constants';
8
+ import { getLocaleContext } from '../../../i18n/localeContext.svelte';
9
+ import { formatMessage } from '../../../i18n/messages';
10
+ import { pickFile } from '../../../utils/host-files';
11
+ import { acceptsFileEnding, isWebp, shouldConvertWebp, webpToPng } from '../../../utils/webp-to-png';
8
12
 
9
13
  interface Props {
10
14
  value?: string;
@@ -22,6 +26,9 @@
22
26
  onChange
23
27
  }: Props = $props();
24
28
 
29
+ const locale = getLocaleContext();
30
+ const t = $derived(locale.messages);
31
+
25
32
  let effectiveModes = $derived(
26
33
  allowedInputModes && allowedInputModes.length > 0
27
34
  ? allowedInputModes
@@ -35,7 +42,6 @@
35
42
  activeMode = effectiveModes.includes(preferred) ? preferred : effectiveModes[0];
36
43
  });
37
44
 
38
- let fileInput: HTMLInputElement | null = $state(null);
39
45
  let uploadedFileName = $state('');
40
46
  let urlInput = $state('');
41
47
  let isDragging = $state(false);
@@ -52,9 +58,12 @@
52
58
  if (parsed.type === 'base64') {
53
59
  if (parsed._isMetadata && parsed._fileSize) {
54
60
  const sizeMB = (parsed._fileSize / 1024 / 1024).toFixed(2);
55
- uploadedFileName = `Uploaded file (${parsed.fileEnding}, ${sizeMB}MB)`;
61
+ uploadedFileName = formatMessage(t.uploadedFileSize, {
62
+ ext: parsed.fileEnding,
63
+ size: sizeMB
64
+ });
56
65
  } else {
57
- uploadedFileName = `Uploaded file (${parsed.fileEnding})`;
66
+ uploadedFileName = formatMessage(t.uploadedFile, { ext: parsed.fileEnding });
58
67
  }
59
68
  } else if (parsed.type === 'url') {
60
69
  urlInput = parsed.file;
@@ -65,6 +74,20 @@
65
74
  }
66
75
  });
67
76
 
77
+ function formatNotAccepted(fileEnding: string): string {
78
+ return formatMessage(t.fileFormatNotAccepted, {
79
+ ext: fileEnding,
80
+ formats: acceptedFormats.join(', ')
81
+ });
82
+ }
83
+
84
+ function formatTooLarge(bytes: number): string {
85
+ return formatMessage(t.fileTooLarge, {
86
+ size: (bytes / 1024 / 1024).toFixed(2),
87
+ max: APP_DEFAULTS.FILE_UPLOAD.MAX_SIZE_MB
88
+ });
89
+ }
90
+
68
91
  function getFileExtension(filename: string): string {
69
92
  // Strip query strings before extracting extension
70
93
  const cleanPath = filename.split('?')[0];
@@ -72,9 +95,27 @@
72
95
  return ext.toLowerCase();
73
96
  }
74
97
 
75
- function isValidFileExtension(fileEnding: string): boolean {
76
- if (acceptedFormats.length === 0) return true;
77
- return acceptedFormats.includes(fileEnding.toLowerCase());
98
+ // Runs before the size cap: the PNG is larger than the WebP it came from. A WebP already over
99
+ // the cap is passed through unconverted, so the cap rejects it without a full decode.
100
+ async function prepare(
101
+ blob: Blob,
102
+ fileEnding: string
103
+ ): Promise<{ blob: Blob; fileEnding: string }> {
104
+ if (blob.size > APP_DEFAULTS.FILE_UPLOAD.MAX_SIZE_BYTES) return { blob, fileEnding };
105
+ if (!shouldConvertWebp(fileEnding, acceptedFormats)) return { blob, fileEnding };
106
+ return { blob: await webpToPng(blob), fileEnding: '.png' };
107
+ }
108
+
109
+ function readBase64(blob: Blob): Promise<string> {
110
+ return new Promise<string>((resolve, reject) => {
111
+ const reader = new FileReader();
112
+ reader.onload = (e) => {
113
+ const result = e.target?.result as string;
114
+ resolve(result.includes(',') ? result.split(',')[1] : result);
115
+ };
116
+ reader.onerror = () => reject(new Error(t.fileReadFailed));
117
+ reader.readAsDataURL(blob);
118
+ });
78
119
  }
79
120
 
80
121
  function isCorsError(error: unknown): boolean {
@@ -96,56 +137,52 @@
96
137
  try {
97
138
  parsedUrl = new URL(urlInput);
98
139
  } catch {
99
- urlError = { message: 'Invalid URL — make sure it starts with https://', isCors: false };
140
+ urlError = { message: t.urlInvalid, isCors: false };
100
141
  return;
101
142
  }
102
143
 
103
144
  if (parsedUrl.protocol !== 'https:' && parsedUrl.protocol !== 'http:') {
104
- urlError = { message: 'Only http:// and https:// URLs are supported.', isCors: false };
145
+ urlError = { message: t.urlProtocolUnsupported, isCors: false };
105
146
  return;
106
147
  }
107
148
 
108
149
  const response = await fetch(urlInput);
109
150
  if (!response.ok) {
110
151
  urlError = {
111
- message: `Server returned ${response.status} ${response.statusText}. Check the URL is correct and publicly accessible.`,
152
+ message: formatMessage(t.urlServerError, {
153
+ status: `${response.status} ${response.statusText}`.trim()
154
+ }),
112
155
  isCors: false
113
156
  };
114
157
  return;
115
158
  }
116
159
 
117
- const blob = await response.blob();
118
- const fileEnding = getFileExtension(urlInput);
160
+ const fetched = await response.blob();
161
+ const requestedEnding = (await isWebp(fetched)) ? '.webp' : getFileExtension(urlInput);
119
162
 
120
- if (!isValidFileExtension(fileEnding)) {
121
- urlError = {
122
- message: `File format "${fileEnding}" is not accepted. Allowed: ${acceptedFormats.join(', ')}`,
123
- isCors: false
124
- };
163
+ if (!acceptsFileEnding(requestedEnding, acceptedFormats)) {
164
+ urlError = { message: formatNotAccepted(requestedEnding), isCors: false };
125
165
  return;
126
166
  }
127
167
 
168
+ const { blob, fileEnding } = await prepare(fetched, requestedEnding);
169
+
128
170
  const maxSize = APP_DEFAULTS.FILE_UPLOAD.MAX_SIZE_BYTES;
129
171
  if (blob.size > maxSize) {
130
172
  urlError = {
131
- message: `File too large: ${(blob.size / 1024 / 1024).toFixed(2)}MB (max ${APP_DEFAULTS.FILE_UPLOAD.MAX_SIZE_MB}MB). Download it and use Upload instead.`,
173
+ message: `${formatTooLarge(blob.size)} ${t.fileTooLargeUseUpload}`,
132
174
  isCors: false
133
175
  };
134
176
  return;
135
177
  }
136
178
 
137
- const base64Data = await new Promise<string>((resolve, reject) => {
138
- const reader = new FileReader();
139
- reader.onload = (e) => {
140
- const result = e.target?.result as string;
141
- resolve(result.includes(',') ? result.split(',')[1] : result);
142
- };
143
- reader.onerror = () => reject(new Error('Failed to read the downloaded file.'));
144
- reader.readAsDataURL(blob);
145
- });
179
+ const base64Data = await readBase64(blob);
146
180
  const data = JSON.stringify({ file: base64Data, type: 'base64', fileEnding });
147
181
  value = data;
148
- urlSuccess = `Loaded ${fileEnding} (${(blob.size / 1024).toFixed(0)} KB)`;
182
+ urlSuccess = formatMessage(t.fileLoaded, {
183
+ ext: fileEnding,
184
+ size: (blob.size / 1024).toFixed(0)
185
+ });
149
186
  onChange(data);
150
187
  } catch (error) {
151
188
  if (isCorsError(error)) {
@@ -158,26 +195,22 @@
158
195
  })();
159
196
  // The opaque TypeError hides CORS blocks and plain network failures (404, DNS)
160
197
  // alike, so the message has to cover both.
161
- let hint =
162
- 'Check that the URL is correct and the file is publicly accessible. If the server requires login, download the file and use the Upload option instead.';
198
+ let hint = t.urlUnreachableHint;
163
199
  if (host.includes('sharepoint.com') || host.includes('onedrive.com')) {
164
- hint =
165
- 'SharePoint/OneDrive blocks browser access. Open the file in SharePoint, use "Download" to save it locally, then upload it here.';
200
+ hint = t.urlHintSharePoint;
166
201
  } else if (host.includes('drive.google.com')) {
167
- hint =
168
- 'Google Drive blocks browser access. Use "Download" in Google Drive to save the file locally, then upload it here.';
202
+ hint = t.urlHintGoogleDrive;
169
203
  } else if (host.includes('dropbox.com')) {
170
- hint =
171
- 'Dropbox links may block browser access. Try changing "?dl=0" to "?dl=1" in the URL, or download and upload instead.';
204
+ hint = t.urlHintDropbox;
172
205
  }
173
206
  urlError = {
174
- message: `Could not reach "${host}" — the file may not exist, or the server does not allow browser access.`,
207
+ message: formatMessage(t.urlUnreachable, { host }),
175
208
  isCors: true,
176
209
  hint
177
210
  };
178
211
  } else {
179
212
  urlError = {
180
- message: error instanceof Error ? error.message : 'Unknown error',
213
+ message: error instanceof Error ? error.message : t.unknownError,
181
214
  isCors: false
182
215
  };
183
216
  }
@@ -186,50 +219,39 @@
186
219
  }
187
220
  }
188
221
 
189
- function handleFileUpload(event: Event) {
190
- const target = event.target as HTMLInputElement;
191
- const file = target.files?.[0];
192
- if (!file) return;
222
+ async function handleFile(file: File) {
223
+ const requestedEnding = getFileExtension(file.name);
193
224
 
194
- const fileEnding = getFileExtension(file.name);
195
-
196
- if (!isValidFileExtension(fileEnding)) {
197
- toast.error(`File format not accepted: ${fileEnding}`);
225
+ if (!acceptsFileEnding(requestedEnding, acceptedFormats)) {
226
+ toast.error(formatNotAccepted(requestedEnding));
198
227
  return;
199
228
  }
200
229
 
201
- // The file is base64-embedded into the compute request body, so without a
202
- // client-side cap an oversize file comes back as an opaque 413. This cap is
203
- // currently LOOSER than the server's COMPUTE_REQUEST_MAX_BYTES (see the TEMP
204
- // note in constants.ts) — some files pass here and still 413. The URL import
205
- // path applies the same cap.
206
- if (file.size > APP_DEFAULTS.FILE_UPLOAD.MAX_SIZE_BYTES) {
207
- toast.error(
208
- `File too large: ${(file.size / 1024 / 1024).toFixed(2)}MB (max ${APP_DEFAULTS.FILE_UPLOAD.MAX_SIZE_MB}MB).`
209
- );
210
- return;
211
- }
212
-
213
- uploadedFileName = file.name;
214
-
215
- const reader = new FileReader();
216
- reader.onload = (e) => {
217
- const base64 = e.target?.result as string;
218
- const base64Data = base64.includes(',') ? base64.split(',')[1] : base64;
230
+ try {
231
+ const { blob, fileEnding } = await prepare(file, requestedEnding);
232
+
233
+ // The file is base64-embedded into the compute request body, so without a
234
+ // client-side cap an oversize file comes back as an opaque 413. This cap is
235
+ // currently LOOSER than the server's COMPUTE_REQUEST_MAX_BYTES (see the TEMP
236
+ // note in constants.ts) — some files pass here and still 413. The URL import
237
+ // path applies the same cap.
238
+ if (blob.size > APP_DEFAULTS.FILE_UPLOAD.MAX_SIZE_BYTES) {
239
+ toast.error(formatTooLarge(blob.size));
240
+ return;
241
+ }
219
242
 
220
- const data = JSON.stringify({
221
- file: base64Data,
222
- type: 'base64',
223
- fileEnding
224
- });
243
+ uploadedFileName = file.name;
244
+ const data = JSON.stringify({ file: await readBase64(blob), type: 'base64', fileEnding });
225
245
  value = data;
226
246
  onChange(data);
227
- };
228
- reader.readAsDataURL(file);
247
+ } catch (error) {
248
+ toast.error(error instanceof Error ? error.message : t.fileReadFailed);
249
+ }
229
250
  }
230
251
 
231
- function openFilePicker() {
232
- fileInput?.click();
252
+ async function openFilePicker() {
253
+ const file = await pickFile({ accept: acceptAttribute });
254
+ if (file) handleFile(file);
233
255
  }
234
256
 
235
257
  function handleDragOver(e: DragEvent) {
@@ -245,40 +267,28 @@
245
267
  e.preventDefault();
246
268
  isDragging = false;
247
269
 
248
- const files = e.dataTransfer?.files;
249
- if (files?.[0]) {
250
- const fakeEvent = new Event('change');
251
- const fakeTarget = { files: files } as HTMLInputElement;
252
- Object.defineProperty(fakeEvent, 'target', { value: fakeTarget });
253
- handleFileUpload(fakeEvent);
254
- }
270
+ const file = e.dataTransfer?.files?.[0];
271
+ if (file) handleFile(file);
255
272
  }
256
273
 
257
274
  const acceptAttribute = $derived(acceptedFormats.length > 0 ? acceptedFormats.join(',') : '*');
258
275
  </script>
259
276
 
260
- <div class="gap-4 flex w-full flex-col">
261
- <input
262
- bind:this={fileInput}
263
- type="file"
264
- accept={acceptAttribute}
265
- onchange={handleFileUpload}
266
- class="hidden"
267
- />
268
-
277
+ <div class="gap-2.5 flex w-full flex-col">
269
278
  {#if showToggle}
270
- <div class="rounded text-xs flex overflow-hidden border">
279
+ <div class="p-0.5 text-xs flex rounded-md bg-muted">
271
280
  {#each effectiveModes as mode (mode)}
272
281
  <button
273
282
  type="button"
274
283
  onclick={() => (activeMode = mode)}
275
- class={`px-3 py-1 flex-1 transition-colors ${
284
+ aria-pressed={activeMode === mode}
285
+ class={`px-3 py-1 font-medium flex-1 rounded-sm transition-colors ${
276
286
  activeMode === mode
277
- ? 'bg-primary text-primary-foreground'
278
- : 'text-muted-foreground hover:bg-accent'
287
+ ? 'shadow-xs bg-background text-foreground'
288
+ : 'text-muted-foreground hover:text-foreground'
279
289
  }`}
280
290
  >
281
- {mode === 'upload' ? 'Upload' : 'URL'}
291
+ {mode === 'upload' ? t.fileModeUpload : t.fileModeUrl}
282
292
  </button>
283
293
  {/each}
284
294
  </div>
@@ -286,9 +296,9 @@
286
296
 
287
297
  {#if activeMode === 'url'}
288
298
  <div class="gap-2 flex flex-col">
289
- <Label for="url-input" class="gap-2 flex items-center">
299
+ <Label for="url-input">
290
300
  <Link size={16} />
291
- File URL
301
+ {t.fileUrlLabel}
292
302
  </Label>
293
303
  <div class="gap-2 flex">
294
304
  <Input
@@ -297,7 +307,7 @@
297
307
  bind:value={urlInput}
298
308
  placeholder="https://example.com/model.3dm"
299
309
  disabled={isLoading}
300
- class={urlError ? 'border-destructive focus-visible:ring-destructive' : ''}
310
+ aria-invalid={urlError ? true : undefined}
301
311
  oninput={() => {
302
312
  urlError = null;
303
313
  urlSuccess = '';
@@ -309,7 +319,7 @@
309
319
  disabled={isLoading || !urlInput.trim()}
310
320
  onclick={handleUrlChange}
311
321
  >
312
- {isLoading ? 'Fetching...' : 'Fetch'}
322
+ {isLoading ? t.fetchingFile : t.fetchFile}
313
323
  </Button>
314
324
  </div>
315
325
 
@@ -335,32 +345,26 @@
335
345
  {/if}
336
346
 
337
347
  {#if !urlError && !urlSuccess}
338
- <p class="text-xs text-muted-foreground">
339
- URL must be publicly accessible (no login required).
340
- </p>
348
+ <p class="text-xs text-muted-foreground">{t.fileUrlPublic}</p>
341
349
  {/if}
342
350
  </div>
343
351
  {:else}
344
352
  <div class="gap-2 flex flex-col">
345
- <Label for="file-upload" class="gap-2 flex items-center">
346
- <FileUp size={16} />
347
- Upload File
348
- </Label>
349
353
  <Button
350
354
  type="button"
351
- variant="outline"
352
- class="gap-2 w-full {isDragging ? 'border-primary' : ''}"
355
+ variant={isDragging ? 'secondary' : 'outline'}
356
+ class="w-full"
353
357
  onclick={openFilePicker}
354
358
  ondragover={handleDragOver}
355
359
  ondragleave={handleDragLeave}
356
360
  ondrop={handleDrop}
357
361
  >
358
362
  <FileUp size={16} />
359
- {uploadedFileName || 'Choose File or Drag & Drop'}
363
+ {uploadedFileName || t.chooseFile}
360
364
  </Button>
361
365
  {#if acceptedFormats.length > 0}
362
366
  <p class="text-xs text-muted-foreground">
363
- Accepted formats: {acceptedFormats.join(', ')}
367
+ {formatMessage(t.acceptedFormats, { formats: acceptedFormats.join(', ') })}
364
368
  </p>
365
369
  {/if}
366
370
  </div>
@@ -0,0 +1,128 @@
1
+ <script lang="ts">
2
+ import { Button } from '../../primitives/button';
3
+ import type { GeometryPickResult, PickKind } from '../../../contexts/hostContext.svelte';
4
+ import { getLocaleContext } from '../../../i18n/localeContext.svelte';
5
+ import type { ViewerMessages } from '../../../i18n/messages';
6
+
7
+ interface Props {
8
+ inputId: string;
9
+ /** The kinds of object the input takes; one kind names the button after it. */
10
+ kinds?: readonly PickKind[];
11
+ /** 1 picks a single object. */
12
+ atMost?: number;
13
+ /** What the host reports the param holds, such as "2 curves"; absent until something is picked. */
14
+ summary?: string;
15
+ /** Absent where this page may not pick, such as a browser tab beside the Rhino panel. */
16
+ onPick?: () => Promise<GeometryPickResult>;
17
+ onClear?: () => void;
18
+ /** Subscribes to what the host holds after any page picks or clears; returns an unsubscribe. */
19
+ watchSummary?: (listener: (summary: string | null) => void) => () => void;
20
+ /** Shown when the pick fails; the host's own message. */
21
+ onError?: (message: string) => void;
22
+ disabled?: boolean;
23
+ }
24
+
25
+ let {
26
+ inputId,
27
+ kinds,
28
+ atMost,
29
+ summary,
30
+ onPick,
31
+ onClear,
32
+ watchSummary,
33
+ onError,
34
+ disabled = false
35
+ }: Props = $props();
36
+
37
+ const locale = getLocaleContext();
38
+ const t = $derived(locale.messages);
39
+
40
+ type PickLabels = readonly [one: keyof ViewerMessages, other: keyof ViewerMessages];
41
+
42
+ const ANY_LABELS: PickLabels = ['geometryPickAnyOne', 'geometryPickAnyOther'];
43
+ const KIND_LABELS: Record<PickKind, PickLabels> = {
44
+ point: ['geometryPickPointOne', 'geometryPickPointOther'],
45
+ pointCloud: ['geometryPickPointCloudOne', 'geometryPickPointCloudOther'],
46
+ curve: ['geometryPickCurveOne', 'geometryPickCurveOther'],
47
+ line: ['geometryPickLineOne', 'geometryPickLineOther'],
48
+ plane: ['geometryPickPlaneOne', 'geometryPickPlaneOther'],
49
+ surface: ['geometryPickSurfaceOne', 'geometryPickSurfaceOther'],
50
+ polysurface: ['geometryPickPolysurfaceOne', 'geometryPickPolysurfaceOther'],
51
+ extrusion: ['geometryPickExtrusionOne', 'geometryPickExtrusionOther'],
52
+ mesh: ['geometryPickMeshOne', 'geometryPickMeshOther'],
53
+ subd: ['geometryPickSubdOne', 'geometryPickSubdOther'],
54
+ block: ['geometryPickBlockOne', 'geometryPickBlockOther']
55
+ };
56
+
57
+ const pickLabel = $derived.by(() => {
58
+ const [one, other] = kinds?.length === 1 ? KIND_LABELS[kinds[0]] : ANY_LABELS;
59
+ return t[atMost === 1 ? one : other];
60
+ });
61
+
62
+ // Rhino's command line prompts during the pick; the page keeps the button from being pressed
63
+ // twice and says where to look.
64
+ let picking = $state(false);
65
+ // The last pick or clear wins over what the host reported when the page loaded.
66
+ let local = $state<string | null | undefined>(undefined);
67
+ const shown = $derived(local !== undefined ? local : (summary ?? null));
68
+
69
+ $effect(() =>
70
+ watchSummary?.((held) => {
71
+ local = held;
72
+ })
73
+ );
74
+
75
+ async function pick(onPick: () => Promise<GeometryPickResult>) {
76
+ picking = true;
77
+ try {
78
+ const result = await onPick();
79
+ if (result.outcome === 'picked') local = result.summary;
80
+ else if (result.outcome === 'failed') onError?.(result.error);
81
+ } finally {
82
+ picking = false;
83
+ }
84
+ }
85
+
86
+ // The field label points at inputId: the button where there is one, else an <output>, which
87
+ // unlike a <span> can be labelled.
88
+ const readout = $derived(onPick ? 'span' : 'output');
89
+
90
+ function clear(onClear: () => void) {
91
+ local = null;
92
+ onClear();
93
+ }
94
+ </script>
95
+
96
+ <div class="gap-2 min-w-0 flex flex-wrap items-center">
97
+ {#if onPick}
98
+ <Button
99
+ id={inputId}
100
+ variant="outline"
101
+ size="sm"
102
+ onclick={() => pick(onPick)}
103
+ disabled={disabled || picking}
104
+ >
105
+ {shown ? t.geometryPickAgain : pickLabel}
106
+ </Button>
107
+ {/if}
108
+ {#if picking}
109
+ <span class="text-sm min-w-0 text-muted-foreground" role="status">{t.geometryPicking}</span>
110
+ {:else if shown}
111
+ <svelte:element
112
+ this={readout}
113
+ id={onPick ? undefined : inputId}
114
+ class="text-sm min-w-0 truncate text-foreground"
115
+ >
116
+ {shown}
117
+ </svelte:element>
118
+ {#if onClear}
119
+ <Button variant="ghost" size="sm" onclick={() => clear(onClear)} {disabled}>
120
+ {t.geometryClear}
121
+ </Button>
122
+ {/if}
123
+ {:else if !onPick}
124
+ <output id={inputId} class="text-sm min-w-0 text-muted-foreground"
125
+ >{t.geometryPickInPanel}</output
126
+ >
127
+ {/if}
128
+ </div>
@@ -0,0 +1,21 @@
1
+ import type { GeometryPickResult, PickKind } from '../../../contexts/hostContext.svelte';
2
+ interface Props {
3
+ inputId: string;
4
+ /** The kinds of object the input takes; one kind names the button after it. */
5
+ kinds?: readonly PickKind[];
6
+ /** 1 picks a single object. */
7
+ atMost?: number;
8
+ /** What the host reports the param holds, such as "2 curves"; absent until something is picked. */
9
+ summary?: string;
10
+ /** Absent where this page may not pick, such as a browser tab beside the Rhino panel. */
11
+ onPick?: () => Promise<GeometryPickResult>;
12
+ onClear?: () => void;
13
+ /** Subscribes to what the host holds after any page picks or clears; returns an unsubscribe. */
14
+ watchSummary?: (listener: (summary: string | null) => void) => () => void;
15
+ /** Shown when the pick fails; the host's own message. */
16
+ onError?: (message: string) => void;
17
+ disabled?: boolean;
18
+ }
19
+ declare const GeometryInput: import("svelte").Component<Props, {}, "">;
20
+ type GeometryInput = ReturnType<typeof GeometryInput>;
21
+ export default GeometryInput;