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

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 (348) hide show
  1. package/dist/components/ConfirmDialog.svelte +2 -10
  2. package/dist/components/ErrorScreen.svelte +16 -26
  3. package/dist/components/compute/AppLayout.svelte +7 -13
  4. package/dist/components/compute/ComputeApp.svelte +3 -3
  5. package/dist/components/compute/ComputeMessagesDialog.svelte +23 -49
  6. package/dist/components/compute/ParameterPresetManager.svelte +24 -68
  7. package/dist/components/compute/SolveMessages.svelte +23 -31
  8. package/dist/components/layout/Pagination.svelte +2 -4
  9. package/dist/components/layout/SideNav.svelte +1 -1
  10. package/dist/components/preview/ChartOutput.svelte +1 -5
  11. package/dist/components/preview/Group.svelte +71 -102
  12. package/dist/components/preview/Group.svelte.d.ts +1 -1
  13. package/dist/components/preview/HelpButton.svelte +34 -0
  14. package/dist/components/preview/HelpButton.svelte.d.ts +8 -0
  15. package/dist/components/preview/ImageOutput.svelte +2 -4
  16. package/dist/components/preview/InputControl.svelte +45 -45
  17. package/dist/components/preview/OutputDisplay.svelte +12 -22
  18. package/dist/components/preview/TabBar.svelte +106 -22
  19. package/dist/components/preview/TabBar.svelte.d.ts +1 -0
  20. package/dist/components/preview/TabContent.svelte +27 -56
  21. package/dist/components/preview/TabLayout.svelte +3 -3
  22. package/dist/components/preview/inputs/CheckboxInput.svelte +7 -7
  23. package/dist/components/preview/inputs/CheckboxInput.svelte.d.ts +3 -0
  24. package/dist/components/preview/inputs/ColorInput.svelte +1 -1
  25. package/dist/components/preview/inputs/FileInput.svelte +10 -13
  26. package/dist/components/preview/inputs/NumberInput.svelte +37 -57
  27. package/dist/components/preview/inputs/TextInput.svelte +0 -1
  28. package/dist/components/primitives/CalculateButton.svelte +1 -1
  29. package/dist/components/primitives/Callout.svelte +11 -18
  30. package/dist/components/primitives/DataTable.svelte +3 -4
  31. package/dist/components/primitives/FilterableDropdown.svelte +42 -129
  32. package/dist/components/primitives/FilterableDropdown.svelte.d.ts +1 -1
  33. package/dist/components/primitives/IssueList.svelte +56 -0
  34. package/dist/components/primitives/IssueList.svelte.d.ts +20 -0
  35. package/dist/components/primitives/SeverityIcon.svelte +15 -0
  36. package/dist/components/primitives/SeverityIcon.svelte.d.ts +8 -0
  37. package/dist/components/primitives/SolvingIndicator.svelte +1 -29
  38. package/dist/components/primitives/StateDisplay.svelte +19 -79
  39. package/dist/components/primitives/ViewToggle.svelte +18 -33
  40. package/dist/components/primitives/alert-dialog/alert-dialog-action.svelte +9 -3
  41. package/dist/components/primitives/alert-dialog/alert-dialog-action.svelte.d.ts +6 -1
  42. package/dist/components/primitives/alert-dialog/alert-dialog-content.svelte +1 -1
  43. package/dist/components/primitives/alert-dialog/alert-dialog-overlay.svelte +1 -1
  44. package/dist/components/primitives/badge/badge.svelte +2 -2
  45. package/dist/components/primitives/badge/badge.svelte.d.ts +4 -4
  46. package/dist/components/primitives/button/button.svelte +3 -2
  47. package/dist/components/primitives/button/button.svelte.d.ts +7 -4
  48. package/dist/components/primitives/card/card-header.svelte +1 -1
  49. package/dist/components/primitives/card/card.svelte +21 -5
  50. package/dist/components/primitives/card/card.svelte.d.ts +25 -1
  51. package/dist/components/primitives/card/index.d.ts +1 -2
  52. package/dist/components/primitives/card/index.js +2 -3
  53. package/dist/components/primitives/checkbox/checkbox.svelte +1 -1
  54. package/dist/components/primitives/command/command-dialog.svelte +42 -0
  55. package/dist/components/primitives/command/command-dialog.svelte.d.ts +14 -0
  56. package/dist/components/primitives/command/command-empty.svelte +17 -0
  57. package/dist/components/primitives/command/command-empty.svelte.d.ts +4 -0
  58. package/dist/components/primitives/command/command-group.svelte +33 -0
  59. package/dist/components/primitives/command/command-group.svelte.d.ts +7 -0
  60. package/dist/components/primitives/command/command-input.svelte +36 -0
  61. package/dist/components/primitives/command/command-input.svelte.d.ts +4 -0
  62. package/dist/components/primitives/command/command-item.svelte +28 -0
  63. package/dist/components/primitives/command/command-item.svelte.d.ts +4 -0
  64. package/dist/components/primitives/command/command-link-item.svelte +21 -0
  65. package/dist/components/primitives/command/command-link-item.svelte.d.ts +4 -0
  66. package/dist/components/primitives/command/command-list.svelte +20 -0
  67. package/dist/components/primitives/command/command-list.svelte.d.ts +4 -0
  68. package/dist/components/primitives/command/command-loading.svelte +7 -0
  69. package/dist/components/primitives/command/command-loading.svelte.d.ts +4 -0
  70. package/dist/components/primitives/command/command-separator.svelte +17 -0
  71. package/dist/components/primitives/command/command-separator.svelte.d.ts +4 -0
  72. package/dist/components/primitives/command/command-shortcut.svelte +23 -0
  73. package/dist/components/primitives/command/command-shortcut.svelte.d.ts +5 -0
  74. package/dist/components/primitives/command/command.svelte +28 -0
  75. package/dist/components/primitives/command/command.svelte.d.ts +8 -0
  76. package/dist/components/primitives/command/index.d.ts +12 -0
  77. package/dist/components/primitives/command/index.js +14 -0
  78. package/dist/components/primitives/context-menu/context-menu-content.svelte +1 -1
  79. package/dist/components/primitives/context-menu/context-menu-sub-content.svelte +1 -1
  80. package/dist/components/primitives/dialog/dialog-content.svelte +5 -1
  81. package/dist/components/primitives/dialog/dialog-content.svelte.d.ts +2 -0
  82. package/dist/components/primitives/dialog/dialog-overlay.svelte +1 -1
  83. package/dist/components/primitives/dialog/dialog-title.svelte +6 -2
  84. package/dist/components/primitives/dialog/dialog-title.svelte.d.ts +5 -1
  85. package/dist/components/primitives/drawer/Drawer.svelte +1 -1
  86. package/dist/components/primitives/dropdown-menu/dropdown-menu-checkbox-group.svelte +16 -0
  87. package/dist/components/primitives/dropdown-menu/dropdown-menu-checkbox-group.svelte.d.ts +4 -0
  88. package/dist/components/primitives/dropdown-menu/dropdown-menu-checkbox-item.svelte +46 -0
  89. package/dist/components/primitives/dropdown-menu/dropdown-menu-checkbox-item.svelte.d.ts +9 -0
  90. package/dist/components/primitives/dropdown-menu/dropdown-menu-content.svelte +31 -0
  91. package/dist/components/primitives/dropdown-menu/dropdown-menu-content.svelte.d.ts +10 -0
  92. package/dist/components/primitives/dropdown-menu/dropdown-menu-group-heading.svelte +22 -0
  93. package/dist/components/primitives/dropdown-menu/dropdown-menu-group-heading.svelte.d.ts +8 -0
  94. package/dist/components/primitives/dropdown-menu/dropdown-menu-group.svelte +7 -0
  95. package/dist/components/primitives/dropdown-menu/dropdown-menu-group.svelte.d.ts +4 -0
  96. package/dist/components/primitives/dropdown-menu/dropdown-menu-item.svelte +27 -0
  97. package/dist/components/primitives/dropdown-menu/dropdown-menu-item.svelte.d.ts +8 -0
  98. package/dist/components/primitives/dropdown-menu/dropdown-menu-label.svelte +24 -0
  99. package/dist/components/primitives/dropdown-menu/dropdown-menu-label.svelte.d.ts +8 -0
  100. package/dist/components/primitives/dropdown-menu/dropdown-menu-portal.svelte +7 -0
  101. package/dist/components/primitives/dropdown-menu/dropdown-menu-portal.svelte.d.ts +3 -0
  102. package/dist/components/primitives/dropdown-menu/dropdown-menu-radio-group.svelte +16 -0
  103. package/dist/components/primitives/dropdown-menu/dropdown-menu-radio-group.svelte.d.ts +4 -0
  104. package/dist/components/primitives/dropdown-menu/dropdown-menu-radio-item.svelte +36 -0
  105. package/dist/components/primitives/dropdown-menu/dropdown-menu-radio-item.svelte.d.ts +4 -0
  106. package/dist/components/primitives/dropdown-menu/dropdown-menu-separator.svelte +17 -0
  107. package/dist/components/primitives/dropdown-menu/dropdown-menu-separator.svelte.d.ts +4 -0
  108. package/dist/components/primitives/dropdown-menu/dropdown-menu-shortcut.svelte +23 -0
  109. package/dist/components/primitives/dropdown-menu/dropdown-menu-shortcut.svelte.d.ts +5 -0
  110. package/dist/components/primitives/dropdown-menu/dropdown-menu-sub-content.svelte +31 -0
  111. package/dist/components/primitives/dropdown-menu/dropdown-menu-sub-content.svelte.d.ts +10 -0
  112. package/dist/components/primitives/dropdown-menu/dropdown-menu-sub-trigger.svelte +29 -0
  113. package/dist/components/primitives/dropdown-menu/dropdown-menu-sub-trigger.svelte.d.ts +7 -0
  114. package/dist/components/primitives/dropdown-menu/dropdown-menu-sub.svelte +7 -0
  115. package/dist/components/primitives/dropdown-menu/dropdown-menu-sub.svelte.d.ts +3 -0
  116. package/dist/components/primitives/dropdown-menu/dropdown-menu-trigger.svelte +7 -0
  117. package/dist/components/primitives/dropdown-menu/dropdown-menu-trigger.svelte.d.ts +4 -0
  118. package/dist/components/primitives/dropdown-menu/dropdown-menu.svelte +7 -0
  119. package/dist/components/primitives/dropdown-menu/dropdown-menu.svelte.d.ts +3 -0
  120. package/dist/components/primitives/dropdown-menu/index.d.ts +18 -0
  121. package/dist/components/primitives/dropdown-menu/index.js +18 -0
  122. package/dist/components/primitives/{alert/alert-description.svelte → empty/empty-content.svelte} +3 -3
  123. package/dist/components/primitives/empty/empty-content.svelte.d.ts +5 -0
  124. package/dist/components/primitives/empty/empty-description.svelte +23 -0
  125. package/dist/components/primitives/{alert/alert-description.svelte.d.ts → empty/empty-description.svelte.d.ts} +4 -4
  126. package/dist/components/primitives/{alert/alert-title.svelte → empty/empty-header.svelte} +3 -3
  127. package/dist/components/primitives/empty/empty-header.svelte.d.ts +5 -0
  128. package/dist/components/primitives/empty/empty-media.svelte +41 -0
  129. package/dist/components/primitives/empty/empty-media.svelte.d.ts +26 -0
  130. package/dist/components/primitives/{card/card-action.svelte → empty/empty-title.svelte} +2 -2
  131. package/dist/components/primitives/{card/card-action.svelte.d.ts → empty/empty-title.svelte.d.ts} +3 -3
  132. package/dist/components/primitives/empty/empty.svelte +23 -0
  133. package/dist/components/primitives/empty/empty.svelte.d.ts +5 -0
  134. package/dist/components/primitives/empty/index.d.ts +7 -0
  135. package/dist/components/primitives/empty/index.js +9 -0
  136. package/dist/components/primitives/index.d.ts +10 -1
  137. package/dist/components/primitives/index.js +10 -1
  138. package/dist/components/primitives/input/input.svelte +4 -4
  139. package/dist/components/primitives/input-group/index.d.ts +7 -0
  140. package/dist/components/primitives/input-group/index.js +9 -0
  141. package/dist/components/primitives/input-group/input-group-addon.svelte +53 -0
  142. package/dist/components/primitives/input-group/input-group-addon.svelte.d.ts +32 -0
  143. package/dist/components/primitives/input-group/input-group-button.svelte +49 -0
  144. package/dist/components/primitives/input-group/input-group-button.svelte.d.ts +32 -0
  145. package/dist/components/primitives/input-group/input-group-input.svelte +25 -0
  146. package/dist/components/primitives/input-group/input-group-input.svelte.d.ts +11 -0
  147. package/dist/components/primitives/input-group/input-group-text.svelte +22 -0
  148. package/dist/components/primitives/input-group/input-group-text.svelte.d.ts +5 -0
  149. package/dist/components/primitives/input-group/input-group-textarea.svelte +23 -0
  150. package/dist/components/primitives/input-group/input-group-textarea.svelte.d.ts +3 -0
  151. package/dist/components/primitives/input-group/input-group.svelte +24 -0
  152. package/dist/components/primitives/{alert/alert-title.svelte.d.ts → input-group/input-group.svelte.d.ts} +4 -4
  153. package/dist/components/primitives/mode-toggle/mode-toggle.svelte +2 -6
  154. package/dist/components/primitives/popover/index.d.ts +9 -0
  155. package/dist/components/primitives/popover/index.js +11 -0
  156. package/dist/components/primitives/popover/popover-close.svelte +7 -0
  157. package/dist/components/primitives/popover/popover-close.svelte.d.ts +4 -0
  158. package/dist/components/primitives/popover/popover-content.svelte +31 -0
  159. package/dist/components/primitives/popover/popover-content.svelte.d.ts +10 -0
  160. package/dist/components/primitives/popover/popover-description.svelte +20 -0
  161. package/dist/components/primitives/popover/popover-description.svelte.d.ts +5 -0
  162. package/dist/components/primitives/popover/popover-header.svelte +20 -0
  163. package/dist/components/primitives/popover/popover-header.svelte.d.ts +5 -0
  164. package/dist/components/primitives/popover/popover-portal.svelte +7 -0
  165. package/dist/components/primitives/popover/popover-portal.svelte.d.ts +3 -0
  166. package/dist/components/primitives/popover/popover-title.svelte +15 -0
  167. package/dist/components/primitives/popover/popover-title.svelte.d.ts +5 -0
  168. package/dist/components/primitives/popover/popover-trigger.svelte +17 -0
  169. package/dist/components/primitives/popover/popover-trigger.svelte.d.ts +4 -0
  170. package/dist/components/primitives/popover/popover.svelte +7 -0
  171. package/dist/components/primitives/popover/popover.svelte.d.ts +3 -0
  172. package/dist/components/primitives/resizable/resizable-handle.svelte +6 -2
  173. package/dist/components/primitives/resizable/resizable-handle.svelte.d.ts +2 -0
  174. package/dist/components/primitives/resizable/resizable-pane-group.svelte +1 -4
  175. package/dist/components/primitives/scroll-area/scroll-area.svelte +1 -1
  176. package/dist/components/primitives/search/search.svelte +3 -3
  177. package/dist/components/primitives/select/select-content.svelte +1 -1
  178. package/dist/components/primitives/select/select-trigger.svelte +1 -1
  179. package/dist/components/primitives/severity.d.ts +7 -0
  180. package/dist/components/primitives/severity.js +19 -0
  181. package/dist/components/primitives/slider/slider.svelte +2 -2
  182. package/dist/components/primitives/sonner/sonner.svelte +1 -1
  183. package/dist/components/primitives/spinner/index.d.ts +1 -0
  184. package/dist/components/primitives/spinner/index.js +1 -0
  185. package/dist/components/primitives/spinner/spinner.svelte +29 -0
  186. package/dist/components/primitives/spinner/spinner.svelte.d.ts +4 -0
  187. package/dist/components/primitives/switch/switch.svelte +2 -2
  188. package/dist/components/primitives/tabs/tabs-list.svelte +27 -5
  189. package/dist/components/primitives/tabs/tabs-list.svelte.d.ts +22 -1
  190. package/dist/components/primitives/tabs/tabs-trigger.svelte +23 -5
  191. package/dist/components/primitives/tabs/tabs-trigger.svelte.d.ts +22 -1
  192. package/dist/components/primitives/tabs/tabs.svelte +6 -2
  193. package/dist/components/primitives/tabs/tabs.svelte.d.ts +5 -1
  194. package/dist/components/primitives/textarea/textarea.svelte +1 -1
  195. package/dist/components/primitives/theme-switcher/ThemeSwitcher.svelte +1 -1
  196. package/dist/components/primitives/toggle/index.d.ts +3 -0
  197. package/dist/components/primitives/toggle/index.js +5 -0
  198. package/dist/components/primitives/toggle/toggle.svelte +52 -0
  199. package/dist/components/primitives/toggle/toggle.svelte.d.ts +43 -0
  200. package/dist/components/primitives/toggle-group/index.d.ts +3 -0
  201. package/dist/components/primitives/toggle-group/index.js +5 -0
  202. package/dist/components/primitives/toggle-group/toggle-group-item.svelte +35 -0
  203. package/dist/components/primitives/toggle-group/toggle-group-item.svelte.d.ts +6 -0
  204. package/dist/components/primitives/toggle-group/toggle-group.svelte +75 -0
  205. package/dist/components/primitives/toggle-group/toggle-group.svelte.d.ts +17 -0
  206. package/dist/components/viewer/MeshMetadataDialog.svelte +3 -3
  207. package/dist/components/viewer/SceneManager.svelte +14 -5
  208. package/dist/components/viewer/Viewer.svelte +120 -171
  209. package/dist/i18n/messages.d.ts +2 -0
  210. package/dist/i18n/messages.js +4 -0
  211. package/dist/styles/base.css +43 -0
  212. package/package.json +6 -6
  213. package/src/lib/components/ConfirmDialog.svelte +2 -10
  214. package/src/lib/components/ErrorScreen.svelte +16 -26
  215. package/src/lib/components/compute/AppLayout.svelte +7 -13
  216. package/src/lib/components/compute/ComputeApp.svelte +3 -3
  217. package/src/lib/components/compute/ComputeMessagesDialog.svelte +23 -49
  218. package/src/lib/components/compute/ParameterPresetManager.svelte +24 -68
  219. package/src/lib/components/compute/SolveMessages.svelte +23 -31
  220. package/src/lib/components/layout/Pagination.svelte +2 -4
  221. package/src/lib/components/layout/SideNav.svelte +1 -1
  222. package/src/lib/components/preview/ChartOutput.svelte +1 -5
  223. package/src/lib/components/preview/Group.svelte +71 -102
  224. package/src/lib/components/preview/HelpButton.svelte +34 -0
  225. package/src/lib/components/preview/ImageOutput.svelte +2 -4
  226. package/src/lib/components/preview/InputControl.svelte +45 -45
  227. package/src/lib/components/preview/OutputDisplay.svelte +12 -22
  228. package/src/lib/components/preview/TabBar.svelte +106 -22
  229. package/src/lib/components/preview/TabContent.svelte +27 -56
  230. package/src/lib/components/preview/TabLayout.svelte +3 -3
  231. package/src/lib/components/preview/inputs/CheckboxInput.svelte +7 -7
  232. package/src/lib/components/preview/inputs/ColorInput.svelte +1 -1
  233. package/src/lib/components/preview/inputs/FileInput.svelte +10 -13
  234. package/src/lib/components/preview/inputs/NumberInput.svelte +37 -57
  235. package/src/lib/components/preview/inputs/TextInput.svelte +0 -1
  236. package/src/lib/components/primitives/CalculateButton.svelte +1 -1
  237. package/src/lib/components/primitives/Callout.svelte +11 -18
  238. package/src/lib/components/primitives/DataTable.svelte +3 -4
  239. package/src/lib/components/primitives/FilterableDropdown.svelte +42 -129
  240. package/src/lib/components/primitives/IssueList.svelte +56 -0
  241. package/src/lib/components/primitives/SeverityIcon.svelte +15 -0
  242. package/src/lib/components/primitives/SolvingIndicator.svelte +1 -29
  243. package/src/lib/components/primitives/StateDisplay.svelte +19 -79
  244. package/src/lib/components/primitives/ViewToggle.svelte +18 -33
  245. package/src/lib/components/primitives/alert-dialog/alert-dialog-action.svelte +9 -3
  246. package/src/lib/components/primitives/alert-dialog/alert-dialog-content.svelte +1 -1
  247. package/src/lib/components/primitives/alert-dialog/alert-dialog-overlay.svelte +1 -1
  248. package/src/lib/components/primitives/badge/badge.svelte +2 -2
  249. package/src/lib/components/primitives/button/button.svelte +3 -2
  250. package/src/lib/components/primitives/card/card-header.svelte +1 -1
  251. package/src/lib/components/primitives/card/card.svelte +21 -5
  252. package/src/lib/components/primitives/card/index.ts +1 -4
  253. package/src/lib/components/primitives/checkbox/checkbox.svelte +1 -1
  254. package/src/lib/components/primitives/command/command-dialog.svelte +42 -0
  255. package/src/lib/components/primitives/command/command-empty.svelte +17 -0
  256. package/src/lib/components/primitives/command/command-group.svelte +33 -0
  257. package/src/lib/components/primitives/command/command-input.svelte +36 -0
  258. package/src/lib/components/primitives/command/command-item.svelte +28 -0
  259. package/src/lib/components/primitives/command/command-link-item.svelte +21 -0
  260. package/src/lib/components/primitives/command/command-list.svelte +20 -0
  261. package/src/lib/components/primitives/command/command-loading.svelte +7 -0
  262. package/src/lib/components/primitives/command/command-separator.svelte +17 -0
  263. package/src/lib/components/primitives/command/command-shortcut.svelte +23 -0
  264. package/src/lib/components/primitives/command/command.svelte +28 -0
  265. package/src/lib/components/primitives/command/index.ts +37 -0
  266. package/src/lib/components/primitives/context-menu/context-menu-content.svelte +1 -1
  267. package/src/lib/components/primitives/context-menu/context-menu-sub-content.svelte +1 -1
  268. package/src/lib/components/primitives/dialog/dialog-content.svelte +5 -1
  269. package/src/lib/components/primitives/dialog/dialog-overlay.svelte +1 -1
  270. package/src/lib/components/primitives/dialog/dialog-title.svelte +6 -2
  271. package/src/lib/components/primitives/drawer/Drawer.svelte +1 -1
  272. package/src/lib/components/primitives/dropdown-menu/dropdown-menu-checkbox-group.svelte +16 -0
  273. package/src/lib/components/primitives/dropdown-menu/dropdown-menu-checkbox-item.svelte +46 -0
  274. package/src/lib/components/primitives/dropdown-menu/dropdown-menu-content.svelte +31 -0
  275. package/src/lib/components/primitives/dropdown-menu/dropdown-menu-group-heading.svelte +22 -0
  276. package/src/lib/components/primitives/dropdown-menu/dropdown-menu-group.svelte +7 -0
  277. package/src/lib/components/primitives/dropdown-menu/dropdown-menu-item.svelte +27 -0
  278. package/src/lib/components/primitives/dropdown-menu/dropdown-menu-label.svelte +24 -0
  279. package/src/lib/components/primitives/dropdown-menu/dropdown-menu-portal.svelte +7 -0
  280. package/src/lib/components/primitives/dropdown-menu/dropdown-menu-radio-group.svelte +16 -0
  281. package/src/lib/components/primitives/dropdown-menu/dropdown-menu-radio-item.svelte +36 -0
  282. package/src/lib/components/primitives/dropdown-menu/dropdown-menu-separator.svelte +17 -0
  283. package/src/lib/components/primitives/dropdown-menu/dropdown-menu-shortcut.svelte +23 -0
  284. package/src/lib/components/primitives/dropdown-menu/dropdown-menu-sub-content.svelte +31 -0
  285. package/src/lib/components/primitives/dropdown-menu/dropdown-menu-sub-trigger.svelte +29 -0
  286. package/src/lib/components/primitives/dropdown-menu/dropdown-menu-sub.svelte +7 -0
  287. package/src/lib/components/primitives/dropdown-menu/dropdown-menu-trigger.svelte +7 -0
  288. package/src/lib/components/primitives/dropdown-menu/dropdown-menu.svelte +7 -0
  289. package/src/lib/components/primitives/dropdown-menu/index.ts +54 -0
  290. package/src/lib/components/primitives/{alert/alert-description.svelte → empty/empty-content.svelte} +3 -3
  291. package/src/lib/components/primitives/empty/empty-description.svelte +23 -0
  292. package/src/lib/components/primitives/{alert/alert-title.svelte → empty/empty-header.svelte} +3 -3
  293. package/src/lib/components/primitives/empty/empty-media.svelte +41 -0
  294. package/src/lib/components/primitives/{card/card-action.svelte → empty/empty-title.svelte} +2 -2
  295. package/src/lib/components/primitives/empty/empty.svelte +23 -0
  296. package/src/lib/components/primitives/empty/index.ts +22 -0
  297. package/src/lib/components/primitives/index.ts +10 -1
  298. package/src/lib/components/primitives/input/input.svelte +4 -4
  299. package/src/lib/components/primitives/input-group/index.ts +22 -0
  300. package/src/lib/components/primitives/input-group/input-group-addon.svelte +53 -0
  301. package/src/lib/components/primitives/input-group/input-group-button.svelte +49 -0
  302. package/src/lib/components/primitives/input-group/input-group-input.svelte +25 -0
  303. package/src/lib/components/primitives/input-group/input-group-text.svelte +22 -0
  304. package/src/lib/components/primitives/input-group/input-group-textarea.svelte +23 -0
  305. package/src/lib/components/primitives/input-group/input-group.svelte +24 -0
  306. package/src/lib/components/primitives/mode-toggle/mode-toggle.svelte +2 -6
  307. package/src/lib/components/primitives/popover/index.ts +28 -0
  308. package/src/lib/components/primitives/popover/popover-close.svelte +7 -0
  309. package/src/lib/components/primitives/popover/popover-content.svelte +31 -0
  310. package/src/lib/components/primitives/popover/popover-description.svelte +20 -0
  311. package/src/lib/components/primitives/popover/popover-header.svelte +20 -0
  312. package/src/lib/components/primitives/popover/popover-portal.svelte +7 -0
  313. package/src/lib/components/primitives/popover/popover-title.svelte +15 -0
  314. package/src/lib/components/primitives/popover/popover-trigger.svelte +17 -0
  315. package/src/lib/components/primitives/popover/popover.svelte +7 -0
  316. package/src/lib/components/primitives/resizable/resizable-handle.svelte +6 -2
  317. package/src/lib/components/primitives/resizable/resizable-pane-group.svelte +1 -4
  318. package/src/lib/components/primitives/scroll-area/scroll-area.svelte +1 -1
  319. package/src/lib/components/primitives/search/search.svelte +3 -3
  320. package/src/lib/components/primitives/select/select-content.svelte +1 -1
  321. package/src/lib/components/primitives/select/select-trigger.svelte +1 -1
  322. package/src/lib/components/primitives/severity.ts +26 -0
  323. package/src/lib/components/primitives/slider/slider.svelte +2 -2
  324. package/src/lib/components/primitives/sonner/sonner.svelte +1 -1
  325. package/src/lib/components/primitives/spinner/index.ts +1 -0
  326. package/src/lib/components/primitives/spinner/spinner.svelte +29 -0
  327. package/src/lib/components/primitives/switch/switch.svelte +2 -2
  328. package/src/lib/components/primitives/tabs/tabs-list.svelte +27 -5
  329. package/src/lib/components/primitives/tabs/tabs-trigger.svelte +23 -5
  330. package/src/lib/components/primitives/tabs/tabs.svelte +6 -2
  331. package/src/lib/components/primitives/textarea/textarea.svelte +1 -1
  332. package/src/lib/components/primitives/theme-switcher/ThemeSwitcher.svelte +1 -1
  333. package/src/lib/components/primitives/toggle/index.ts +13 -0
  334. package/src/lib/components/primitives/toggle/toggle.svelte +52 -0
  335. package/src/lib/components/primitives/toggle-group/index.ts +10 -0
  336. package/src/lib/components/primitives/toggle-group/toggle-group-item.svelte +35 -0
  337. package/src/lib/components/primitives/toggle-group/toggle-group.svelte +75 -0
  338. package/src/lib/components/viewer/MeshMetadataDialog.svelte +3 -3
  339. package/src/lib/components/viewer/SceneManager.svelte +14 -5
  340. package/src/lib/components/viewer/Viewer.svelte +120 -171
  341. package/src/lib/i18n/messages.ts +6 -0
  342. package/src/lib/styles/base.css +43 -0
  343. package/dist/components/primitives/alert/alert.svelte +0 -44
  344. package/dist/components/primitives/alert/alert.svelte.d.ts +0 -26
  345. package/dist/components/primitives/alert/index.d.ts +0 -5
  346. package/dist/components/primitives/alert/index.js +0 -7
  347. package/src/lib/components/primitives/alert/alert.svelte +0 -44
  348. package/src/lib/components/primitives/alert/index.ts +0 -14
@@ -1,7 +1,6 @@
1
1
  <script lang="ts">
2
2
  import type { LayoutItem, InputLayoutItem, OutputLayoutItem } from '@selvajs/schemas';
3
3
  import type { Snippet } from 'svelte';
4
- import * as Card from '../primitives/card';
5
4
  import { ChevronDown } from '@lucide/svelte';
6
5
  import { buildVisibilityMap, itemKey } from '../../schema/visibility-rules';
7
6
 
@@ -20,7 +19,7 @@
20
19
  ]
21
20
  >;
22
21
  outputSnippet: Snippet<[layoutItem: OutputLayoutItem]>;
23
- /** When true, renders items flat without the Card wrapper, header, or collapse toggle. */
22
+ /** When true, renders items without the header or collapse toggle. */
24
23
  flat?: boolean;
25
24
  }
26
25
 
@@ -37,110 +36,84 @@
37
36
  flat = false
38
37
  }: Props = $props();
39
38
 
40
- function handleKeydown(e: KeyboardEvent) {
41
- if (e.key === 'Enter' || e.key === ' ') {
42
- e.preventDefault();
43
- onToggle();
44
- }
45
- }
46
-
47
- // One visibility evaluation per item per render; columnStarts and gridItem both read it.
48
39
  const visibilityMap = $derived(buildVisibilityMap(items, values));
49
40
 
50
- // Hidden items must not consume a slot here, because gridItem skips them entirely —
51
- // counting them would offset every following item's column.
52
- const columnStarts = $derived.by(() => {
53
- const positions: number[] = [];
54
- let col = 0;
55
- for (const item of items) {
56
- if (item.type === 'linebreak') {
57
- positions.push(0);
58
- col = 0;
59
- continue;
60
- }
61
- const visibility = visibilityMap[itemKey(item)];
62
- if (!visibility.visible) {
63
- positions.push(0);
64
- continue;
65
- }
66
- const span = Math.min(Math.max(1, item.span ?? 1), columns);
67
- if (col + span > columns) col = 0;
68
- positions.push(col);
69
- col = (col + span) % columns;
70
- }
71
- return positions;
72
- });
41
+ // Below this a label and its control stop fitting side by side, so a wide group
42
+ // sheds columns as its panel narrows instead of squeezing every input.
43
+ const MIN_COLUMN_WIDTH = 160;
44
+ const COLUMN_GAP = 16;
45
+
46
+ let gridWidth = $state(0);
47
+ const effectiveColumns = $derived(
48
+ gridWidth === 0
49
+ ? columns
50
+ : Math.max(
51
+ 1,
52
+ Math.min(columns, Math.floor((gridWidth + COLUMN_GAP) / (MIN_COLUMN_WIDTH + COLUMN_GAP)))
53
+ )
54
+ );
73
55
  </script>
74
56
 
75
- {#if flat}
76
- <div class="p-6">
77
- <div class="schema-grid gap-6 grid" style="--schema-cols: {columns};">
78
- {#each items as layoutItem, i (layoutItem.type === 'linebreak' ? layoutItem.id : layoutItem.paramId)}
79
- {@render gridItem(layoutItem, columns, columnStarts[i] === 0)}
80
- {/each}
81
- </div>
57
+ {#snippet grid()}
58
+ <div
59
+ class="schema-grid"
60
+ style="--schema-cols: {effectiveColumns}; --column-gap: {COLUMN_GAP}px;"
61
+ bind:clientWidth={gridWidth}
62
+ >
63
+ {#each items as layoutItem (layoutItem.type === 'linebreak' ? layoutItem.id : layoutItem.paramId)}
64
+ {@render gridItem(layoutItem)}
65
+ {/each}
82
66
  </div>
83
- {:else}
84
- <Card.Root class="gap-0 py-0 pt-0 overflow-hidden">
85
- <Card.Header
86
- class="pt-4 pb-4! cursor-pointer border-b border-border bg-muted transition-colors select-none hover:bg-muted/50 focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:outline-none"
87
- role="button"
88
- tabindex={0}
67
+ {/snippet}
68
+
69
+ <section class="shadow-xs rounded-xl bg-card">
70
+ {#if flat}
71
+ <div class="p-4">
72
+ {@render grid()}
73
+ </div>
74
+ {:else}
75
+ <button
76
+ type="button"
77
+ class="gap-3 px-4 py-3.5 flex w-full items-start text-left outline-none select-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-inset"
89
78
  aria-expanded={!collapsed}
90
79
  onclick={onToggle}
91
- onkeydown={handleKeydown}
92
80
  >
93
- <Card.Title>{label}</Card.Title>
94
- {#if description}
95
- <Card.Description>{description}</Card.Description>
96
- {/if}
97
- <Card.Action>
98
- <ChevronDown
99
- class="h-4 w-4 text-muted-foreground transition-transform duration-200 {collapsed
100
- ? ''
101
- : 'rotate-180'}"
102
- />
103
- </Card.Action>
104
- </Card.Header>
105
- <div class="content-wrapper" class:collapsed>
81
+ <span class="min-w-0 flex-1">
82
+ <span class="text-base font-semibold leading-snug block text-foreground">{label}</span>
83
+ {#if description}
84
+ <span class="text-xs mt-0.5 leading-snug block text-muted-foreground">{description}</span>
85
+ {/if}
86
+ </span>
87
+ <ChevronDown
88
+ class="mt-1 h-4 w-4 shrink-0 text-muted-foreground transition-transform duration-200 {collapsed
89
+ ? '-rotate-90'
90
+ : ''}"
91
+ />
92
+ </button>
93
+ <div class="content-wrapper" class:collapsed inert={collapsed}>
106
94
  <div class="content-inner">
107
- <Card.Content class="p-6">
108
- <div class="schema-grid gap-6 grid" style="--schema-cols: {columns};">
109
- {#each items as layoutItem, i (layoutItem.type === 'linebreak' ? layoutItem.id : layoutItem.paramId)}
110
- {@render gridItem(layoutItem, columns, columnStarts[i] === 0)}
111
- {/each}
112
- </div>
113
- </Card.Content>
95
+ <div class="px-4 pt-1 pb-5">
96
+ {@render grid()}
97
+ </div>
114
98
  </div>
115
99
  </div>
116
- </Card.Root>
117
- {/if}
100
+ {/if}
101
+ </section>
118
102
 
119
- {#snippet gridItem(layoutItem: LayoutItem, cols: number, isFirstInRow: boolean)}
103
+ {#snippet gridItem(layoutItem: LayoutItem)}
120
104
  {#if layoutItem.type === 'linebreak'}
121
- <div style="grid-column: 1 / -1" class="h-px bg-border" aria-hidden="true"></div>
105
+ <div class="grid-break" aria-hidden="true"></div>
122
106
  {:else}
123
107
  {@const visibility = visibilityMap[itemKey(layoutItem)]}
124
- {@const span = Math.min(Math.max(1, layoutItem.span ?? 1), cols)}
108
+ {@const span = Math.min(Math.max(1, layoutItem.span ?? 1), effectiveColumns)}
125
109
  {#if visibility.visible}
126
- {#if layoutItem.type === 'input'}
127
- <div
128
- class="grid-cell min-w-0 flex items-center"
129
- class:opacity-50={visibility.disabled}
130
- class:col-divider={!isFirstInRow && cols > 1}
131
- style="grid-column: span {span} / span {span}"
132
- >
110
+ <div class="grid-cell min-w-0" class:opacity-50={visibility.disabled} style="--span: {span}">
111
+ {#if layoutItem.type === 'input'}
133
112
  {@render inputSnippet(layoutItem, visibility)}
134
- </div>
135
- {:else if layoutItem.type === 'output'}
136
- <div
137
- class="grid-cell"
138
- class:col-divider={!isFirstInRow && cols > 1}
139
- style="grid-column: span {span} / span {span}"
140
- >
113
+ {:else if layoutItem.type === 'output'}
141
114
  {@render outputSnippet(layoutItem)}
142
- </div>
143
- {/if}
115
+ {/if}
116
+ </div>
144
117
  {/if}
145
118
  {/if}
146
119
  {/snippet}
@@ -158,27 +131,23 @@
158
131
 
159
132
  .content-inner {
160
133
  min-height: 0;
134
+ overflow: hidden;
161
135
  }
162
136
 
163
137
  .schema-grid {
138
+ display: grid;
164
139
  grid-template-columns: repeat(var(--schema-cols), minmax(0, 1fr));
140
+ gap: 1rem var(--column-gap);
141
+ align-items: start;
165
142
  }
166
143
 
167
- /* Vertical divider painted in the column gap. `gap-6` is 24px, so a 12px
168
- negative margin + 12px padding centres the 1px line in the gutter. */
169
- .col-divider {
170
- border-left: 1px solid var(--border);
171
- padding-left: 12px;
172
- margin-left: -12px;
144
+ .grid-cell {
145
+ grid-column: span var(--span) / span var(--span);
173
146
  }
174
147
 
175
- /* When the container collapses the grid to 1 visual column, the items are
176
- stacked and the divider would float on the left of every row. Hide it. */
177
- @container (max-width: 320px) {
178
- .col-divider {
179
- border-left: 0;
180
- padding-left: 0;
181
- margin-left: 0;
182
- }
148
+ /* An empty full-width row: the two row gaps around it already read as a break. */
149
+ .grid-break {
150
+ grid-column: 1 / -1;
151
+ margin-block: -0.25rem;
183
152
  }
184
153
  </style>
@@ -17,7 +17,7 @@ interface Props {
17
17
  }
18
18
  ]>;
19
19
  outputSnippet: Snippet<[layoutItem: OutputLayoutItem]>;
20
- /** When true, renders items flat without the Card wrapper, header, or collapse toggle. */
20
+ /** When true, renders items without the header or collapse toggle. */
21
21
  flat?: boolean;
22
22
  }
23
23
  declare const Group: import("svelte").Component<Props, {}, "">;
@@ -0,0 +1,34 @@
1
+ <script lang="ts">
2
+ import { HelpCircle } from '@lucide/svelte';
3
+ import * as Dialog from '../primitives/dialog';
4
+
5
+ interface Props {
6
+ /** The field's label: the dialog title and the button's accessible name. */
7
+ label: string;
8
+ description: string;
9
+ }
10
+
11
+ let { label, description }: Props = $props();
12
+ </script>
13
+
14
+ <!-- Every field has one, so a column of them is noise. Where a fine pointer can hover, it shows
15
+ only while the pointer or focus is inside the enclosing `group/field`; touch keeps it visible. -->
16
+ <Dialog.Root>
17
+ <Dialog.Trigger>
18
+ {#snippet child({ props })}
19
+ <button
20
+ {...props}
21
+ class="-m-1 p-1 shrink-0 cursor-help rounded-sm text-muted-foreground transition hover:text-foreground pointer-fine:opacity-0 pointer-fine:group-focus-within/field:opacity-100 pointer-fine:group-hover/field:opacity-100 pointer-fine:focus-visible:opacity-100"
22
+ aria-label={label}
23
+ >
24
+ <HelpCircle class="size-3.5" />
25
+ </button>
26
+ {/snippet}
27
+ </Dialog.Trigger>
28
+ <Dialog.Content class="sm:max-w-md">
29
+ <Dialog.Header>
30
+ <Dialog.Title>{label}</Dialog.Title>
31
+ <Dialog.Description>{description}</Dialog.Description>
32
+ </Dialog.Header>
33
+ </Dialog.Content>
34
+ </Dialog.Root>
@@ -0,0 +1,8 @@
1
+ interface Props {
2
+ /** The field's label: the dialog title and the button's accessible name. */
3
+ label: string;
4
+ description: string;
5
+ }
6
+ declare const HelpButton: import("svelte").Component<Props, {}, "">;
7
+ type HelpButton = ReturnType<typeof HelpButton>;
8
+ export default HelpButton;
@@ -97,10 +97,8 @@
97
97
  </div>
98
98
  {:else}
99
99
  <div
100
- class="w-full"
101
- style="height: {isFullscreen ? '100vh' : '380px'}; {backgroundColor
102
- ? `background-color: ${backgroundColor};`
103
- : ''}"
100
+ class="w-full bg-(--image-bg) {isFullscreen ? 'h-screen' : 'h-95'}"
101
+ style:--image-bg={backgroundColor}
104
102
  >
105
103
  <img
106
104
  src={dataUrl}
@@ -16,8 +16,7 @@
16
16
  isColorWidget
17
17
  } from '@selvajs/schemas';
18
18
  import * as Field from '../primitives/field';
19
- import * as Dialog from '../primitives/dialog';
20
- import { HelpCircle } from '@lucide/svelte';
19
+ import HelpButton from './HelpButton.svelte';
21
20
  import {
22
21
  CheckboxInput,
23
22
  ChecklistInput,
@@ -65,15 +64,15 @@
65
64
  });
66
65
  const clientSlot = getClientSlot();
67
66
 
68
- // Min/max hint rendered next to the label. `hideRange` lets the author suppress it.
67
+ // Sliders never show the hint: the track already conveys the bounds.
69
68
  const numberRangeHint = $derived.by(() => {
70
69
  if (!isNumberWidget(item)) return null;
71
70
  const cfg = item.config;
72
- if (cfg?.hideRange) return null;
71
+ if (cfg?.hideRange || cfg?.renderAsSlider) return null;
73
72
  const hasMin = typeof cfg?.minimum === 'number';
74
73
  const hasMax = typeof cfg?.maximum === 'number';
75
74
  if (!hasMin && !hasMax) return null;
76
- if (hasMin && hasMax) return `${cfg!.minimum} to ${cfg!.maximum}`;
75
+ if (hasMin && hasMax) return `${cfg!.minimum} – ${cfg!.maximum}`;
77
76
  if (hasMin) return `≥ ${cfg!.minimum}`;
78
77
  return `≤ ${cfg!.maximum}`;
79
78
  });
@@ -171,54 +170,52 @@
171
170
  }
172
171
  </script>
173
172
 
173
+ {#snippet labelText(forId?: string, tone: 'quiet' | 'strong' = 'quiet')}
174
+ <Field.Label for={forId} class="min-w-0 block break-words">
175
+ <span
176
+ class={tone === 'quiet' ? 'font-normal text-muted-foreground' : 'font-normal text-foreground'}
177
+ >{label}</span
178
+ >
179
+ </Field.Label>
180
+ {/snippet}
181
+
182
+ {#snippet helpButton()}
183
+ {#if item.description}
184
+ <HelpButton {label} description={item.description} />
185
+ {/if}
186
+ {/snippet}
187
+
188
+ {#snippet fieldHeader(forId?: string)}
189
+ <div class="gap-1.5 min-h-5 min-w-0 flex items-center">
190
+ {@render labelText(forId)}
191
+ {@render helpButton()}
192
+ {#if showRangeInLabel}
193
+ <span
194
+ class="text-xs pl-2 ml-auto hidden shrink-0 whitespace-nowrap text-muted-foreground tabular-nums group-focus-within/field:inline"
195
+ >
196
+ {numberRangeHint}
197
+ </span>
198
+ {/if}
199
+ </div>
200
+ {/snippet}
201
+
174
202
  {#if isClientSlot}
175
203
  {#if clientSlot}
176
- <Field.Field>
177
- <Field.Label class="gap-2 flex items-center">
178
- {label}
179
- {#if item.description}
180
- <Dialog.Root>
181
- <Dialog.Trigger class="p-1 cursor-help opacity-60 transition-opacity hover:opacity-100">
182
- <HelpCircle size={16} />
183
- </Dialog.Trigger>
184
- <Dialog.Content class="sm:max-w-md">
185
- <Dialog.Header>
186
- <Dialog.Title>{label}</Dialog.Title>
187
- <Dialog.Description>{item.description}</Dialog.Description>
188
- </Dialog.Header>
189
- </Dialog.Content>
190
- </Dialog.Root>
191
- {/if}
192
- </Field.Label>
204
+ <div role="group" class="group/field gap-1.5 min-w-0 flex flex-col">
205
+ {@render fieldHeader()}
193
206
  {@render clientSlot({
194
207
  inputId: item.paramId,
195
208
  displayName: label,
196
209
  value,
197
210
  onValueChange: commit
198
211
  })}
199
- </Field.Field>
212
+ </div>
200
213
  {/if}
201
214
  {:else if !hideDynamicListWhenEmpty}
202
- <Field.Field>
203
- <Field.Label for={inputId} class="gap-2 flex items-center">
204
- {label}
205
- {#if item.description}
206
- <Dialog.Root>
207
- <Dialog.Trigger class="p-1 cursor-help opacity-60 transition-opacity hover:opacity-100">
208
- <HelpCircle size={16} />
209
- </Dialog.Trigger>
210
- <Dialog.Content class="sm:max-w-md">
211
- <Dialog.Header>
212
- <Dialog.Title>{label}</Dialog.Title>
213
- <Dialog.Description>{item.description}</Dialog.Description>
214
- </Dialog.Header>
215
- </Dialog.Content>
216
- </Dialog.Root>
217
- {/if}
218
- {#if showRangeInLabel}
219
- <span class="text-xs font-normal text-muted-foreground">{numberRangeHint}</span>
220
- {/if}
221
- </Field.Label>
215
+ <div role="group" class="group/field gap-1.5 min-w-0 flex flex-col">
216
+ {#if !isCheckboxWidget(item)}
217
+ {@render fieldHeader(inputId)}
218
+ {/if}
222
219
 
223
220
  {#if isNumberWidget(item)}
224
221
  {@const config = item.config}
@@ -235,7 +232,10 @@
235
232
  value={typeof value === 'boolean' ? value : undefined}
236
233
  onChange={commit}
237
234
  {disabled}
238
- />
235
+ >
236
+ {@render labelText(inputId, 'strong')}
237
+ {@render helpButton()}
238
+ </CheckboxInput>
239
239
  {:else if isTextWidget(item)}
240
240
  {@const config = item.config}
241
241
  <TextInput
@@ -307,5 +307,5 @@
307
307
  onChange={(newValue) => commit(newValue)}
308
308
  />
309
309
  {/if}
310
- </Field.Field>
310
+ </div>
311
311
  {/if}
@@ -10,8 +10,8 @@
10
10
  isFileData
11
11
  } from '../../utils/file-download';
12
12
  import { Button } from '../primitives';
13
- import * as Dialog from '../primitives/dialog';
14
- import { Info, Folder, FolderOpen, FileIcon, ChevronRight } from '@lucide/svelte';
13
+ import { Folder, FolderOpen, FileIcon, ChevronRight } from '@lucide/svelte';
14
+ import HelpButton from './HelpButton.svelte';
15
15
  import { SvelteMap, SvelteSet } from 'svelte/reactivity';
16
16
  import { Label } from '../primitives/label';
17
17
 
@@ -154,17 +154,7 @@
154
154
  <div class="gap-2 flex items-center">
155
155
  <Label>{label}</Label>
156
156
  {#if item.description}
157
- <Dialog.Root>
158
- <Dialog.Trigger class="p-1 cursor-help opacity-60 transition-opacity hover:opacity-100">
159
- <Info size={16} />
160
- </Dialog.Trigger>
161
- <Dialog.Content class="sm:max-w-md">
162
- <Dialog.Header>
163
- <Dialog.Title>{label}</Dialog.Title>
164
- <Dialog.Description>{item.description}</Dialog.Description>
165
- </Dialog.Header>
166
- </Dialog.Content>
167
- </Dialog.Root>
157
+ <HelpButton {label} description={item.description} />
168
158
  {/if}
169
159
  </div>
170
160
  {/snippet}
@@ -287,7 +277,7 @@
287
277
 
288
278
  <!-- Dynamic value list outputs are routing sinks (their options feed an input), not displayed. -->
289
279
  {#if item.widgetType !== 'dynamicValueList'}
290
- <div class="gap-2 flex flex-col">
280
+ <div role="group" class="group/field gap-2 flex flex-col">
291
281
  {@render fieldHeader()}
292
282
 
293
283
  {#if item.widgetType === 'chart'}
@@ -311,24 +301,24 @@
311
301
  <div class="group relative">
312
302
  {#if isObjectValue}
313
303
  <pre
314
- class="{boxClass} overflow-wrap-anywhere max-h-96 overflow-auto bg-muted/10 text-foreground">{formattedValue}</pre>
304
+ class="{boxClass} max-h-96 overflow-auto bg-muted/10 wrap-anywhere text-foreground">{formattedValue}</pre>
315
305
  {:else}
316
306
  <div
317
- class="{boxClass} overflow-wrap-anywhere bg-muted/10 wrap-break-word whitespace-pre-wrap text-foreground"
307
+ class="{boxClass} bg-muted/10 wrap-anywhere wrap-break-word whitespace-pre-wrap text-foreground"
318
308
  >
319
309
  {#if hasValue}{value}{:else}{@render placeholder()}{/if}
320
310
  </div>
321
311
  {/if}
322
312
  {#if hasValue}
323
- <Button
324
- onclick={copyToClipboard}
313
+ <div
325
314
  class="right-2 top-2 absolute transition-opacity {copied
326
315
  ? 'opacity-100'
327
- : 'opacity-0 group-hover:opacity-100'}"
328
- size="sm"
316
+ : 'opacity-0 group-hover:opacity-100 focus-within:opacity-100'}"
329
317
  >
330
- {copied ? 'Copied!' : 'Copy'}
331
- </Button>
318
+ <Button onclick={copyToClipboard} size="sm">
319
+ {copied ? 'Copied!' : 'Copy'}
320
+ </Button>
321
+ </div>
332
322
  {/if}
333
323
  </div>
334
324
  {/if}
@@ -1,44 +1,73 @@
1
1
  <script lang="ts">
2
2
  import type { TabConfig } from '@selvajs/schemas';
3
3
  import * as Tabs from '../primitives/tabs';
4
- import { ScrollArea } from '../primitives/scroll-area';
4
+ import { ChevronLeft, ChevronRight } from '@lucide/svelte';
5
5
  import Icon from '@iconify/svelte';
6
+ import { getLocaleContext } from '../../i18n/localeContext.svelte';
7
+
8
+ const locale = getLocaleContext();
9
+ const t = $derived(locale.messages);
6
10
 
7
11
  interface Props {
8
12
  tabs: TabConfig[];
13
+ activeTabId: string;
9
14
  onTabChange: (tabId: string) => void;
10
15
  }
11
16
 
12
- let { tabs, onTabChange }: Props = $props();
17
+ let { tabs, activeTabId, onTabChange }: Props = $props();
18
+
19
+ const SCROLL_BUTTON_WIDTH = 32;
20
+
21
+ let listRef = $state<HTMLElement | null>(null);
22
+ let canScrollBack = $state(false);
23
+ let canScrollForward = $state(false);
24
+
25
+ function updateOverflow() {
26
+ if (!listRef) return;
27
+ const { scrollLeft, scrollWidth, clientWidth } = listRef;
28
+ canScrollBack = scrollLeft > 1;
29
+ canScrollForward = scrollLeft + clientWidth < scrollWidth - 1;
30
+ }
13
31
 
14
- let viewportRef = $state<HTMLElement | null>(null);
32
+ $effect(() => {
33
+ if (!listRef) return;
34
+ const observer = new ResizeObserver(updateOverflow);
35
+ observer.observe(listRef);
36
+ updateOverflow();
37
+ return () => observer.disconnect();
38
+ });
39
+
40
+ // A tab picked from the collapsed strip may sit outside the visible strip. Not
41
+ // scrollIntoView: that also scrolls every scrollable ancestor, e.g. the mobile drawer.
42
+ $effect(() => {
43
+ if (!listRef) return;
44
+ const active = listRef.querySelector<HTMLElement>(`[data-value="${CSS.escape(activeTabId)}"]`);
45
+ if (!active) return;
46
+ // Keep the tab clear of the scroll buttons, which overlay the strip's edges.
47
+ const start = active.offsetLeft - SCROLL_BUTTON_WIDTH;
48
+ const end = active.offsetLeft + active.offsetWidth + SCROLL_BUTTON_WIDTH;
49
+ if (start < listRef.scrollLeft) listRef.scrollLeft = start;
50
+ else if (end > listRef.scrollLeft + listRef.clientWidth)
51
+ listRef.scrollLeft = end - listRef.clientWidth;
52
+ });
53
+
54
+ function scrollByPage(direction: -1 | 1) {
55
+ listRef?.scrollBy({ left: direction * listRef.clientWidth * 0.7, behavior: 'smooth' });
56
+ }
15
57
 
16
58
  function handleWheel(e: WheelEvent) {
17
- if (!viewportRef) return;
59
+ if (!listRef || (!canScrollBack && !canScrollForward)) return;
18
60
  // Trackpad horizontal swipes already produce deltaX — let those pass through.
19
61
  if (Math.abs(e.deltaX) > Math.abs(e.deltaY)) return;
20
- const canScroll = viewportRef.scrollWidth > viewportRef.clientWidth;
21
- if (!canScroll) return;
22
62
  e.preventDefault();
23
- viewportRef.scrollLeft += e.deltaY;
63
+ listRef.scrollLeft += e.deltaY;
24
64
  }
25
65
  </script>
26
66
 
27
- <ScrollArea
28
- bind:viewportRef
29
- class="w-full shrink-0 border-b border-border"
30
- orientation="horizontal"
31
- onwheel={handleWheel}
32
- >
33
- <Tabs.List
34
- class="px-2 py-2 gap-0 inline-flex h-auto w-max justify-start rounded-none bg-transparent"
35
- >
67
+ <div class="tab-bar relative shrink-0 border-b border-border">
68
+ <Tabs.List bind:ref={listRef} variant="line" onscroll={updateOverflow} onwheel={handleWheel}>
36
69
  {#each tabs as tab (tab.id)}
37
- <Tabs.Trigger
38
- value={tab.id}
39
- onclick={() => onTabChange(tab.id)}
40
- class="group/tab gap-1.5 px-3 py-1 text-sm font-medium relative h-auto flex-none shrink-0 rounded-none border-0 transition-colors not-last:border-r not-last:border-border hover:bg-accent data-[state=active]:bg-transparent data-[state=active]:text-foreground data-[state=active]:shadow-none data-[state=inactive]:text-muted-foreground dark:data-[state=active]:border-transparent dark:data-[state=active]:bg-transparent"
41
- >
70
+ <Tabs.Trigger value={tab.id} onclick={() => onTabChange(tab.id)} variant="line">
42
71
  {#if tab.icon}
43
72
  {#if tab.icon.includes(':')}
44
73
  <Icon icon={tab.icon} class="h-4 w-4" />
@@ -50,4 +79,59 @@
50
79
  </Tabs.Trigger>
51
80
  {/each}
52
81
  </Tabs.List>
53
- </ScrollArea>
82
+
83
+ {#if canScrollBack}
84
+ <button
85
+ type="button"
86
+ class="scroll-button back"
87
+ aria-label={t.scrollTabsBack}
88
+ onclick={() => scrollByPage(-1)}
89
+ >
90
+ <ChevronLeft class="h-4 w-4" />
91
+ </button>
92
+ {/if}
93
+ {#if canScrollForward}
94
+ <button
95
+ type="button"
96
+ class="scroll-button forward"
97
+ aria-label={t.scrollTabsForward}
98
+ onclick={() => scrollByPage(1)}
99
+ >
100
+ <ChevronRight class="h-4 w-4" />
101
+ </button>
102
+ {/if}
103
+ </div>
104
+
105
+ <style>
106
+ .tab-bar :global([data-slot='tabs-list']) {
107
+ position: relative;
108
+ overflow-x: auto;
109
+ scrollbar-width: none;
110
+ }
111
+ .tab-bar :global([data-slot='tabs-list']::-webkit-scrollbar) {
112
+ display: none;
113
+ }
114
+
115
+ .scroll-button {
116
+ position: absolute;
117
+ top: 0;
118
+ bottom: 1px;
119
+ display: flex;
120
+ align-items: center;
121
+ color: var(--muted-foreground);
122
+ cursor: pointer;
123
+ }
124
+ .scroll-button:hover {
125
+ color: var(--foreground);
126
+ }
127
+ .scroll-button.back {
128
+ left: 0;
129
+ padding: 0 1.25rem 0 0.375rem;
130
+ background: linear-gradient(to right, var(--card) 55%, transparent);
131
+ }
132
+ .scroll-button.forward {
133
+ right: 0;
134
+ padding: 0 0.375rem 0 1.25rem;
135
+ background: linear-gradient(to left, var(--card) 55%, transparent);
136
+ }
137
+ </style>
@@ -1,6 +1,7 @@
1
1
  import type { TabConfig } from '@selvajs/schemas';
2
2
  interface Props {
3
3
  tabs: TabConfig[];
4
+ activeTabId: string;
4
5
  onTabChange: (tabId: string) => void;
5
6
  }
6
7
  declare const TabBar: import("svelte").Component<Props, {}, "">;