@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
@@ -15,31 +15,18 @@
15
15
  type Grid,
16
16
  type ThreeViewer
17
17
  } from '@selvajs/visualization/render';
18
- import {
19
- Maximize,
20
- Minimize,
21
- Camera,
22
- Layers,
23
- Settings2,
24
- Box,
25
- Square,
26
- Frame,
27
- Ruler,
28
- Grid3x3,
29
- Palette,
30
- Spline
31
- } from '@lucide/svelte';
32
18
  import { SvelteSet } from 'svelte/reactivity';
33
19
  import type * as THREE from 'three';
34
20
  import type { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js';
35
21
  import { createSceneOutliner, type SceneOutliner } from '@selvajs/visualization/scene';
22
+ import { clearGeometryCache } from '@selvajs/visualization/parse';
36
23
  import SceneManager from './SceneManager.svelte';
24
+ import ViewerDock from './ViewerDock.svelte';
37
25
  import MeshMetadataPanel from './MeshMetadataPanel.svelte';
38
26
  import * as Resizable from '../primitives/resizable/index.js';
39
- import * as DropdownMenu from '../primitives/dropdown-menu/index.js';
40
- import { Button } from '../primitives/button/index.js';
41
- import type { Locale } from '../../i18n/messages';
42
- import { layerLocaleContext } from '../../i18n/localeContext.svelte';
27
+ import type { Locale } from '../../i18n/messages.js';
28
+ import { layerLocaleContext } from '../../i18n/localeContext.svelte.js';
29
+ import { saveBlob } from '../../utils/host-files.js';
43
30
 
44
31
  export interface ViewerConfig {
45
32
  showScreenshotButton?: boolean;
@@ -50,6 +37,8 @@
50
37
  showDisplayMenu?: boolean;
51
38
  enableMeshClick?: boolean;
52
39
  backgroundColor?: string;
40
+ /** The look to open in. Default `technical`. */
41
+ look?: Look;
53
42
  /** Initial state of the edge overlay and its display-menu checkmark. Default false. */
54
43
  showEdges?: boolean;
55
44
  }
@@ -57,7 +46,10 @@
57
46
  interface Props {
58
47
  meshes: any[];
59
48
  isFullscreen?: boolean;
49
+ /** @deprecated Ignored: the panel's solve status shows a running solve. */
60
50
  isSolving?: boolean;
51
+ /** @deprecated Ignored, like `isSolving`. */
52
+ isSlow?: boolean;
61
53
  isBlurred?: boolean;
62
54
  drawerOpen?: boolean;
63
55
  viewerConfig?: ViewerConfig;
@@ -86,13 +78,13 @@
86
78
  showDisplayMenu: true,
87
79
  enableMeshClick: true,
88
80
  backgroundColor: '#E6E6E6',
81
+ look: 'technical',
89
82
  showEdges: false
90
83
  };
91
84
 
92
85
  let {
93
86
  meshes,
94
87
  isFullscreen = $bindable(false),
95
- isSolving = false,
96
88
  isBlurred = false,
97
89
  drawerOpen = false,
98
90
  viewerConfig = {},
@@ -118,11 +110,14 @@
118
110
  let clearEdges: ThreeViewer['clearEdges'] | null = null;
119
111
  let invalidate: (() => void) | null = null;
120
112
  let captureImage: ThreeViewer['captureImage'] | null = null;
121
- let setLook: ((look: Look) => void) | null = null;
113
+ let setLook: ThreeViewer['setLook'] | null = null;
114
+ let syncEmissiveLights: (() => void) | null = null;
122
115
  let updateGridScale: (() => void) | null = null;
123
116
  let updateShadowBounds: (() => void) | null = null;
124
117
  let fitToView: (() => void) | null = null;
125
118
  let clearSelection: (() => void) | null = null;
119
+ let selectEntries: ThreeViewer['selectEntries'] | null = null;
120
+ let setHover: ThreeViewer['setHover'] | null = null;
126
121
  let viewerInitialized = false;
127
122
  let sceneVersion = $state(0);
128
123
  let hideButton = $state(false);
@@ -137,9 +132,16 @@
137
132
  let projection: CameraProjection = $state('perspective');
138
133
  let measureActive = $state(false);
139
134
  let gridVisible = $state(false);
140
- let renderStyle: Look = $state('technical');
135
+ // A saved schema can name a look this build doesn't have, and an unknown look throws on mount.
136
+ const openingLook = untrack(() => {
137
+ const look = viewerConfig.look;
138
+ return look && LOOKS.includes(look) ? look : defaultViewerConfig.look;
139
+ });
140
+ const opensAsLineDrawing = LOOK_PRESETS[openingLook].requiresEdges === true;
141
+ const configuredEdges = untrack(() => viewerConfig.showEdges) ?? defaultViewerConfig.showEdges;
142
+ let renderStyle: Look = $state(openingLook);
141
143
  // Seeded once, then owned by the menu toggle.
142
- let edgesVisible = $state(untrack(() => viewerConfig.showEdges) ?? defaultViewerConfig.showEdges);
144
+ let edgesVisible = $state(opensAsLineDrawing || configuredEdges);
143
145
  let selectedMeshMetadata: Record<string, any> | null = $state(null);
144
146
  let selectedMeshName: string | null = $state(null);
145
147
 
@@ -152,14 +154,20 @@
152
154
  arctic: t.lookArctic,
153
155
  xray: t.lookXray,
154
156
  lineart: t.lookLineart,
155
- wireframe: t.lookWireframe
157
+ wireframe: t.lookWireframe,
158
+ night: t.lookNight
156
159
  });
160
+ // Night has its own toggle, so it stays out of the radio list.
157
161
  const styleOptions = $derived<{ look: Look; label: string }[]>(
158
- LOOKS.map((look) => ({
162
+ LOOKS.filter((look) => look !== 'night').map((look) => ({
159
163
  look,
160
164
  label: lookLabels[look] ?? look.charAt(0).toUpperCase() + look.slice(1)
161
165
  }))
162
166
  );
167
+ const nightOn = $derived(renderStyle === 'night');
168
+
169
+ // What the night toggle returns to.
170
+ let dayLook: Look = $state(openingLook === 'night' ? defaultViewerConfig.look : openingLook);
163
171
 
164
172
  const VIEW_PRESETS: { preset: ViewPreset; label: () => string }[] = [
165
173
  { preset: 'top', label: () => t.viewTop },
@@ -197,8 +205,8 @@
197
205
  events: {
198
206
  // Fires before onMeshMetadataClicked, so picking an object without metadata closes the
199
207
  // previous object's panel instead of leaving it describing the wrong thing.
200
- onObjectSelected: closeMetadata,
201
- onBackgroundClicked: closeMetadata,
208
+ onObjectSelected: dropPanelSelection,
209
+ onBackgroundClicked: dropPanelSelection,
202
210
  onMeshMetadataClicked: config.enableMeshClick
203
211
  ? (metadata: Record<string, unknown>) => {
204
212
  if (hasUsefulMetadata(metadata)) {
@@ -226,25 +234,25 @@
226
234
  invalidate = init.invalidate;
227
235
  captureImage = init.captureImage;
228
236
  setLook = init.setLook;
237
+ syncEmissiveLights = init.syncEmissiveLights;
229
238
  updateGridScale = init.updateGridScale;
230
239
  updateShadowBounds = init.updateShadowBounds;
231
240
  fitToView = init.fitToView;
232
241
  clearSelection = init.clearSelection;
242
+ selectEntries = init.selectEntries;
243
+ setHover = init.setHover;
233
244
  projection = init.cameraController.getProjection();
234
245
 
235
- const renderer = init.renderer;
236
-
237
246
  // Untracked so the host reading `meshes` or config inside its setup can't re-run onMount's teardown.
238
247
  const hostCleanup = untrack(() => onViewerReady?.(init));
239
248
 
240
249
  return () => {
241
250
  // Before dispose, so the host can still remove its own objects from a live scene.
242
251
  hostCleanup?.();
252
+ // Also frees the GL context: a second forceContextLoss() here hits an already-lost one.
243
253
  init.dispose();
244
- // `{#key definitionKey}` recreates the canvas + WebGLRenderer + GL context
245
- // on every definition switch; browsers cap live contexts (~16). Explicitly
246
- // drop this one so the GPU-side context is released now rather than at GC.
247
- renderer.forceContextLoss();
254
+ // Parsed geometry outlives the viewer otherwise: the cache is page-wide.
255
+ clearGeometryCache();
248
256
  };
249
257
  });
250
258
 
@@ -272,12 +280,13 @@
272
280
 
273
281
  // Edges the lineart look switched on, so leaving it can put the user's own choice back rather
274
282
  // than stranding them with overlays they never asked for.
275
- let edgesBeforeLineDrawing: boolean | null = null;
283
+ let edgesBeforeLineDrawing: boolean | null = opensAsLineDrawing ? configuredEdges : null;
276
284
 
277
285
  function setRenderStyle(look: Look) {
278
286
  if (!setLook || look === renderStyle) return;
279
287
  const wasLineDrawing = LOOK_PRESETS[renderStyle].requiresEdges === true;
280
288
  renderStyle = look;
289
+ if (look !== 'night') dayLook = look;
281
290
  setLook(look);
282
291
 
283
292
  // A look never drives the overlay itself; honouring `requiresEdges` is the host's call. Without
@@ -343,6 +352,10 @@
343
352
  else clearEdges?.(scene);
344
353
  }
345
354
 
355
+ function toggleNight() {
356
+ setRenderStyle(nightOn ? dayLook : 'night');
357
+ }
358
+
346
359
  function toggleEdges() {
347
360
  edgesVisible = !edgesVisible;
348
361
  // Toggling by hand inside lineart overrides what that look forced, so the pre-look value is
@@ -359,7 +372,8 @@
359
372
  untrack(() => {
360
373
  // The new meshes carry the materials the parser built, so a look that overrides them
361
374
  // (arctic, x-ray) has to be re-applied or the solve silently reverts to shaded.
362
- setLook?.(renderStyle);
375
+ // Emissive lights wait for `applyTo` below, or a hidden lamp would count as lit.
376
+ setLook?.(renderStyle, { deferEmissiveLights: true });
363
377
  // updateScene discarded the previous solve's overlays along with its content.
364
378
  if (edgesVisible) applyEdges?.(scene!, edgeOverrides());
365
379
  // Rescale the grid so cells and fade match the new content's extent.
@@ -370,6 +384,7 @@
370
384
  // The rebuild un-hid everything; the outliner keys hidden state on Grasshopper
371
385
  // identity, not on the instances just discarded, so it can re-hide it.
372
386
  outliner?.applyTo();
387
+ syncEmissiveLights?.();
373
388
  sceneVersion++;
374
389
  // Repaint now rather than on the render loop's safety interval.
375
390
  invalidate?.();
@@ -386,6 +401,24 @@
386
401
  selectedMeshName = null;
387
402
  }
388
403
 
404
+ // A click on the canvas replaces whatever the panel selected: one selection at a time.
405
+ function dropPanelSelection() {
406
+ closeMetadata();
407
+ selectedObjects.clear();
408
+ }
409
+
410
+ // Mirrors the panel's selection into the viewport. The size check skips walking the entries for
411
+ // the common empty case, which also keeps `has()` from subscribing to every key.
412
+ $effect(() => {
413
+ if (selectedObjects.size === 0) {
414
+ selectEntries?.([]);
415
+ return;
416
+ }
417
+ const chosen = outliner?.entries().filter((entry) => selectedObjects.has(entry.key)) ?? [];
418
+ closeMetadata();
419
+ selectEntries?.(chosen);
420
+ });
421
+
389
422
  function dismissMetadata() {
390
423
  closeMetadata();
391
424
  clearSelection?.();
@@ -408,6 +441,27 @@
408
441
  isFullscreen = !isFullscreen;
409
442
  }
410
443
 
444
+ // Single letters; F (fit) is handled by the canvas itself. Held back while typing, e.g. in the
445
+ // scene manager's search box.
446
+ const SHORTCUTS: Record<string, () => void> = {
447
+ o: toggleProjection,
448
+ m: toggleMeasure,
449
+ g: toggleGrid,
450
+ n: toggleNight,
451
+ e: toggleEdges,
452
+ s: () => (sceneManagerOpen = !sceneManagerOpen)
453
+ };
454
+
455
+ function handleShortcut(event: KeyboardEvent) {
456
+ if (event.ctrlKey || event.metaKey || event.altKey || event.repeat) return;
457
+ const target = event.target as HTMLElement;
458
+ if (target.closest('input, textarea, select, [contenteditable]')) return;
459
+ const action = SHORTCUTS[event.key.toLowerCase()];
460
+ if (!action) return;
461
+ event.preventDefault();
462
+ action();
463
+ }
464
+
411
465
  function hasUsefulMetadata(metadata: Record<string, any>): boolean {
412
466
  if (!metadata) return false;
413
467
 
@@ -433,22 +487,18 @@
433
487
  const blob = await captureImage?.();
434
488
  if (!blob) return;
435
489
 
436
- const url = URL.createObjectURL(blob);
437
- const link = document.createElement('a');
438
490
  const timestamp = new Date().toISOString().slice(0, 19).replace(/:/g, '-');
439
- link.href = url;
440
- link.download = `viewer-${timestamp}.png`;
441
- document.body.appendChild(link);
442
- link.click();
443
- document.body.removeChild(link);
444
- URL.revokeObjectURL(url);
491
+ await saveBlob(blob, `viewer-${timestamp}.png`);
445
492
  }
446
493
  </script>
447
494
 
495
+ <!-- Key events bubble up from the focused canvas or any control inside; the div itself is not interactive. -->
496
+ <!-- svelte-ignore a11y_no_static_element_interactions -->
448
497
  <div
449
498
  class="min-h-64 sm:min-h-96 lg:min-h-125 relative h-full flex-1 border {isFullscreen
450
499
  ? 'fullscreen-viewer'
451
500
  : 'overflow-hidden rounded-lg'}"
501
+ onkeydown={handleShortcut}
452
502
  >
453
503
  <Resizable.PaneGroup direction="horizontal" class="h-full w-full">
454
504
  <!-- `defaultSize` must sum to 100 across the live panes. Panes register a frame before the
@@ -462,7 +512,7 @@
462
512
  the DOM, so this is the only observable proof a solve's geometry decoded and
463
513
  rendered; e2e asserts on it. -->
464
514
  <canvas
465
- class="block h-full w-full"
515
+ class="viewer-canvas block h-full w-full outline-none select-none"
466
516
  data-testid="viewer-canvas"
467
517
  data-mesh-count={meshes.length}
468
518
  bind:this={canvas}
@@ -474,10 +524,6 @@
474
524
  : 'blur-overlay-inactive'}"
475
525
  ></div>
476
526
 
477
- {#if isSolving}
478
- <div class="inset-0 animate-in fade-in backdrop-blur-xs absolute z-10 duration-200"></div>
479
- {/if}
480
-
481
527
  {#if logoUrl}
482
528
  <!-- pointer-events:none so it never intercepts canvas drags. -->
483
529
  <div
@@ -503,143 +549,36 @@
503
549
  {/if}
504
550
 
505
551
  {#if config.showToolsMenu}
506
- <div
507
- class="left-4 bottom-4 gap-2 *:shadow-lg absolute z-50 flex items-center *:rounded-md {hideButton
508
- ? 'pointer-events-none opacity-0'
509
- : ''}"
510
- >
511
- <DropdownMenu.Root>
512
- <DropdownMenu.Trigger>
513
- {#snippet child({ props })}
514
- <Button
515
- {...props}
516
- variant="outline"
517
- size="icon-lg"
518
- title={t.toolsMenu}
519
- aria-label={t.toolsMenu}
520
- >
521
- <Settings2 />
522
- </Button>
523
- {/snippet}
524
- </DropdownMenu.Trigger>
525
- <!-- Above the fullscreen viewer, which sits at z-index 10000. -->
526
- <DropdownMenu.Content sideOffset={6} class="min-w-44 z-10001 w-auto">
527
- <DropdownMenu.Item onSelect={toggleProjection}>
528
- {#if projection === 'perspective'}
529
- <Square />
530
- {t.switchToOrthographic}
531
- {:else}
532
- <Box />
533
- {t.switchToPerspective}
534
- {/if}
535
- </DropdownMenu.Item>
536
- <DropdownMenu.Item onSelect={() => fitToView?.()}>
537
- <Frame />
538
- {t.fitToView}
539
- </DropdownMenu.Item>
540
-
541
- <DropdownMenu.Sub>
542
- <DropdownMenu.SubTrigger>
543
- <Box />
544
- {t.views}
545
- </DropdownMenu.SubTrigger>
546
- <DropdownMenu.SubContent class="z-10001">
547
- {#each VIEW_PRESETS as { preset, label } (preset)}
548
- <DropdownMenu.Item onSelect={() => setView(preset)}
549
- >{label()}</DropdownMenu.Item
550
- >
551
- {/each}
552
- </DropdownMenu.SubContent>
553
- </DropdownMenu.Sub>
554
-
555
- {#if config.showDisplayMenu}
556
- <DropdownMenu.Sub>
557
- <DropdownMenu.SubTrigger>
558
- <Palette />
559
- {t.display}
560
- </DropdownMenu.SubTrigger>
561
- <DropdownMenu.SubContent class="min-w-40 z-10001">
562
- <DropdownMenu.RadioGroup
563
- value={renderStyle}
564
- onValueChange={(look) => setRenderStyle(look as typeof renderStyle)}
565
- >
566
- {#each styleOptions as { look, label } (look)}
567
- <DropdownMenu.RadioItem value={look} closeOnSelect={false}>
568
- {label}
569
- </DropdownMenu.RadioItem>
570
- {/each}
571
- </DropdownMenu.RadioGroup>
572
- <DropdownMenu.Separator />
573
- <DropdownMenu.CheckboxItem
574
- checked={edgesVisible}
575
- onCheckedChange={toggleEdges}
576
- >
577
- <Spline />
578
- {t.edges}
579
- </DropdownMenu.CheckboxItem>
580
- </DropdownMenu.SubContent>
581
- </DropdownMenu.Sub>
582
- {/if}
583
-
584
- <DropdownMenu.CheckboxItem checked={measureActive} onCheckedChange={toggleMeasure}>
585
- <Ruler />
586
- {t.measure}
587
- </DropdownMenu.CheckboxItem>
588
-
589
- {#if config.showGridToggle}
590
- <DropdownMenu.CheckboxItem checked={gridVisible} onCheckedChange={toggleGrid}>
591
- <Grid3x3 />
592
- {t.grid}
593
- </DropdownMenu.CheckboxItem>
594
- {/if}
595
-
596
- {#if config.showSceneManager || config.showScreenshotButton || config.showFullscreenButton}
597
- <DropdownMenu.Separator />
598
- {/if}
599
-
600
- {#if config.showSceneManager}
601
- <DropdownMenu.CheckboxItem
602
- checked={sceneManagerOpen}
603
- onCheckedChange={() => (sceneManagerOpen = !sceneManagerOpen)}
604
- >
605
- <Layers />
606
- {t.sceneManager}
607
- </DropdownMenu.CheckboxItem>
608
- {/if}
609
-
610
- {#if config.showScreenshotButton}
611
- <DropdownMenu.Item onSelect={downloadScreenshot}>
612
- <Camera />
613
- {t.screenshot}
614
- </DropdownMenu.Item>
615
- {/if}
616
-
617
- {#if config.showFullscreenButton}
618
- <DropdownMenu.Item onSelect={toggleFullscreen}>
619
- {#if isFullscreen}
620
- <Minimize />
621
- {t.exitFullscreen}
622
- {:else}
623
- <Maximize />
624
- {t.fullscreen}
625
- {/if}
626
- </DropdownMenu.Item>
627
- {/if}
628
- </DropdownMenu.Content>
629
- </DropdownMenu.Root>
630
- <!-- Touch has no F key, and fit-to-view is the way back from a framed part. -->
631
- <div class="hidden pointer-coarse:block">
632
- <Button
633
- variant="outline"
634
- size="icon-lg"
635
- title={t.fitToView}
636
- aria-label={t.fitToView}
637
- onclick={() => fitToView?.()}
638
- >
639
- <Frame />
640
- </Button>
641
- </div>
642
- </div>
552
+ <ViewerDock
553
+ {t}
554
+ hidden={hideButton}
555
+ showDisplay={config.showDisplayMenu}
556
+ showGrid={config.showGridToggle}
557
+ showSceneManager={config.showSceneManager}
558
+ showScreenshot={config.showScreenshotButton}
559
+ showFullscreen={config.showFullscreenButton}
560
+ {styleOptions}
561
+ viewPresets={VIEW_PRESETS.map(({ preset, label }) => ({ preset, label: label() }))}
562
+ {renderStyle}
563
+ {nightOn}
564
+ {edgesVisible}
565
+ {measureActive}
566
+ {gridVisible}
567
+ {sceneManagerOpen}
568
+ {projection}
569
+ {isFullscreen}
570
+ onSetLook={setRenderStyle}
571
+ onToggleNight={toggleNight}
572
+ onToggleEdges={toggleEdges}
573
+ onToggleMeasure={toggleMeasure}
574
+ onToggleGrid={toggleGrid}
575
+ onToggleSceneManager={() => (sceneManagerOpen = !sceneManagerOpen)}
576
+ onToggleProjection={toggleProjection}
577
+ onSetView={setView}
578
+ onFit={() => fitToView?.()}
579
+ onScreenshot={downloadScreenshot}
580
+ onToggleFullscreen={toggleFullscreen}
581
+ />
643
582
  {/if}
644
583
  </div>
645
584
  </Resizable.Pane>
@@ -647,7 +586,12 @@
647
586
  {#if sceneManagerOpen && scene && outliner}
648
587
  <Resizable.Handle withHandle />
649
588
  <Resizable.Pane id="scene-manager" order={2} defaultSize={15} minSize={8} maxSize={30}>
650
- <SceneManager {outliner} {sceneVersion} onVisibilityChange={() => invalidate?.()} />
589
+ <SceneManager
590
+ {outliner}
591
+ {sceneVersion}
592
+ onVisibilityChange={() => syncEmissiveLights?.()}
593
+ onHover={(entry) => setHover?.(entry?.object ?? null, entry?.memberIndex ?? null)}
594
+ />
651
595
  </Resizable.Pane>
652
596
  {/if}
653
597
  </Resizable.PaneGroup>
@@ -666,6 +610,12 @@
666
610
  border-radius: 0 !important;
667
611
  }
668
612
 
613
+ /* A long press on touch otherwise selects the canvas as an image and opens the save/copy callout. */
614
+ .viewer-canvas {
615
+ -webkit-touch-callout: none;
616
+ -webkit-tap-highlight-color: transparent;
617
+ }
618
+
669
619
  .blur-overlay {
670
620
  pointer-events: none;
671
621
  }
@@ -1,5 +1,5 @@
1
- import { type ThreeViewer } from '@selvajs/visualization/render';
2
- import type { Locale } from '../../i18n/messages';
1
+ import { type Look, type ThreeViewer } from '@selvajs/visualization/render';
2
+ import type { Locale } from '../../i18n/messages.js';
3
3
  export interface ViewerConfig {
4
4
  showScreenshotButton?: boolean;
5
5
  showFullscreenButton?: boolean;
@@ -9,13 +9,18 @@ export interface ViewerConfig {
9
9
  showDisplayMenu?: boolean;
10
10
  enableMeshClick?: boolean;
11
11
  backgroundColor?: string;
12
+ /** The look to open in. Default `technical`. */
13
+ look?: Look;
12
14
  /** Initial state of the edge overlay and its display-menu checkmark. Default false. */
13
15
  showEdges?: boolean;
14
16
  }
15
17
  interface Props {
16
18
  meshes: any[];
17
19
  isFullscreen?: boolean;
20
+ /** @deprecated Ignored: the panel's solve status shows a running solve. */
18
21
  isSolving?: boolean;
22
+ /** @deprecated Ignored, like `isSolving`. */
23
+ isSlow?: boolean;
19
24
  isBlurred?: boolean;
20
25
  drawerOpen?: boolean;
21
26
  viewerConfig?: ViewerConfig;