selva-shared 0.8.1

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 (506) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +45 -0
  3. package/dist/components/AppLayout.svelte +439 -0
  4. package/dist/components/AppLayout.svelte.d.ts +17 -0
  5. package/dist/components/CollapsedPanelStrip.svelte +67 -0
  6. package/dist/components/CollapsedPanelStrip.svelte.d.ts +11 -0
  7. package/dist/components/ComputeMessages.svelte +172 -0
  8. package/dist/components/ComputeMessages.svelte.d.ts +7 -0
  9. package/dist/components/ErrorScreen.svelte +55 -0
  10. package/dist/components/ErrorScreen.svelte.d.ts +9 -0
  11. package/dist/components/StateManager.svelte +318 -0
  12. package/dist/components/StateManager.svelte.d.ts +9 -0
  13. package/dist/components/Viewer.svelte +207 -0
  14. package/dist/components/Viewer.svelte.d.ts +12 -0
  15. package/dist/components/layout/FooterItemRenderer.svelte +20 -0
  16. package/dist/components/layout/FooterItemRenderer.svelte.d.ts +7 -0
  17. package/dist/components/layout/PageContainer.svelte +36 -0
  18. package/dist/components/layout/PageContainer.svelte.d.ts +12 -0
  19. package/dist/components/layout/PageFooter.svelte +223 -0
  20. package/dist/components/layout/PageFooter.svelte.d.ts +9 -0
  21. package/dist/components/layout/PageHeader.svelte +89 -0
  22. package/dist/components/layout/PageHeader.svelte.d.ts +12 -0
  23. package/dist/components/layout/index.d.ts +3 -0
  24. package/dist/components/layout/index.js +4 -0
  25. package/dist/components/preview/ChartOutput.svelte +257 -0
  26. package/dist/components/preview/ChartOutput.svelte.d.ts +8 -0
  27. package/dist/components/preview/Group.svelte +121 -0
  28. package/dist/components/preview/Group.svelte.d.ts +23 -0
  29. package/dist/components/preview/InputControl.svelte +119 -0
  30. package/dist/components/preview/InputControl.svelte.d.ts +11 -0
  31. package/dist/components/preview/OutputDisplay.svelte +296 -0
  32. package/dist/components/preview/OutputDisplay.svelte.d.ts +9 -0
  33. package/dist/components/preview/TabBar.svelte +36 -0
  34. package/dist/components/preview/TabBar.svelte.d.ts +8 -0
  35. package/dist/components/preview/TabContent.svelte +124 -0
  36. package/dist/components/preview/TabContent.svelte.d.ts +13 -0
  37. package/dist/components/preview/TabLayout.svelte +109 -0
  38. package/dist/components/preview/TabLayout.svelte.d.ts +13 -0
  39. package/dist/components/preview/index.d.ts +3 -0
  40. package/dist/components/preview/index.js +4 -0
  41. package/dist/components/preview/inputs/CheckboxInput.svelte +29 -0
  42. package/dist/components/preview/inputs/CheckboxInput.svelte.d.ts +10 -0
  43. package/dist/components/preview/inputs/ColorInput.svelte +21 -0
  44. package/dist/components/preview/inputs/ColorInput.svelte.d.ts +7 -0
  45. package/dist/components/preview/inputs/DropdownInput.svelte +40 -0
  46. package/dist/components/preview/inputs/DropdownInput.svelte.d.ts +10 -0
  47. package/dist/components/preview/inputs/FileInput.svelte +358 -0
  48. package/dist/components/preview/inputs/FileInput.svelte.d.ts +10 -0
  49. package/dist/components/preview/inputs/NumberInput.svelte +152 -0
  50. package/dist/components/preview/inputs/NumberInput.svelte.d.ts +11 -0
  51. package/dist/components/preview/inputs/TextInput.svelte +74 -0
  52. package/dist/components/preview/inputs/TextInput.svelte.d.ts +11 -0
  53. package/dist/components/preview/inputs/index.d.ts +6 -0
  54. package/dist/components/preview/inputs/index.js +6 -0
  55. package/dist/components/ui/CalculateButton.svelte +56 -0
  56. package/dist/components/ui/CalculateButton.svelte.d.ts +9 -0
  57. package/dist/components/ui/SolvingIndicator.svelte +55 -0
  58. package/dist/components/ui/SolvingIndicator.svelte.d.ts +6 -0
  59. package/dist/components/ui/StateDisplay.svelte +106 -0
  60. package/dist/components/ui/StateDisplay.svelte.d.ts +10 -0
  61. package/dist/components/ui/alert/alert-description.svelte +23 -0
  62. package/dist/components/ui/alert/alert-description.svelte.d.ts +5 -0
  63. package/dist/components/ui/alert/alert-title.svelte +20 -0
  64. package/dist/components/ui/alert/alert-title.svelte.d.ts +5 -0
  65. package/dist/components/ui/alert/alert.svelte +44 -0
  66. package/dist/components/ui/alert/alert.svelte.d.ts +26 -0
  67. package/dist/components/ui/alert/index.d.ts +5 -0
  68. package/dist/components/ui/alert/index.js +7 -0
  69. package/dist/components/ui/alert-dialog/alert-dialog-action.svelte +18 -0
  70. package/dist/components/ui/alert-dialog/alert-dialog-action.svelte.d.ts +4 -0
  71. package/dist/components/ui/alert-dialog/alert-dialog-cancel.svelte +18 -0
  72. package/dist/components/ui/alert-dialog/alert-dialog-cancel.svelte.d.ts +4 -0
  73. package/dist/components/ui/alert-dialog/alert-dialog-content.svelte +27 -0
  74. package/dist/components/ui/alert-dialog/alert-dialog-content.svelte.d.ts +8 -0
  75. package/dist/components/ui/alert-dialog/alert-dialog-description.svelte +17 -0
  76. package/dist/components/ui/alert-dialog/alert-dialog-description.svelte.d.ts +4 -0
  77. package/dist/components/ui/alert-dialog/alert-dialog-footer.svelte +20 -0
  78. package/dist/components/ui/alert-dialog/alert-dialog-footer.svelte.d.ts +5 -0
  79. package/dist/components/ui/alert-dialog/alert-dialog-header.svelte +20 -0
  80. package/dist/components/ui/alert-dialog/alert-dialog-header.svelte.d.ts +5 -0
  81. package/dist/components/ui/alert-dialog/alert-dialog-overlay.svelte +20 -0
  82. package/dist/components/ui/alert-dialog/alert-dialog-overlay.svelte.d.ts +4 -0
  83. package/dist/components/ui/alert-dialog/alert-dialog-title.svelte +17 -0
  84. package/dist/components/ui/alert-dialog/alert-dialog-title.svelte.d.ts +4 -0
  85. package/dist/components/ui/alert-dialog/alert-dialog-trigger.svelte +7 -0
  86. package/dist/components/ui/alert-dialog/alert-dialog-trigger.svelte.d.ts +4 -0
  87. package/dist/components/ui/alert-dialog/index.d.ts +12 -0
  88. package/dist/components/ui/alert-dialog/index.js +15 -0
  89. package/dist/components/ui/badge/badge.svelte +50 -0
  90. package/dist/components/ui/badge/badge.svelte.d.ts +32 -0
  91. package/dist/components/ui/badge/index.d.ts +2 -0
  92. package/dist/components/ui/badge/index.js +2 -0
  93. package/dist/components/ui/button/button.svelte +83 -0
  94. package/dist/components/ui/button/button.svelte.d.ts +67 -0
  95. package/dist/components/ui/button/index.d.ts +2 -0
  96. package/dist/components/ui/button/index.js +4 -0
  97. package/dist/components/ui/button-group/button-group-separator.svelte +20 -0
  98. package/dist/components/ui/button-group/button-group-separator.svelte.d.ts +13 -0
  99. package/dist/components/ui/button-group/button-group-text.svelte +30 -0
  100. package/dist/components/ui/button-group/button-group-text.svelte.d.ts +11 -0
  101. package/dist/components/ui/button-group/button-group.svelte +46 -0
  102. package/dist/components/ui/button-group/button-group.svelte.d.ts +26 -0
  103. package/dist/components/ui/button-group/index.d.ts +4 -0
  104. package/dist/components/ui/button-group/index.js +6 -0
  105. package/dist/components/ui/card/card-action.svelte +20 -0
  106. package/dist/components/ui/card/card-action.svelte.d.ts +5 -0
  107. package/dist/components/ui/card/card-content.svelte +15 -0
  108. package/dist/components/ui/card/card-content.svelte.d.ts +5 -0
  109. package/dist/components/ui/card/card-description.svelte +20 -0
  110. package/dist/components/ui/card/card-description.svelte.d.ts +5 -0
  111. package/dist/components/ui/card/card-footer.svelte +20 -0
  112. package/dist/components/ui/card/card-footer.svelte.d.ts +5 -0
  113. package/dist/components/ui/card/card-header.svelte +23 -0
  114. package/dist/components/ui/card/card-header.svelte.d.ts +5 -0
  115. package/dist/components/ui/card/card-title.svelte +20 -0
  116. package/dist/components/ui/card/card-title.svelte.d.ts +5 -0
  117. package/dist/components/ui/card/card.svelte +23 -0
  118. package/dist/components/ui/card/card.svelte.d.ts +5 -0
  119. package/dist/components/ui/card/index.d.ts +8 -0
  120. package/dist/components/ui/card/index.js +10 -0
  121. package/dist/components/ui/checkbox/checkbox.svelte +36 -0
  122. package/dist/components/ui/checkbox/checkbox.svelte.d.ts +4 -0
  123. package/dist/components/ui/checkbox/index.d.ts +2 -0
  124. package/dist/components/ui/checkbox/index.js +4 -0
  125. package/dist/components/ui/collapsible/collapsible-content.svelte +7 -0
  126. package/dist/components/ui/collapsible/collapsible-content.svelte.d.ts +4 -0
  127. package/dist/components/ui/collapsible/collapsible-trigger.svelte +7 -0
  128. package/dist/components/ui/collapsible/collapsible-trigger.svelte.d.ts +4 -0
  129. package/dist/components/ui/collapsible/collapsible.svelte +11 -0
  130. package/dist/components/ui/collapsible/collapsible.svelte.d.ts +4 -0
  131. package/dist/components/ui/collapsible/index.d.ts +4 -0
  132. package/dist/components/ui/collapsible/index.js +6 -0
  133. package/dist/components/ui/context-menu/context-menu-checkbox-item.svelte +38 -0
  134. package/dist/components/ui/context-menu/context-menu-checkbox-item.svelte.d.ts +9 -0
  135. package/dist/components/ui/context-menu/context-menu-content.svelte +25 -0
  136. package/dist/components/ui/context-menu/context-menu-content.svelte.d.ts +7 -0
  137. package/dist/components/ui/context-menu/context-menu-group-heading.svelte +21 -0
  138. package/dist/components/ui/context-menu/context-menu-group-heading.svelte.d.ts +7 -0
  139. package/dist/components/ui/context-menu/context-menu-group.svelte +7 -0
  140. package/dist/components/ui/context-menu/context-menu-group.svelte.d.ts +4 -0
  141. package/dist/components/ui/context-menu/context-menu-item.svelte +27 -0
  142. package/dist/components/ui/context-menu/context-menu-item.svelte.d.ts +8 -0
  143. package/dist/components/ui/context-menu/context-menu-label.svelte +24 -0
  144. package/dist/components/ui/context-menu/context-menu-label.svelte.d.ts +8 -0
  145. package/dist/components/ui/context-menu/context-menu-radio-group.svelte +16 -0
  146. package/dist/components/ui/context-menu/context-menu-radio-group.svelte.d.ts +4 -0
  147. package/dist/components/ui/context-menu/context-menu-radio-item.svelte +31 -0
  148. package/dist/components/ui/context-menu/context-menu-radio-item.svelte.d.ts +4 -0
  149. package/dist/components/ui/context-menu/context-menu-separator.svelte +17 -0
  150. package/dist/components/ui/context-menu/context-menu-separator.svelte.d.ts +4 -0
  151. package/dist/components/ui/context-menu/context-menu-shortcut.svelte +20 -0
  152. package/dist/components/ui/context-menu/context-menu-shortcut.svelte.d.ts +5 -0
  153. package/dist/components/ui/context-menu/context-menu-sub-content.svelte +20 -0
  154. package/dist/components/ui/context-menu/context-menu-sub-content.svelte.d.ts +4 -0
  155. package/dist/components/ui/context-menu/context-menu-sub-trigger.svelte +29 -0
  156. package/dist/components/ui/context-menu/context-menu-sub-trigger.svelte.d.ts +8 -0
  157. package/dist/components/ui/context-menu/context-menu-trigger.svelte +7 -0
  158. package/dist/components/ui/context-menu/context-menu-trigger.svelte.d.ts +4 -0
  159. package/dist/components/ui/context-menu/index.d.ts +16 -0
  160. package/dist/components/ui/context-menu/index.js +19 -0
  161. package/dist/components/ui/dialog/dialog-close.svelte +7 -0
  162. package/dist/components/ui/dialog/dialog-close.svelte.d.ts +4 -0
  163. package/dist/components/ui/dialog/dialog-content.svelte +43 -0
  164. package/dist/components/ui/dialog/dialog-content.svelte.d.ts +11 -0
  165. package/dist/components/ui/dialog/dialog-description.svelte +17 -0
  166. package/dist/components/ui/dialog/dialog-description.svelte.d.ts +4 -0
  167. package/dist/components/ui/dialog/dialog-footer.svelte +20 -0
  168. package/dist/components/ui/dialog/dialog-footer.svelte.d.ts +5 -0
  169. package/dist/components/ui/dialog/dialog-header.svelte +20 -0
  170. package/dist/components/ui/dialog/dialog-header.svelte.d.ts +5 -0
  171. package/dist/components/ui/dialog/dialog-overlay.svelte +20 -0
  172. package/dist/components/ui/dialog/dialog-overlay.svelte.d.ts +4 -0
  173. package/dist/components/ui/dialog/dialog-title.svelte +17 -0
  174. package/dist/components/ui/dialog/dialog-title.svelte.d.ts +4 -0
  175. package/dist/components/ui/dialog/dialog-trigger.svelte +7 -0
  176. package/dist/components/ui/dialog/dialog-trigger.svelte.d.ts +4 -0
  177. package/dist/components/ui/dialog/index.d.ts +11 -0
  178. package/dist/components/ui/dialog/index.js +14 -0
  179. package/dist/components/ui/field/field-content.svelte +20 -0
  180. package/dist/components/ui/field/field-content.svelte.d.ts +5 -0
  181. package/dist/components/ui/field/field-description.svelte +25 -0
  182. package/dist/components/ui/field/field-description.svelte.d.ts +5 -0
  183. package/dist/components/ui/field/field-error.svelte +58 -0
  184. package/dist/components/ui/field/field-error.svelte.d.ts +12 -0
  185. package/dist/components/ui/field/field-group.svelte +23 -0
  186. package/dist/components/ui/field/field-group.svelte.d.ts +5 -0
  187. package/dist/components/ui/field/field-label.svelte +26 -0
  188. package/dist/components/ui/field/field-label.svelte.d.ts +10 -0
  189. package/dist/components/ui/field/field-legend.svelte +29 -0
  190. package/dist/components/ui/field/field-legend.svelte.d.ts +8 -0
  191. package/dist/components/ui/field/field-separator.svelte +38 -0
  192. package/dist/components/ui/field/field-separator.svelte.d.ts +9 -0
  193. package/dist/components/ui/field/field-set.svelte +24 -0
  194. package/dist/components/ui/field/field-set.svelte.d.ts +5 -0
  195. package/dist/components/ui/field/field-title.svelte +23 -0
  196. package/dist/components/ui/field/field-title.svelte.d.ts +5 -0
  197. package/dist/components/ui/field/field.svelte +53 -0
  198. package/dist/components/ui/field/field.svelte.d.ts +29 -0
  199. package/dist/components/ui/field/index.d.ts +11 -0
  200. package/dist/components/ui/field/index.js +13 -0
  201. package/dist/components/ui/index.d.ts +21 -0
  202. package/dist/components/ui/index.js +24 -0
  203. package/dist/components/ui/input/index.d.ts +2 -0
  204. package/dist/components/ui/input/index.js +4 -0
  205. package/dist/components/ui/input/input.svelte +52 -0
  206. package/dist/components/ui/input/input.svelte.d.ts +13 -0
  207. package/dist/components/ui/label/index.d.ts +2 -0
  208. package/dist/components/ui/label/index.js +4 -0
  209. package/dist/components/ui/label/label.svelte +20 -0
  210. package/dist/components/ui/label/label.svelte.d.ts +4 -0
  211. package/dist/components/ui/mode-toggle/index.d.ts +1 -0
  212. package/dist/components/ui/mode-toggle/index.js +1 -0
  213. package/dist/components/ui/mode-toggle/mode-toggle.svelte +16 -0
  214. package/dist/components/ui/mode-toggle/mode-toggle.svelte.d.ts +18 -0
  215. package/dist/components/ui/resizable/index.d.ts +4 -0
  216. package/dist/components/ui/resizable/index.js +6 -0
  217. package/dist/components/ui/resizable/resizable-handle.svelte +30 -0
  218. package/dist/components/ui/resizable/resizable-handle.svelte.d.ts +8 -0
  219. package/dist/components/ui/resizable/resizable-pane-group.svelte +20 -0
  220. package/dist/components/ui/resizable/resizable-pane-group.svelte.d.ts +7 -0
  221. package/dist/components/ui/scroll-area/index.d.ts +3 -0
  222. package/dist/components/ui/scroll-area/index.js +5 -0
  223. package/dist/components/ui/scroll-area/scroll-area-scrollbar.svelte +31 -0
  224. package/dist/components/ui/scroll-area/scroll-area-scrollbar.svelte.d.ts +4 -0
  225. package/dist/components/ui/scroll-area/scroll-area.svelte +43 -0
  226. package/dist/components/ui/scroll-area/scroll-area.svelte.d.ts +11 -0
  227. package/dist/components/ui/select/index.d.ts +11 -0
  228. package/dist/components/ui/select/index.js +14 -0
  229. package/dist/components/ui/select/select-content.svelte +40 -0
  230. package/dist/components/ui/select/select-content.svelte.d.ts +8 -0
  231. package/dist/components/ui/select/select-group-heading.svelte +21 -0
  232. package/dist/components/ui/select/select-group-heading.svelte.d.ts +10 -0
  233. package/dist/components/ui/select/select-group.svelte +7 -0
  234. package/dist/components/ui/select/select-group.svelte.d.ts +4 -0
  235. package/dist/components/ui/select/select-item.svelte +38 -0
  236. package/dist/components/ui/select/select-item.svelte.d.ts +4 -0
  237. package/dist/components/ui/select/select-label.svelte +20 -0
  238. package/dist/components/ui/select/select-label.svelte.d.ts +6 -0
  239. package/dist/components/ui/select/select-scroll-down-button.svelte +20 -0
  240. package/dist/components/ui/select/select-scroll-down-button.svelte.d.ts +4 -0
  241. package/dist/components/ui/select/select-scroll-up-button.svelte +20 -0
  242. package/dist/components/ui/select/select-scroll-up-button.svelte.d.ts +4 -0
  243. package/dist/components/ui/select/select-separator.svelte +18 -0
  244. package/dist/components/ui/select/select-separator.svelte.d.ts +4 -0
  245. package/dist/components/ui/select/select-trigger.svelte +29 -0
  246. package/dist/components/ui/select/select-trigger.svelte.d.ts +8 -0
  247. package/dist/components/ui/separator/index.d.ts +2 -0
  248. package/dist/components/ui/separator/index.js +4 -0
  249. package/dist/components/ui/separator/separator.svelte +21 -0
  250. package/dist/components/ui/separator/separator.svelte.d.ts +4 -0
  251. package/dist/components/ui/slider/index.d.ts +2 -0
  252. package/dist/components/ui/slider/index.js +4 -0
  253. package/dist/components/ui/slider/slider.svelte +52 -0
  254. package/dist/components/ui/slider/slider.svelte.d.ts +5 -0
  255. package/dist/components/ui/sonner/index.d.ts +2 -0
  256. package/dist/components/ui/sonner/index.js +2 -0
  257. package/dist/components/ui/sonner/sonner.svelte +13 -0
  258. package/dist/components/ui/sonner/sonner.svelte.d.ts +4 -0
  259. package/dist/components/ui/switch/index.d.ts +2 -0
  260. package/dist/components/ui/switch/index.js +4 -0
  261. package/dist/components/ui/switch/switch.svelte +29 -0
  262. package/dist/components/ui/switch/switch.svelte.d.ts +4 -0
  263. package/dist/components/ui/tabs/index.d.ts +5 -0
  264. package/dist/components/ui/tabs/index.js +7 -0
  265. package/dist/components/ui/tabs/tabs-content.svelte +17 -0
  266. package/dist/components/ui/tabs/tabs-content.svelte.d.ts +4 -0
  267. package/dist/components/ui/tabs/tabs-list.svelte +16 -0
  268. package/dist/components/ui/tabs/tabs-list.svelte.d.ts +4 -0
  269. package/dist/components/ui/tabs/tabs-trigger.svelte +20 -0
  270. package/dist/components/ui/tabs/tabs-trigger.svelte.d.ts +4 -0
  271. package/dist/components/ui/tabs/tabs.svelte +19 -0
  272. package/dist/components/ui/tabs/tabs.svelte.d.ts +4 -0
  273. package/dist/components/ui/textarea/index.d.ts +2 -0
  274. package/dist/components/ui/textarea/index.js +4 -0
  275. package/dist/components/ui/textarea/textarea.svelte +23 -0
  276. package/dist/components/ui/textarea/textarea.svelte.d.ts +5 -0
  277. package/dist/components/ui/theme-switcher/ThemeSwitcher.svelte +39 -0
  278. package/dist/components/ui/theme-switcher/ThemeSwitcher.svelte.d.ts +3 -0
  279. package/dist/components/ui/theme-switcher/index.d.ts +1 -0
  280. package/dist/components/ui/theme-switcher/index.js +1 -0
  281. package/dist/composables/useFooterItem.svelte.d.ts +15 -0
  282. package/dist/composables/useFooterItem.svelte.js +31 -0
  283. package/dist/constants.d.ts +6 -0
  284. package/dist/constants.js +6 -0
  285. package/dist/contexts/FOOTER_USAGE.md +164 -0
  286. package/dist/contexts/footerContext.svelte.d.ts +17 -0
  287. package/dist/contexts/footerContext.svelte.js +24 -0
  288. package/dist/dummy-output-values.d.ts +3 -0
  289. package/dist/dummy-output-values.js +53 -0
  290. package/dist/dummy-surface-chart.json +13 -0
  291. package/dist/example-schema-left-only.json +367 -0
  292. package/dist/example-schema-right-only.json +322 -0
  293. package/dist/example-schema.json +1582 -0
  294. package/dist/features/preview/handlers.d.ts +55 -0
  295. package/dist/features/preview/handlers.js +175 -0
  296. package/dist/features/preview/index.d.ts +2 -0
  297. package/dist/features/preview/index.js +2 -0
  298. package/dist/features/preview/notifications.d.ts +11 -0
  299. package/dist/features/preview/notifications.js +41 -0
  300. package/dist/index.d.ts +29 -0
  301. package/dist/index.js +39 -0
  302. package/dist/stores/themeStore.svelte.d.ts +12 -0
  303. package/dist/stores/themeStore.svelte.js +42 -0
  304. package/dist/styles/base.css +142 -0
  305. package/dist/styles/themes/cyberpunk.css +98 -0
  306. package/dist/styles/themes/neutral.css +72 -0
  307. package/dist/styles/themes/ocean.css +75 -0
  308. package/dist/styles/themes/selva.css +105 -0
  309. package/dist/themes.d.ts +5 -0
  310. package/dist/themes.js +13 -0
  311. package/dist/types/generated/index.d.ts +6 -0
  312. package/dist/types/generated/index.js +6 -0
  313. package/dist/types/generated/preset.d.ts +80 -0
  314. package/dist/types/generated/preset.js +7 -0
  315. package/dist/types/generated/schema.d.ts +451 -0
  316. package/dist/types/generated/schema.js +48 -0
  317. package/dist/utils/computeThrottle.svelte.d.ts +28 -0
  318. package/dist/utils/computeThrottle.svelte.js +93 -0
  319. package/dist/utils/debounce.d.ts +14 -0
  320. package/dist/utils/debounce.js +25 -0
  321. package/dist/utils/file-download.d.ts +26 -0
  322. package/dist/utils/file-download.js +76 -0
  323. package/dist/utils/loadScript.d.ts +14 -0
  324. package/dist/utils/loadScript.js +41 -0
  325. package/dist/utils/param-exporter.d.ts +30 -0
  326. package/dist/utils/param-exporter.js +186 -0
  327. package/dist/utils/solving.svelte.d.ts +12 -0
  328. package/dist/utils/solving.svelte.js +86 -0
  329. package/dist/utils/utils-shared.d.ts +9 -0
  330. package/dist/utils/utils-shared.js +53 -0
  331. package/dist/utils/visibility-rules.d.ts +12 -0
  332. package/dist/utils/visibility-rules.js +52 -0
  333. package/dist/utils.d.ts +12 -0
  334. package/dist/utils.js +5 -0
  335. package/package.json +70 -0
  336. package/src/lib/components/AppLayout.svelte +439 -0
  337. package/src/lib/components/CollapsedPanelStrip.svelte +67 -0
  338. package/src/lib/components/ComputeMessages.svelte +172 -0
  339. package/src/lib/components/ErrorScreen.svelte +55 -0
  340. package/src/lib/components/StateManager.svelte +318 -0
  341. package/src/lib/components/Viewer.svelte +207 -0
  342. package/src/lib/components/layout/FooterItemRenderer.svelte +20 -0
  343. package/src/lib/components/layout/PageContainer.svelte +36 -0
  344. package/src/lib/components/layout/PageFooter.svelte +223 -0
  345. package/src/lib/components/layout/PageHeader.svelte +89 -0
  346. package/src/lib/components/layout/index.ts +4 -0
  347. package/src/lib/components/preview/ChartOutput.svelte +257 -0
  348. package/src/lib/components/preview/Group.svelte +121 -0
  349. package/src/lib/components/preview/InputControl.svelte +119 -0
  350. package/src/lib/components/preview/OutputDisplay.svelte +296 -0
  351. package/src/lib/components/preview/TabBar.svelte +36 -0
  352. package/src/lib/components/preview/TabContent.svelte +124 -0
  353. package/src/lib/components/preview/TabLayout.svelte +109 -0
  354. package/src/lib/components/preview/index.ts +4 -0
  355. package/src/lib/components/preview/inputs/CheckboxInput.svelte +29 -0
  356. package/src/lib/components/preview/inputs/ColorInput.svelte +21 -0
  357. package/src/lib/components/preview/inputs/DropdownInput.svelte +40 -0
  358. package/src/lib/components/preview/inputs/FileInput.svelte +358 -0
  359. package/src/lib/components/preview/inputs/NumberInput.svelte +152 -0
  360. package/src/lib/components/preview/inputs/TextInput.svelte +74 -0
  361. package/src/lib/components/preview/inputs/index.ts +6 -0
  362. package/src/lib/components/ui/CalculateButton.svelte +56 -0
  363. package/src/lib/components/ui/SolvingIndicator.svelte +55 -0
  364. package/src/lib/components/ui/StateDisplay.svelte +106 -0
  365. package/src/lib/components/ui/alert/alert-description.svelte +23 -0
  366. package/src/lib/components/ui/alert/alert-title.svelte +20 -0
  367. package/src/lib/components/ui/alert/alert.svelte +44 -0
  368. package/src/lib/components/ui/alert/index.ts +14 -0
  369. package/src/lib/components/ui/alert-dialog/alert-dialog-action.svelte +18 -0
  370. package/src/lib/components/ui/alert-dialog/alert-dialog-cancel.svelte +18 -0
  371. package/src/lib/components/ui/alert-dialog/alert-dialog-content.svelte +27 -0
  372. package/src/lib/components/ui/alert-dialog/alert-dialog-description.svelte +17 -0
  373. package/src/lib/components/ui/alert-dialog/alert-dialog-footer.svelte +20 -0
  374. package/src/lib/components/ui/alert-dialog/alert-dialog-header.svelte +20 -0
  375. package/src/lib/components/ui/alert-dialog/alert-dialog-overlay.svelte +20 -0
  376. package/src/lib/components/ui/alert-dialog/alert-dialog-title.svelte +17 -0
  377. package/src/lib/components/ui/alert-dialog/alert-dialog-trigger.svelte +7 -0
  378. package/src/lib/components/ui/alert-dialog/index.ts +39 -0
  379. package/src/lib/components/ui/badge/badge.svelte +50 -0
  380. package/src/lib/components/ui/badge/index.ts +2 -0
  381. package/src/lib/components/ui/button/button.svelte +83 -0
  382. package/src/lib/components/ui/button/index.ts +17 -0
  383. package/src/lib/components/ui/button-group/button-group-separator.svelte +20 -0
  384. package/src/lib/components/ui/button-group/button-group-text.svelte +30 -0
  385. package/src/lib/components/ui/button-group/button-group.svelte +46 -0
  386. package/src/lib/components/ui/button-group/index.ts +13 -0
  387. package/src/lib/components/ui/card/card-action.svelte +20 -0
  388. package/src/lib/components/ui/card/card-content.svelte +15 -0
  389. package/src/lib/components/ui/card/card-description.svelte +20 -0
  390. package/src/lib/components/ui/card/card-footer.svelte +20 -0
  391. package/src/lib/components/ui/card/card-header.svelte +23 -0
  392. package/src/lib/components/ui/card/card-title.svelte +20 -0
  393. package/src/lib/components/ui/card/card.svelte +23 -0
  394. package/src/lib/components/ui/card/index.ts +25 -0
  395. package/src/lib/components/ui/checkbox/checkbox.svelte +36 -0
  396. package/src/lib/components/ui/checkbox/index.ts +6 -0
  397. package/src/lib/components/ui/collapsible/collapsible-content.svelte +7 -0
  398. package/src/lib/components/ui/collapsible/collapsible-trigger.svelte +7 -0
  399. package/src/lib/components/ui/collapsible/collapsible.svelte +11 -0
  400. package/src/lib/components/ui/collapsible/index.ts +13 -0
  401. package/src/lib/components/ui/context-menu/context-menu-checkbox-item.svelte +38 -0
  402. package/src/lib/components/ui/context-menu/context-menu-content.svelte +25 -0
  403. package/src/lib/components/ui/context-menu/context-menu-group-heading.svelte +21 -0
  404. package/src/lib/components/ui/context-menu/context-menu-group.svelte +7 -0
  405. package/src/lib/components/ui/context-menu/context-menu-item.svelte +27 -0
  406. package/src/lib/components/ui/context-menu/context-menu-label.svelte +24 -0
  407. package/src/lib/components/ui/context-menu/context-menu-radio-group.svelte +16 -0
  408. package/src/lib/components/ui/context-menu/context-menu-radio-item.svelte +31 -0
  409. package/src/lib/components/ui/context-menu/context-menu-separator.svelte +17 -0
  410. package/src/lib/components/ui/context-menu/context-menu-shortcut.svelte +20 -0
  411. package/src/lib/components/ui/context-menu/context-menu-sub-content.svelte +20 -0
  412. package/src/lib/components/ui/context-menu/context-menu-sub-trigger.svelte +29 -0
  413. package/src/lib/components/ui/context-menu/context-menu-trigger.svelte +7 -0
  414. package/src/lib/components/ui/context-menu/index.ts +51 -0
  415. package/src/lib/components/ui/dialog/dialog-close.svelte +7 -0
  416. package/src/lib/components/ui/dialog/dialog-content.svelte +43 -0
  417. package/src/lib/components/ui/dialog/dialog-description.svelte +17 -0
  418. package/src/lib/components/ui/dialog/dialog-footer.svelte +20 -0
  419. package/src/lib/components/ui/dialog/dialog-header.svelte +20 -0
  420. package/src/lib/components/ui/dialog/dialog-overlay.svelte +20 -0
  421. package/src/lib/components/ui/dialog/dialog-title.svelte +17 -0
  422. package/src/lib/components/ui/dialog/dialog-trigger.svelte +7 -0
  423. package/src/lib/components/ui/dialog/index.ts +37 -0
  424. package/src/lib/components/ui/field/field-content.svelte +20 -0
  425. package/src/lib/components/ui/field/field-description.svelte +25 -0
  426. package/src/lib/components/ui/field/field-error.svelte +58 -0
  427. package/src/lib/components/ui/field/field-group.svelte +23 -0
  428. package/src/lib/components/ui/field/field-label.svelte +26 -0
  429. package/src/lib/components/ui/field/field-legend.svelte +29 -0
  430. package/src/lib/components/ui/field/field-separator.svelte +38 -0
  431. package/src/lib/components/ui/field/field-set.svelte +24 -0
  432. package/src/lib/components/ui/field/field-title.svelte +23 -0
  433. package/src/lib/components/ui/field/field.svelte +53 -0
  434. package/src/lib/components/ui/field/index.ts +33 -0
  435. package/src/lib/components/ui/index.ts +33 -0
  436. package/src/lib/components/ui/input/index.ts +7 -0
  437. package/src/lib/components/ui/input/input.svelte +52 -0
  438. package/src/lib/components/ui/label/index.ts +7 -0
  439. package/src/lib/components/ui/label/label.svelte +20 -0
  440. package/src/lib/components/ui/mode-toggle/index.ts +1 -0
  441. package/src/lib/components/ui/mode-toggle/mode-toggle.svelte +16 -0
  442. package/src/lib/components/ui/resizable/index.ts +13 -0
  443. package/src/lib/components/ui/resizable/resizable-handle.svelte +30 -0
  444. package/src/lib/components/ui/resizable/resizable-pane-group.svelte +20 -0
  445. package/src/lib/components/ui/scroll-area/index.ts +10 -0
  446. package/src/lib/components/ui/scroll-area/scroll-area-scrollbar.svelte +31 -0
  447. package/src/lib/components/ui/scroll-area/scroll-area.svelte +43 -0
  448. package/src/lib/components/ui/select/index.ts +37 -0
  449. package/src/lib/components/ui/select/select-content.svelte +40 -0
  450. package/src/lib/components/ui/select/select-group-heading.svelte +21 -0
  451. package/src/lib/components/ui/select/select-group.svelte +7 -0
  452. package/src/lib/components/ui/select/select-item.svelte +38 -0
  453. package/src/lib/components/ui/select/select-label.svelte +20 -0
  454. package/src/lib/components/ui/select/select-scroll-down-button.svelte +20 -0
  455. package/src/lib/components/ui/select/select-scroll-up-button.svelte +20 -0
  456. package/src/lib/components/ui/select/select-separator.svelte +18 -0
  457. package/src/lib/components/ui/select/select-trigger.svelte +29 -0
  458. package/src/lib/components/ui/separator/index.ts +7 -0
  459. package/src/lib/components/ui/separator/separator.svelte +21 -0
  460. package/src/lib/components/ui/slider/index.ts +7 -0
  461. package/src/lib/components/ui/slider/slider.svelte +52 -0
  462. package/src/lib/components/ui/sonner/index.ts +2 -0
  463. package/src/lib/components/ui/sonner/sonner.svelte +13 -0
  464. package/src/lib/components/ui/switch/index.ts +7 -0
  465. package/src/lib/components/ui/switch/switch.svelte +29 -0
  466. package/src/lib/components/ui/tabs/index.ts +16 -0
  467. package/src/lib/components/ui/tabs/tabs-content.svelte +17 -0
  468. package/src/lib/components/ui/tabs/tabs-list.svelte +16 -0
  469. package/src/lib/components/ui/tabs/tabs-trigger.svelte +20 -0
  470. package/src/lib/components/ui/tabs/tabs.svelte +19 -0
  471. package/src/lib/components/ui/textarea/index.ts +7 -0
  472. package/src/lib/components/ui/textarea/textarea.svelte +23 -0
  473. package/src/lib/components/ui/theme-switcher/ThemeSwitcher.svelte +39 -0
  474. package/src/lib/components/ui/theme-switcher/index.ts +1 -0
  475. package/src/lib/composables/useFooterItem.svelte.ts +39 -0
  476. package/src/lib/constants.ts +6 -0
  477. package/src/lib/contexts/FOOTER_USAGE.md +164 -0
  478. package/src/lib/contexts/footerContext.svelte.ts +52 -0
  479. package/src/lib/dummy-output-values.ts +62 -0
  480. package/src/lib/dummy-surface-chart.json +13 -0
  481. package/src/lib/example-schema-left-only.json +367 -0
  482. package/src/lib/example-schema-right-only.json +322 -0
  483. package/src/lib/example-schema.json +1582 -0
  484. package/src/lib/features/preview/handlers.ts +243 -0
  485. package/src/lib/features/preview/index.ts +2 -0
  486. package/src/lib/features/preview/notifications.ts +52 -0
  487. package/src/lib/index.ts +52 -0
  488. package/src/lib/stores/themeStore.svelte.ts +54 -0
  489. package/src/lib/styles/base.css +142 -0
  490. package/src/lib/styles/themes/cyberpunk.css +98 -0
  491. package/src/lib/styles/themes/neutral.css +72 -0
  492. package/src/lib/styles/themes/ocean.css +75 -0
  493. package/src/lib/styles/themes/selva.css +105 -0
  494. package/src/lib/themes.ts +18 -0
  495. package/src/lib/types/generated/index.ts +6 -0
  496. package/src/lib/types/generated/preset.ts +82 -0
  497. package/src/lib/types/generated/schema.ts +527 -0
  498. package/src/lib/utils/computeThrottle.svelte.ts +117 -0
  499. package/src/lib/utils/debounce.ts +30 -0
  500. package/src/lib/utils/file-download.ts +88 -0
  501. package/src/lib/utils/loadScript.ts +52 -0
  502. package/src/lib/utils/param-exporter.ts +242 -0
  503. package/src/lib/utils/solving.svelte.ts +100 -0
  504. package/src/lib/utils/utils-shared.ts +57 -0
  505. package/src/lib/utils/visibility-rules.ts +97 -0
  506. package/src/lib/utils.ts +13 -0
@@ -0,0 +1,7 @@
1
+ interface Props {
2
+ value?: string;
3
+ onChange: (value: string) => void;
4
+ }
5
+ declare const ColorInput: import("svelte").Component<Props, {}, "">;
6
+ type ColorInput = ReturnType<typeof ColorInput>;
7
+ export default ColorInput;
@@ -0,0 +1,40 @@
1
+ <script lang="ts">
2
+ import type { DropdownWidgetConfig, SupportedTypes } from '../../../types/generated';
3
+ import * as Select from '../../ui/select';
4
+
5
+ interface Props {
6
+ value?: string;
7
+ config?: DropdownWidgetConfig;
8
+ onChange: (value: SupportedTypes) => void;
9
+ disabled?: boolean;
10
+ }
11
+
12
+ let { value, config, onChange, disabled = false }: Props = $props();
13
+
14
+ const options = $derived(config?.options || {});
15
+ const currentValue = $derived(value || '');
16
+ const currentLabel = $derived(
17
+ Object.entries(options).find(([_, v]) => v === currentValue)?.[0] ?? currentValue
18
+ );
19
+ </script>
20
+
21
+ <Select.Root
22
+ type="single"
23
+ value={currentValue}
24
+ onValueChange={(selected) => {
25
+ if (selected) {
26
+ value = selected;
27
+ onChange(selected);
28
+ }
29
+ }}
30
+ {disabled}
31
+ >
32
+ <Select.Trigger class="w-full" {disabled}>
33
+ {currentLabel || 'Select an option...'}
34
+ </Select.Trigger>
35
+ <Select.Content>
36
+ {#each Object.entries(options) as [name, val] (val)}
37
+ <Select.Item value={val || ''} label={name} />
38
+ {/each}
39
+ </Select.Content>
40
+ </Select.Root>
@@ -0,0 +1,10 @@
1
+ import type { DropdownWidgetConfig, SupportedTypes } from '../../../types/generated';
2
+ interface Props {
3
+ value?: string;
4
+ config?: DropdownWidgetConfig;
5
+ onChange: (value: SupportedTypes) => void;
6
+ disabled?: boolean;
7
+ }
8
+ declare const DropdownInput: import("svelte").Component<Props, {}, "">;
9
+ type DropdownInput = ReturnType<typeof DropdownInput>;
10
+ export default DropdownInput;
@@ -0,0 +1,358 @@
1
+ <script lang="ts">
2
+ import { Input } from '../../ui/input';
3
+ import { Button } from '../../ui/button';
4
+ import { Label } from '../../ui/label';
5
+ import { FileUp, Link, CircleAlert, CircleCheck } from '@lucide/svelte';
6
+ import { APP_CONSTANTS } from '../../../constants';
7
+
8
+ interface Props {
9
+ value?: string;
10
+ acceptedFormats?: string[];
11
+ defaultInputMode?: 'upload' | 'url';
12
+ allowedInputModes?: ('upload' | 'url')[];
13
+ onChange: (value: string) => void;
14
+ }
15
+
16
+ let {
17
+ value = $bindable(),
18
+ acceptedFormats = [],
19
+ defaultInputMode = 'upload',
20
+ allowedInputModes,
21
+ onChange
22
+ }: Props = $props();
23
+
24
+ // Resolve which modes are actually available
25
+ let effectiveModes = $derived(
26
+ allowedInputModes && allowedInputModes.length > 0 ? allowedInputModes : (['upload', 'url'] as const)
27
+ );
28
+ let showToggle = $derived(effectiveModes.length > 1);
29
+
30
+ // Active mode: default to defaultInputMode if allowed, otherwise first allowed mode
31
+ let activeMode = $state<'upload' | 'url'>('upload');
32
+ $effect(() => {
33
+ const preferred = defaultInputMode ?? 'upload';
34
+ activeMode = effectiveModes.includes(preferred) ? preferred : effectiveModes[0];
35
+ });
36
+
37
+ let fileInput: HTMLInputElement | null = $state(null);
38
+ let uploadedFileName = $state('');
39
+ let urlInput = $state('');
40
+ let isDragging = $state(false);
41
+ let isLoading = $state(false);
42
+ let urlError = $state<{ message: string; isCors: boolean } | null>(null);
43
+ let urlSuccess = $state('');
44
+
45
+ // Parse existing value if it's JSON
46
+ $effect(() => {
47
+ if (value) {
48
+ try {
49
+ const parsed = typeof value === 'string' ? JSON.parse(value) : value;
50
+
51
+ if (parsed.type === 'base64') {
52
+ if (parsed._isMetadata && parsed._fileSize) {
53
+ const sizeMB = (parsed._fileSize / 1024 / 1024).toFixed(2);
54
+ uploadedFileName = `Uploaded file (${parsed.fileEnding}, ${sizeMB}MB)`;
55
+ } else {
56
+ uploadedFileName = `Uploaded file (${parsed.fileEnding})`;
57
+ }
58
+ } else if (parsed.type === 'url') {
59
+ urlInput = parsed.file;
60
+ }
61
+ } catch {
62
+ // Not JSON, ignore
63
+ }
64
+ }
65
+ });
66
+
67
+ function getFileExtension(filename: string): string {
68
+ // Strip query strings before extracting extension
69
+ const cleanPath = filename.split('?')[0];
70
+ const ext = cleanPath.includes('.') ? '.' + cleanPath.split('.').pop() : '.tmp';
71
+ return ext.toLowerCase();
72
+ }
73
+
74
+ function isValidFileExtension(fileEnding: string): boolean {
75
+ if (acceptedFormats.length === 0) return true;
76
+ return acceptedFormats.includes(fileEnding.toLowerCase());
77
+ }
78
+
79
+ function isCorsError(error: unknown): boolean {
80
+ // CORS errors surface as a generic TypeError with no useful status code
81
+ // because the browser blocks the response entirely
82
+ if (error instanceof TypeError && error.message === 'Failed to fetch') return true;
83
+ return false;
84
+ }
85
+
86
+ async function handleUrlChange() {
87
+ if (!urlInput.trim()) return;
88
+
89
+ // Reset all state before starting a new fetch
90
+ isLoading = true;
91
+ urlError = null;
92
+ urlSuccess = '';
93
+ uploadedFileName = '';
94
+
95
+ try {
96
+ // Validate URL format first
97
+ let parsedUrl: URL;
98
+ try {
99
+ parsedUrl = new URL(urlInput);
100
+ } catch {
101
+ urlError = { message: 'Invalid URL — make sure it starts with https://', isCors: false };
102
+ isLoading = false;
103
+ return;
104
+ }
105
+
106
+ if (parsedUrl.protocol !== 'https:' && parsedUrl.protocol !== 'http:') {
107
+ urlError = { message: 'Only http:// and https:// URLs are supported.', isCors: false };
108
+ isLoading = false;
109
+ return;
110
+ }
111
+
112
+ const response = await fetch(urlInput);
113
+ if (!response.ok) {
114
+ urlError = {
115
+ message: `Server returned ${response.status} ${response.statusText}. Check the URL is correct and publicly accessible.`,
116
+ isCors: false
117
+ };
118
+ isLoading = false;
119
+ return;
120
+ }
121
+
122
+ const blob = await response.blob();
123
+ const fileEnding = getFileExtension(urlInput);
124
+
125
+ if (!isValidFileExtension(fileEnding)) {
126
+ urlError = {
127
+ message: `File format "${fileEnding}" is not accepted. Allowed: ${acceptedFormats.join(', ')}`,
128
+ isCors: false
129
+ };
130
+ isLoading = false;
131
+ return;
132
+ }
133
+
134
+ const maxSize = APP_CONSTANTS.FILE_UPLOAD.MAX_SIZE_BYTES;
135
+ if (blob.size > maxSize) {
136
+ urlError = {
137
+ message: `File too large: ${(blob.size / 1024 / 1024).toFixed(2)}MB (max ${APP_CONSTANTS.FILE_UPLOAD.MAX_SIZE_MB}MB). Download it and use Upload instead.`,
138
+ isCors: false
139
+ };
140
+ isLoading = false;
141
+ return;
142
+ }
143
+
144
+ // FileReader is async — keep isLoading=true until it completes
145
+ await new Promise<void>((resolve, reject) => {
146
+ const reader = new FileReader();
147
+ reader.onload = (e) => {
148
+ const base64 = e.target?.result as string;
149
+ const base64Data = base64.includes(',') ? base64.split(',')[1] : base64;
150
+ const data = JSON.stringify({ file: base64Data, type: 'base64', fileEnding });
151
+ value = data;
152
+ urlSuccess = `Loaded ${fileEnding} (${(blob.size / 1024).toFixed(0)} KB)`;
153
+ onChange(data);
154
+ resolve();
155
+ };
156
+ reader.onerror = () => reject(new Error('Failed to read the downloaded file.'));
157
+ reader.readAsDataURL(blob);
158
+ });
159
+ } catch (error) {
160
+ if (isCorsError(error)) {
161
+ const host = (() => { try { return new URL(urlInput).hostname; } catch { return ''; } })();
162
+ // We can't distinguish CORS blocks from non-CORS network errors (404, DNS fail, etc.)
163
+ // because the browser hides all of them behind the same opaque TypeError.
164
+ // Give a message that covers both cases.
165
+ let hint = 'Check that the URL is correct and the file is publicly accessible. If the server requires login, download the file and use the Upload option instead.';
166
+ if (host.includes('sharepoint.com') || host.includes('onedrive.com')) {
167
+ hint = 'SharePoint/OneDrive blocks browser access. Open the file in SharePoint, use "Download" to save it locally, then upload it here.';
168
+ } else if (host.includes('drive.google.com')) {
169
+ hint = 'Google Drive blocks browser access. Use "Download" in Google Drive to save the file locally, then upload it here.';
170
+ } else if (host.includes('dropbox.com')) {
171
+ hint = 'Dropbox links may block browser access. Try changing "?dl=0" to "?dl=1" in the URL, or download and upload instead.';
172
+ }
173
+ urlError = {
174
+ message: `Could not reach "${host}" — the file may not exist, or the server does not allow browser access.`,
175
+ isCors: true,
176
+ // @ts-ignore
177
+ hint
178
+ };
179
+ } else {
180
+ urlError = {
181
+ message: error instanceof Error ? error.message : 'Unknown error',
182
+ isCors: false
183
+ };
184
+ }
185
+ } finally {
186
+ isLoading = false;
187
+ }
188
+ }
189
+
190
+ function handleFileUpload(event: Event) {
191
+ const target = event.target as HTMLInputElement;
192
+ const file = target.files?.[0];
193
+ if (!file) return;
194
+
195
+ const fileEnding = getFileExtension(file.name);
196
+
197
+ if (!isValidFileExtension(fileEnding)) {
198
+ alert(`File format not accepted: ${fileEnding}`);
199
+ return;
200
+ }
201
+
202
+ uploadedFileName = file.name;
203
+
204
+ const reader = new FileReader();
205
+ reader.onload = (e) => {
206
+ const base64 = e.target?.result as string;
207
+ const base64Data = base64.includes(',') ? base64.split(',')[1] : base64;
208
+
209
+ const data = JSON.stringify({
210
+ file: base64Data,
211
+ type: 'base64',
212
+ fileEnding
213
+ });
214
+ value = data;
215
+ onChange(data);
216
+ };
217
+ reader.readAsDataURL(file);
218
+ }
219
+
220
+ function openFilePicker() {
221
+ fileInput?.click();
222
+ }
223
+
224
+ function handleDragOver(e: DragEvent) {
225
+ e.preventDefault();
226
+ isDragging = true;
227
+ }
228
+
229
+ function handleDragLeave() {
230
+ isDragging = false;
231
+ }
232
+
233
+ function handleDrop(e: DragEvent) {
234
+ e.preventDefault();
235
+ isDragging = false;
236
+
237
+ const files = e.dataTransfer?.files;
238
+ if (files?.[0]) {
239
+ const fakeEvent = new Event('change');
240
+ const fakeTarget = { files: files } as HTMLInputElement;
241
+ Object.defineProperty(fakeEvent, 'target', { value: fakeTarget });
242
+ handleFileUpload(fakeEvent);
243
+ }
244
+ }
245
+
246
+ const acceptAttribute = $derived(acceptedFormats.length > 0 ? acceptedFormats.join(',') : '*');
247
+ </script>
248
+
249
+ <div class="gap-4 flex w-full flex-col">
250
+ <!-- Hidden file input -->
251
+ <input
252
+ bind:this={fileInput}
253
+ type="file"
254
+ accept={acceptAttribute}
255
+ onchange={handleFileUpload}
256
+ class="hidden"
257
+ />
258
+
259
+ <!-- Mode toggle (only shown when both modes are allowed) -->
260
+ {#if showToggle}
261
+ <div class="flex rounded border overflow-hidden text-xs">
262
+ {#each effectiveModes as mode (mode)}
263
+ <button
264
+ type="button"
265
+ onclick={() => (activeMode = mode)}
266
+ class={`flex-1 px-3 py-1 transition-colors ${
267
+ activeMode === mode
268
+ ? 'bg-primary text-primary-foreground'
269
+ : 'hover:bg-accent text-muted-foreground'
270
+ }`}
271
+ >
272
+ {mode === 'upload' ? 'Upload' : 'URL'}
273
+ </button>
274
+ {/each}
275
+ </div>
276
+ {/if}
277
+
278
+ {#if activeMode === 'url'}
279
+ <!-- URL Input -->
280
+ <div class="gap-2 flex flex-col">
281
+ <Label for="url-input" class="gap-2 flex items-center">
282
+ <Link size={16} />
283
+ File URL
284
+ </Label>
285
+ <div class="gap-2 flex">
286
+ <Input
287
+ id="url-input"
288
+ type="url"
289
+ bind:value={urlInput}
290
+ placeholder="https://example.com/model.3dm"
291
+ disabled={isLoading}
292
+ class={urlError ? 'border-destructive focus-visible:ring-destructive' : ''}
293
+ oninput={() => { urlError = null; urlSuccess = ''; }}
294
+ />
295
+ <Button
296
+ type="button"
297
+ variant="outline"
298
+ disabled={isLoading || !urlInput.trim()}
299
+ onclick={handleUrlChange}
300
+ >
301
+ {isLoading ? 'Fetching...' : 'Fetch'}
302
+ </Button>
303
+ </div>
304
+
305
+ <!-- Success state -->
306
+ {#if urlSuccess}
307
+ <div class="flex items-center gap-1.5 text-xs text-success">
308
+ <CircleCheck size={13} />
309
+ {urlSuccess}
310
+ </div>
311
+ {/if}
312
+
313
+ <!-- Error state -->
314
+ {#if urlError}
315
+ <div class="rounded-md border border-destructive/40 bg-destructive/5 p-2.5 flex flex-col gap-1.5">
316
+ <div class="flex items-start gap-1.5">
317
+ <CircleAlert size={13} class="text-destructive mt-0.5 shrink-0" />
318
+ <p class="text-xs text-destructive leading-snug">{urlError.message}</p>
319
+ </div>
320
+ {#if urlError.isCors && (urlError as any).hint}
321
+ <p class="text-xs text-muted-foreground leading-snug pl-5">{(urlError as any).hint}</p>
322
+ {/if}
323
+ </div>
324
+ {/if}
325
+
326
+ {#if !urlError && !urlSuccess}
327
+ <p class="text-xs text-muted-foreground">
328
+ URL must be publicly accessible (no login required).
329
+ </p>
330
+ {/if}
331
+ </div>
332
+ {:else}
333
+ <!-- File Upload -->
334
+ <div class="gap-2 flex flex-col">
335
+ <Label for="file-upload" class="gap-2 flex items-center">
336
+ <FileUp size={16} />
337
+ Upload File
338
+ </Label>
339
+ <Button
340
+ type="button"
341
+ variant="outline"
342
+ class="gap-2 w-full {isDragging ? 'border-primary' : ''}"
343
+ onclick={openFilePicker}
344
+ ondragover={handleDragOver}
345
+ ondragleave={handleDragLeave}
346
+ ondrop={handleDrop}
347
+ >
348
+ <FileUp size={16} />
349
+ {uploadedFileName || 'Choose File or Drag & Drop'}
350
+ </Button>
351
+ {#if acceptedFormats.length > 0}
352
+ <p class="text-xs text-muted-foreground">
353
+ Accepted formats: {acceptedFormats.join(', ')}
354
+ </p>
355
+ {/if}
356
+ </div>
357
+ {/if}
358
+ </div>
@@ -0,0 +1,10 @@
1
+ interface Props {
2
+ value?: string;
3
+ acceptedFormats?: string[];
4
+ defaultInputMode?: 'upload' | 'url';
5
+ allowedInputModes?: ('upload' | 'url')[];
6
+ onChange: (value: string) => void;
7
+ }
8
+ declare const FileInput: import("svelte").Component<Props, {}, "value">;
9
+ type FileInput = ReturnType<typeof FileInput>;
10
+ export default FileInput;
@@ -0,0 +1,152 @@
1
+ <script lang="ts">
2
+ import type { NumberWidgetConfig, SupportedTypes } from '../../../types/generated';
3
+ import { debounce } from '../../../utils/debounce';
4
+ import { Input } from '../../ui/input';
5
+ import { Slider } from '../../ui/slider';
6
+ import * as Field from '../../ui/field';
7
+
8
+ interface Props {
9
+ inputId: string;
10
+ value?: number;
11
+ config?: NumberWidgetConfig;
12
+ onChange: (value: SupportedTypes) => void;
13
+ disabled?: boolean;
14
+ }
15
+
16
+ let { inputId, value = $bindable(), config, onChange, disabled = false }: Props = $props();
17
+
18
+ let validationError = $state<string | null>(null);
19
+ let sliderEditing = $state(false);
20
+ let sliderInputValue = $state('');
21
+
22
+ const min = $derived(config?.minimum ?? 0);
23
+ const max = $derived(config?.maximum ?? 100);
24
+ const step = $derived(config?.stepSize ?? 1);
25
+ const numValue = $derived(typeof value === 'number' ? value : min);
26
+
27
+ const commitDebounced = debounce((newValue: SupportedTypes) => onChange(newValue), 400);
28
+ const commitSliderDebounced = debounce((newValue: SupportedTypes) => onChange(newValue), 150);
29
+
30
+ function validateNumber(val: number): string | null {
31
+ if (config?.minimum !== undefined && val < config.minimum)
32
+ return `Minimum value is ${config.minimum}`;
33
+ if (config?.maximum !== undefined && val > config.maximum)
34
+ return `Maximum value is ${config.maximum}`;
35
+ return null;
36
+ }
37
+
38
+ function handleNumberInput(newValue: number) {
39
+ const error = validateNumber(newValue);
40
+ validationError = error;
41
+ if (!error) {
42
+ value = newValue;
43
+ commitDebounced(newValue);
44
+ }
45
+ }
46
+
47
+ function handleSliderChange(newValue: number) {
48
+ value = newValue;
49
+ commitSliderDebounced(newValue);
50
+ }
51
+
52
+ function focusSliderInput(node: HTMLInputElement) {
53
+ node.focus();
54
+ node.select();
55
+ }
56
+
57
+ function decimalPlaces(stepSize: number): number {
58
+ return Math.max(0, -Math.floor(Math.log10(stepSize)));
59
+ }
60
+ </script>
61
+
62
+ {#if config?.renderAsSlider}
63
+ {@const dp = decimalPlaces(step)}
64
+ <div class="gap-4 flex items-center">
65
+ <Slider
66
+ type="single"
67
+ value={numValue}
68
+ {min}
69
+ {max}
70
+ {step}
71
+ class="flex-1"
72
+ onValueChange={handleSliderChange}
73
+ {disabled}
74
+ />
75
+ {#if sliderEditing}
76
+ <input
77
+ use:focusSliderInput
78
+ type="number"
79
+ {step}
80
+ class="min-w-12 w-16 text-sm border-b border-border bg-transparent text-right outline-none focus:border-foreground"
81
+ bind:value={sliderInputValue}
82
+ onblur={() => {
83
+ const parsed = parseFloat(sliderInputValue);
84
+ if (!isNaN(parsed)) handleSliderChange(Math.min(max, Math.max(min, parsed)));
85
+ sliderEditing = false;
86
+ }}
87
+ onkeydown={(e) => {
88
+ if (e.key === 'Enter') {
89
+ const parsed = parseFloat(sliderInputValue);
90
+ if (!isNaN(parsed)) handleSliderChange(Math.min(max, Math.max(min, parsed)));
91
+ sliderEditing = false;
92
+ } else if (e.key === 'Escape') {
93
+ sliderEditing = false;
94
+ }
95
+ }}
96
+ />
97
+ {:else}
98
+ <span
99
+ role="button"
100
+ tabindex={0}
101
+ class="min-w-12 text-sm cursor-text text-right text-muted-foreground select-none"
102
+ title="Double-click to edit"
103
+ ondblclick={() => {
104
+ sliderInputValue = numValue.toFixed(dp);
105
+ sliderEditing = true;
106
+ }}
107
+ onkeydown={(e) => {
108
+ if (e.key === 'Enter' || e.key === ' ') {
109
+ sliderInputValue = numValue.toFixed(dp);
110
+ sliderEditing = true;
111
+ }
112
+ }}
113
+ >
114
+ {numValue.toFixed(dp)}
115
+ </span>
116
+ {/if}
117
+ </div>
118
+ {:else}
119
+ <Input
120
+ id={inputId}
121
+ type="number"
122
+ value={numValue}
123
+ min={config?.minimum}
124
+ max={config?.maximum}
125
+ {step}
126
+ placeholder={config?.placeholder}
127
+ data-invalid={validationError ? true : undefined}
128
+ aria-invalid={validationError ? true : undefined}
129
+ class={validationError ? 'border-destructive' : ''}
130
+ {disabled}
131
+ oninput={() => (validationError = null)}
132
+ onchange={(e) => {
133
+ const newValue = parseFloat((e.currentTarget as HTMLInputElement).value);
134
+ if (!isNaN(newValue)) handleNumberInput(newValue);
135
+ }}
136
+ onblur={(e) => {
137
+ const newValue = parseFloat((e.currentTarget as HTMLInputElement).value);
138
+ if (!isNaN(newValue)) {
139
+ const error = validateNumber(newValue);
140
+ validationError = error;
141
+ if (!error) {
142
+ value = newValue;
143
+ onChange(newValue);
144
+ }
145
+ }
146
+ }}
147
+ />
148
+ {/if}
149
+
150
+ {#if validationError}
151
+ <Field.Error>{validationError}</Field.Error>
152
+ {/if}
@@ -0,0 +1,11 @@
1
+ import type { NumberWidgetConfig, SupportedTypes } from '../../../types/generated';
2
+ interface Props {
3
+ inputId: string;
4
+ value?: number;
5
+ config?: NumberWidgetConfig;
6
+ onChange: (value: SupportedTypes) => void;
7
+ disabled?: boolean;
8
+ }
9
+ declare const NumberInput: import("svelte").Component<Props, {}, "value">;
10
+ type NumberInput = ReturnType<typeof NumberInput>;
11
+ export default NumberInput;
@@ -0,0 +1,74 @@
1
+ <script lang="ts">
2
+ import type { TextWidgetConfig, SupportedTypes } from '../../../types/generated';
3
+ import { debounce } from '../../../utils/debounce';
4
+ import { Input } from '../../ui/input';
5
+ import * as Field from '../../ui/field';
6
+
7
+ interface Props {
8
+ inputId: string;
9
+ value?: string;
10
+ config?: TextWidgetConfig;
11
+ onChange: (value: SupportedTypes) => void;
12
+ disabled?: boolean;
13
+ }
14
+
15
+ let { inputId, value = $bindable(), config, onChange, disabled = false }: Props = $props();
16
+
17
+ let validationError = $state<string | null>(null);
18
+ let currentValue = $state(value || '');
19
+
20
+ const commitDebounced = debounce((newValue: SupportedTypes) => onChange(newValue), 400);
21
+
22
+ function validateText(val: string): string | null {
23
+ if (config?.maxLength && val.length > config.maxLength)
24
+ return `Maximum ${config.maxLength} characters allowed`;
25
+ if (config?.pattern) {
26
+ try {
27
+ if (!new RegExp(config.pattern).test(val))
28
+ return config.customErrorMessage || 'Invalid format';
29
+ } catch {
30
+ return 'Invalid validation pattern configured';
31
+ }
32
+ }
33
+ return null;
34
+ }
35
+
36
+ function handleChange() {
37
+ const error = validateText(currentValue);
38
+ validationError = error;
39
+ if (!error) {
40
+ value = currentValue;
41
+ commitDebounced(currentValue);
42
+ }
43
+ }
44
+ </script>
45
+
46
+ <Input
47
+ id={inputId}
48
+ type="text"
49
+ bind:value={currentValue}
50
+ placeholder={config?.placeholder}
51
+ maxlength={config?.maxLength}
52
+ data-invalid={validationError ? true : undefined}
53
+ aria-invalid={validationError ? true : undefined}
54
+ class={validationError ? 'border-destructive' : ''}
55
+ {disabled}
56
+ oninput={() => {
57
+ validationError = null;
58
+ handleChange();
59
+ }}
60
+ onblur={(e) => {
61
+ const val = (e.currentTarget as HTMLInputElement).value;
62
+ const error = validateText(val);
63
+ validationError = error;
64
+ if (!error) {
65
+ currentValue = val;
66
+ value = val;
67
+ onChange(val);
68
+ }
69
+ }}
70
+ />
71
+
72
+ {#if validationError}
73
+ <Field.Error>{validationError}</Field.Error>
74
+ {/if}
@@ -0,0 +1,11 @@
1
+ import type { TextWidgetConfig, SupportedTypes } from '../../../types/generated';
2
+ interface Props {
3
+ inputId: string;
4
+ value?: string;
5
+ config?: TextWidgetConfig;
6
+ onChange: (value: SupportedTypes) => void;
7
+ disabled?: boolean;
8
+ }
9
+ declare const TextInput: import("svelte").Component<Props, {}, "value">;
10
+ type TextInput = ReturnType<typeof TextInput>;
11
+ export default TextInput;
@@ -0,0 +1,6 @@
1
+ export { default as CheckboxInput } from './CheckboxInput.svelte';
2
+ export { default as ColorInput } from './ColorInput.svelte';
3
+ export { default as DropdownInput } from './DropdownInput.svelte';
4
+ export { default as FileInput } from './FileInput.svelte';
5
+ export { default as NumberInput } from './NumberInput.svelte';
6
+ export { default as TextInput } from './TextInput.svelte';
@@ -0,0 +1,6 @@
1
+ export { default as CheckboxInput } from './CheckboxInput.svelte';
2
+ export { default as ColorInput } from './ColorInput.svelte';
3
+ export { default as DropdownInput } from './DropdownInput.svelte';
4
+ export { default as FileInput } from './FileInput.svelte';
5
+ export { default as NumberInput } from './NumberInput.svelte';
6
+ export { default as TextInput } from './TextInput.svelte';