@happyvertical/smrt-svelte 0.55.6 → 0.55.8

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 (318) hide show
  1. package/AGENTS.md +9 -31
  2. package/README.md +195 -5
  3. package/agents/browser-ai.md +47 -0
  4. package/agents/command-palette.md +85 -0
  5. package/agents/import-export.md +62 -0
  6. package/agents/overview-surfaces.md +255 -0
  7. package/agents/screens.md +57 -0
  8. package/agents/workspace.md +202 -5
  9. package/dist/browser-ai/adapters/stt/dictation-source.d.ts.map +1 -1
  10. package/dist/browser-ai/adapters/stt/dictation-source.js +8 -2
  11. package/dist/browser-ai/adapters/stt/factory.d.ts +6 -3
  12. package/dist/browser-ai/adapters/stt/factory.d.ts.map +1 -1
  13. package/dist/browser-ai/adapters/stt/factory.js +19 -9
  14. package/dist/browser-ai/adapters/stt/index.d.ts +3 -1
  15. package/dist/browser-ai/adapters/stt/index.d.ts.map +1 -1
  16. package/dist/browser-ai/adapters/stt/index.js +3 -1
  17. package/dist/browser-ai/adapters/stt/local-speech-model.d.ts +111 -0
  18. package/dist/browser-ai/adapters/stt/local-speech-model.d.ts.map +1 -0
  19. package/dist/browser-ai/adapters/stt/local-speech-model.js +377 -0
  20. package/dist/browser-ai/adapters/stt/local-speech.d.ts +82 -0
  21. package/dist/browser-ai/adapters/stt/local-speech.d.ts.map +1 -0
  22. package/dist/browser-ai/adapters/stt/local-speech.js +317 -0
  23. package/dist/browser-ai/adapters/stt/local-speech.worker.d.ts +2 -0
  24. package/dist/browser-ai/adapters/stt/local-speech.worker.d.ts.map +1 -0
  25. package/dist/browser-ai/adapters/stt/local-speech.worker.js +32 -0
  26. package/dist/browser-ai/adapters/stt/transformers-env.d.ts +8 -0
  27. package/dist/browser-ai/adapters/stt/transformers-env.d.ts.map +1 -0
  28. package/dist/browser-ai/adapters/stt/transformers-env.js +17 -0
  29. package/dist/browser-ai/adapters/stt/types.d.ts +54 -9
  30. package/dist/browser-ai/adapters/stt/types.d.ts.map +1 -1
  31. package/dist/browser-ai/adapters/tts/browser-synthesis.d.ts +5 -0
  32. package/dist/browser-ai/adapters/tts/browser-synthesis.d.ts.map +1 -1
  33. package/dist/browser-ai/adapters/tts/browser-synthesis.js +83 -55
  34. package/dist/browser-ai/capabilities/speech-probe.d.ts +29 -0
  35. package/dist/browser-ai/capabilities/speech-probe.d.ts.map +1 -0
  36. package/dist/browser-ai/capabilities/speech-probe.js +19 -0
  37. package/dist/browser-ai/core/errors.d.ts +9 -0
  38. package/dist/browser-ai/core/errors.d.ts.map +1 -1
  39. package/dist/browser-ai/core/errors.js +12 -0
  40. package/dist/browser-ai/index.d.ts +1 -0
  41. package/dist/browser-ai/index.d.ts.map +1 -1
  42. package/dist/browser-ai/index.js +1 -0
  43. package/dist/components/app/AppShell.svelte +587 -33
  44. package/dist/components/app/AppShell.svelte.d.ts +75 -4
  45. package/dist/components/app/AppShell.svelte.d.ts.map +1 -1
  46. package/dist/components/app/DockToggles.svelte +0 -1
  47. package/dist/components/app/dock-toggle.d.ts +7 -1
  48. package/dist/components/app/dock-toggle.d.ts.map +1 -1
  49. package/dist/components/app/index.d.ts +2 -1
  50. package/dist/components/app/index.d.ts.map +1 -1
  51. package/dist/components/app/slot-item.d.ts +21 -0
  52. package/dist/components/app/slot-item.d.ts.map +1 -0
  53. package/dist/components/app/slot-item.js +1 -0
  54. package/dist/components/command-palette/CommandPalette.svelte +75 -0
  55. package/dist/components/command-palette/CommandPalette.svelte.d.ts +22 -0
  56. package/dist/components/command-palette/CommandPalette.svelte.d.ts.map +1 -0
  57. package/dist/components/command-palette/CommandPaletteDialog.svelte +406 -0
  58. package/dist/components/command-palette/CommandPaletteDialog.svelte.d.ts +18 -0
  59. package/dist/components/command-palette/CommandPaletteDialog.svelte.d.ts.map +1 -0
  60. package/dist/components/command-palette/CommandPaletteTrigger.svelte +91 -0
  61. package/dist/components/command-palette/CommandPaletteTrigger.svelte.d.ts +17 -0
  62. package/dist/components/command-palette/CommandPaletteTrigger.svelte.d.ts.map +1 -0
  63. package/dist/components/command-palette/context.d.ts +18 -0
  64. package/dist/components/command-palette/context.d.ts.map +1 -0
  65. package/dist/components/command-palette/context.js +38 -0
  66. package/dist/components/command-palette/controller.svelte.d.ts +70 -0
  67. package/dist/components/command-palette/controller.svelte.d.ts.map +1 -0
  68. package/dist/components/command-palette/controller.svelte.js +379 -0
  69. package/dist/components/command-palette/hotkeys.d.ts +30 -0
  70. package/dist/components/command-palette/hotkeys.d.ts.map +1 -0
  71. package/dist/components/command-palette/hotkeys.js +161 -0
  72. package/dist/components/command-palette/index.d.ts +19 -0
  73. package/dist/components/command-palette/index.d.ts.map +1 -0
  74. package/dist/components/command-palette/index.js +17 -0
  75. package/dist/components/command-palette/match.d.ts +38 -0
  76. package/dist/components/command-palette/match.d.ts.map +1 -0
  77. package/dist/components/command-palette/match.js +172 -0
  78. package/dist/components/command-palette/providers.d.ts +159 -0
  79. package/dist/components/command-palette/providers.d.ts.map +1 -0
  80. package/dist/components/command-palette/providers.js +345 -0
  81. package/dist/components/command-palette/rank.d.ts +20 -0
  82. package/dist/components/command-palette/rank.d.ts.map +1 -0
  83. package/dist/components/command-palette/rank.js +74 -0
  84. package/dist/components/command-palette/types.d.ts +119 -0
  85. package/dist/components/command-palette/types.d.ts.map +1 -0
  86. package/dist/components/command-palette/types.js +10 -0
  87. package/dist/components/command-palette/use-provider.svelte.d.ts +14 -0
  88. package/dist/components/command-palette/use-provider.svelte.d.ts.map +1 -0
  89. package/dist/components/command-palette/use-provider.svelte.js +23 -0
  90. package/dist/components/forms/AddressInput.svelte +2 -15
  91. package/dist/components/forms/AddressInput.svelte.d.ts.map +1 -1
  92. package/dist/components/forms/DateRangeInput.svelte +2 -15
  93. package/dist/components/forms/DateRangeInput.svelte.d.ts.map +1 -1
  94. package/dist/components/forms/DateTimeInput.svelte +8 -15
  95. package/dist/components/forms/DateTimeInput.svelte.d.ts.map +1 -1
  96. package/dist/components/forms/MeasurementInput.svelte +2 -15
  97. package/dist/components/forms/MeasurementInput.svelte.d.ts.map +1 -1
  98. package/dist/components/forms/MoneyInput.svelte +8 -25
  99. package/dist/components/forms/MoneyInput.svelte.d.ts.map +1 -1
  100. package/dist/components/forms/NumberInput.svelte +7 -15
  101. package/dist/components/forms/NumberInput.svelte.d.ts.map +1 -1
  102. package/dist/components/forms/PhoneInput.svelte +7 -15
  103. package/dist/components/forms/PhoneInput.svelte.d.ts.map +1 -1
  104. package/dist/components/forms/SelectInput.svelte +34 -40
  105. package/dist/components/forms/SelectInput.svelte.d.ts.map +1 -1
  106. package/dist/components/forms/TextInput.svelte +20 -37
  107. package/dist/components/forms/TextInput.svelte.d.ts.map +1 -1
  108. package/dist/components/forms/TextareaInput.svelte +19 -35
  109. package/dist/components/forms/TextareaInput.svelte.d.ts.map +1 -1
  110. package/dist/components/import-export/ImportExport.svelte +678 -0
  111. package/dist/components/import-export/ImportExport.svelte.d.ts +5 -0
  112. package/dist/components/import-export/ImportExport.svelte.d.ts.map +1 -0
  113. package/dist/components/import-export/collection-adapter.d.ts +35 -0
  114. package/dist/components/import-export/collection-adapter.d.ts.map +1 -0
  115. package/dist/components/import-export/collection-adapter.js +42 -0
  116. package/dist/components/import-export/csv.d.ts +60 -0
  117. package/dist/components/import-export/csv.d.ts.map +1 -0
  118. package/dist/components/import-export/csv.js +192 -0
  119. package/dist/components/import-export/download.d.ts +4 -0
  120. package/dist/components/import-export/download.d.ts.map +1 -0
  121. package/dist/components/import-export/download.js +17 -0
  122. package/dist/components/import-export/export.d.ts +25 -0
  123. package/dist/components/import-export/export.d.ts.map +1 -0
  124. package/dist/components/import-export/export.js +68 -0
  125. package/dist/components/import-export/fields.d.ts +48 -0
  126. package/dist/components/import-export/fields.d.ts.map +1 -0
  127. package/dist/components/import-export/fields.js +103 -0
  128. package/dist/components/import-export/index.d.ts +12 -0
  129. package/dist/components/import-export/index.d.ts.map +1 -0
  130. package/dist/components/import-export/index.js +9 -0
  131. package/dist/components/import-export/mapping.d.ts +12 -0
  132. package/dist/components/import-export/mapping.d.ts.map +1 -0
  133. package/dist/components/import-export/mapping.js +38 -0
  134. package/dist/components/import-export/props.d.ts +34 -0
  135. package/dist/components/import-export/props.d.ts.map +1 -0
  136. package/dist/components/import-export/props.js +1 -0
  137. package/dist/components/import-export/report.d.ts +13 -0
  138. package/dist/components/import-export/report.d.ts.map +1 -0
  139. package/dist/components/import-export/report.js +50 -0
  140. package/dist/components/import-export/runner.d.ts +17 -0
  141. package/dist/components/import-export/runner.d.ts.map +1 -0
  142. package/dist/components/import-export/runner.js +39 -0
  143. package/dist/components/import-export/types.d.ts +100 -0
  144. package/dist/components/import-export/types.d.ts.map +1 -0
  145. package/dist/components/import-export/types.js +6 -0
  146. package/dist/components/import-export/validate.d.ts +39 -0
  147. package/dist/components/import-export/validate.d.ts.map +1 -0
  148. package/dist/components/import-export/validate.js +268 -0
  149. package/dist/components/overview/OverviewGrid.svelte +579 -0
  150. package/dist/components/overview/OverviewGrid.svelte.d.ts +5 -0
  151. package/dist/components/overview/OverviewGrid.svelte.d.ts.map +1 -0
  152. package/dist/components/overview/WidgetOptionsForm.svelte +193 -0
  153. package/dist/components/overview/WidgetOptionsForm.svelte.d.ts +5 -0
  154. package/dist/components/overview/WidgetOptionsForm.svelte.d.ts.map +1 -0
  155. package/dist/components/overview/controller.svelte.d.ts +92 -0
  156. package/dist/components/overview/controller.svelte.d.ts.map +1 -0
  157. package/dist/components/overview/controller.svelte.js +336 -0
  158. package/dist/components/overview/format.d.ts +13 -0
  159. package/dist/components/overview/format.d.ts.map +1 -0
  160. package/dist/components/overview/format.js +45 -0
  161. package/dist/components/overview/grid-types.d.ts +52 -0
  162. package/dist/components/overview/grid-types.d.ts.map +1 -0
  163. package/dist/components/overview/grid-types.js +1 -0
  164. package/dist/components/overview/index.d.ts +24 -0
  165. package/dist/components/overview/index.d.ts.map +1 -0
  166. package/dist/components/overview/index.js +22 -0
  167. package/dist/components/overview/load.d.ts +30 -0
  168. package/dist/components/overview/load.d.ts.map +1 -0
  169. package/dist/components/overview/load.js +92 -0
  170. package/dist/components/overview/markdown.d.ts +53 -0
  171. package/dist/components/overview/markdown.d.ts.map +1 -0
  172. package/dist/components/overview/markdown.js +203 -0
  173. package/dist/components/overview/model.d.ts +100 -0
  174. package/dist/components/overview/model.d.ts.map +1 -0
  175. package/dist/components/overview/model.js +460 -0
  176. package/dist/components/overview/recipe-widgets.d.ts +77 -0
  177. package/dist/components/overview/recipe-widgets.d.ts.map +1 -0
  178. package/dist/components/overview/recipe-widgets.js +151 -0
  179. package/dist/components/overview/registry.d.ts +45 -0
  180. package/dist/components/overview/registry.d.ts.map +1 -0
  181. package/dist/components/overview/registry.js +112 -0
  182. package/dist/components/overview/resize.d.ts +25 -0
  183. package/dist/components/overview/resize.d.ts.map +1 -0
  184. package/dist/components/overview/resize.js +41 -0
  185. package/dist/components/overview/schema.d.ts +34 -0
  186. package/dist/components/overview/schema.d.ts.map +1 -0
  187. package/dist/components/overview/schema.js +180 -0
  188. package/dist/components/overview/server.d.ts +14 -0
  189. package/dist/components/overview/server.d.ts.map +1 -0
  190. package/dist/components/overview/server.js +13 -0
  191. package/dist/components/overview/types.d.ts +235 -0
  192. package/dist/components/overview/types.d.ts.map +1 -0
  193. package/dist/components/overview/types.js +17 -0
  194. package/dist/components/overview/widgets/ChartWidget.svelte +111 -0
  195. package/dist/components/overview/widgets/ChartWidget.svelte.d.ts +6 -0
  196. package/dist/components/overview/widgets/ChartWidget.svelte.d.ts.map +1 -0
  197. package/dist/components/overview/widgets/MetricWidget.svelte +86 -0
  198. package/dist/components/overview/widgets/MetricWidget.svelte.d.ts +6 -0
  199. package/dist/components/overview/widgets/MetricWidget.svelte.d.ts.map +1 -0
  200. package/dist/components/overview/widgets/NoteWidget.svelte +61 -0
  201. package/dist/components/overview/widgets/NoteWidget.svelte.d.ts +5 -0
  202. package/dist/components/overview/widgets/NoteWidget.svelte.d.ts.map +1 -0
  203. package/dist/components/overview/widgets/RecordListWidget.svelte +91 -0
  204. package/dist/components/overview/widgets/RecordListWidget.svelte.d.ts +6 -0
  205. package/dist/components/overview/widgets/RecordListWidget.svelte.d.ts.map +1 -0
  206. package/dist/components/overview/widgets/ShortcutsWidget.svelte +80 -0
  207. package/dist/components/overview/widgets/ShortcutsWidget.svelte.d.ts +6 -0
  208. package/dist/components/overview/widgets/ShortcutsWidget.svelte.d.ts.map +1 -0
  209. package/dist/components/overview/widgets/core.d.ts +44 -0
  210. package/dist/components/overview/widgets/core.d.ts.map +1 -0
  211. package/dist/components/overview/widgets/core.js +222 -0
  212. package/dist/components/overview/widgets/data.d.ts +76 -0
  213. package/dist/components/overview/widgets/data.d.ts.map +1 -0
  214. package/dist/components/overview/widgets/data.js +40 -0
  215. package/dist/components/screens/DetailScreen.svelte +220 -0
  216. package/dist/components/screens/DetailScreen.svelte.d.ts +5 -0
  217. package/dist/components/screens/DetailScreen.svelte.d.ts.map +1 -0
  218. package/dist/components/screens/EditForm.svelte +313 -0
  219. package/dist/components/screens/EditForm.svelte.d.ts +5 -0
  220. package/dist/components/screens/EditForm.svelte.d.ts.map +1 -0
  221. package/dist/components/screens/ListScreen.svelte +191 -0
  222. package/dist/components/screens/ListScreen.svelte.d.ts +5 -0
  223. package/dist/components/screens/ListScreen.svelte.d.ts.map +1 -0
  224. package/dist/components/screens/RecipeScreens.svelte +237 -0
  225. package/dist/components/screens/RecipeScreens.svelte.d.ts +5 -0
  226. package/dist/components/screens/RecipeScreens.svelte.d.ts.map +1 -0
  227. package/dist/components/screens/fields.d.ts +54 -0
  228. package/dist/components/screens/fields.d.ts.map +1 -0
  229. package/dist/components/screens/fields.js +229 -0
  230. package/dist/components/screens/index.d.ts +8 -0
  231. package/dist/components/screens/index.d.ts.map +1 -0
  232. package/dist/components/screens/index.js +6 -0
  233. package/dist/components/screens/types.d.ts +215 -0
  234. package/dist/components/screens/types.d.ts.map +1 -0
  235. package/dist/components/screens/types.js +1 -0
  236. package/dist/components/screens/values.d.ts +62 -0
  237. package/dist/components/screens/values.d.ts.map +1 -0
  238. package/dist/components/screens/values.js +289 -0
  239. package/dist/components/sortable/Sortable.svelte +6 -33
  240. package/dist/components/sortable/Sortable.svelte.d.ts.map +1 -1
  241. package/dist/components/sortable/announce.d.ts +5 -0
  242. package/dist/components/sortable/announce.d.ts.map +1 -0
  243. package/dist/components/sortable/announce.js +33 -0
  244. package/dist/components/sortable/controller.svelte.d.ts +10 -0
  245. package/dist/components/sortable/controller.svelte.d.ts.map +1 -1
  246. package/dist/components/sortable/controller.svelte.js +29 -7
  247. package/dist/components/workspace/admin-shell/AdminShell.svelte +424 -58
  248. package/dist/components/workspace/admin-shell/AdminShell.svelte.d.ts +27 -2
  249. package/dist/components/workspace/admin-shell/AdminShell.svelte.d.ts.map +1 -1
  250. package/dist/components/workspace/admin-shell/ShellBrand.svelte +86 -0
  251. package/dist/components/workspace/admin-shell/ShellBrand.svelte.d.ts +18 -0
  252. package/dist/components/workspace/admin-shell/ShellBrand.svelte.d.ts.map +1 -0
  253. package/dist/components/workspace/admin-shell/ShellIconButton.svelte +77 -0
  254. package/dist/components/workspace/admin-shell/ShellIconButton.svelte.d.ts +26 -0
  255. package/dist/components/workspace/admin-shell/ShellIconButton.svelte.d.ts.map +1 -0
  256. package/dist/components/workspace/admin-shell/ShellLayoutEditor.svelte +88 -16
  257. package/dist/components/workspace/admin-shell/ShellLayoutEditor.svelte.d.ts.map +1 -1
  258. package/dist/components/workspace/admin-shell/ShellNavEditor.svelte +531 -0
  259. package/dist/components/workspace/admin-shell/ShellNavEditor.svelte.d.ts +26 -0
  260. package/dist/components/workspace/admin-shell/ShellNavEditor.svelte.d.ts.map +1 -0
  261. package/dist/components/workspace/admin-shell/ShellSectionIcon.svelte +57 -0
  262. package/dist/components/workspace/admin-shell/ShellSectionIcon.svelte.d.ts +22 -0
  263. package/dist/components/workspace/admin-shell/ShellSectionIcon.svelte.d.ts.map +1 -0
  264. package/dist/components/workspace/admin-shell/ShellSectionMenu.svelte +290 -0
  265. package/dist/components/workspace/admin-shell/ShellSectionMenu.svelte.d.ts +32 -0
  266. package/dist/components/workspace/admin-shell/ShellSectionMenu.svelte.d.ts.map +1 -0
  267. package/dist/components/workspace/admin-shell/TenantNav.svelte +67 -2
  268. package/dist/components/workspace/admin-shell/TenantNav.svelte.d.ts +8 -0
  269. package/dist/components/workspace/admin-shell/TenantNav.svelte.d.ts.map +1 -1
  270. package/dist/components/workspace/admin-shell/layout-controller.svelte.d.ts +67 -0
  271. package/dist/components/workspace/admin-shell/layout-controller.svelte.d.ts.map +1 -1
  272. package/dist/components/workspace/admin-shell/layout-controller.svelte.js +129 -1
  273. package/dist/components/workspace/admin-shell/layout.d.ts +122 -0
  274. package/dist/components/workspace/admin-shell/layout.d.ts.map +1 -1
  275. package/dist/components/workspace/admin-shell/layout.js +410 -10
  276. package/dist/components/workspace/admin-shell/settings.js +4 -4
  277. package/dist/components/workspace/admin-shell/shell-icons.d.ts +45 -0
  278. package/dist/components/workspace/admin-shell/shell-icons.d.ts.map +1 -0
  279. package/dist/components/workspace/admin-shell/shell-icons.js +66 -0
  280. package/dist/components/workspace/admin-shell/slot-labels.d.ts +33 -0
  281. package/dist/components/workspace/admin-shell/slot-labels.d.ts.map +1 -0
  282. package/dist/components/workspace/admin-shell/slot-labels.js +33 -0
  283. package/dist/components/workspace/admin-shell/slots.d.ts +50 -0
  284. package/dist/components/workspace/admin-shell/slots.d.ts.map +1 -0
  285. package/dist/components/workspace/admin-shell/slots.js +77 -0
  286. package/dist/components/workspace/admin-shell/state.svelte.d.ts +35 -0
  287. package/dist/components/workspace/admin-shell/state.svelte.d.ts.map +1 -1
  288. package/dist/components/workspace/admin-shell/state.svelte.js +111 -0
  289. package/dist/components/workspace/admin-shell/types.d.ts +101 -1
  290. package/dist/components/workspace/admin-shell/types.d.ts.map +1 -1
  291. package/dist/components/workspace/index.d.ts +9 -2
  292. package/dist/components/workspace/index.d.ts.map +1 -1
  293. package/dist/components/workspace/index.js +6 -0
  294. package/dist/components/workspace/manifest-nav.d.ts +20 -0
  295. package/dist/components/workspace/manifest-nav.d.ts.map +1 -1
  296. package/dist/components/workspace/manifest-nav.js +42 -13
  297. package/dist/i18n/server.d.ts +6 -0
  298. package/dist/i18n/server.d.ts.map +1 -1
  299. package/dist/i18n/server.js +6 -0
  300. package/dist/i18n/strings.import-export.d.ts +88 -0
  301. package/dist/i18n/strings.import-export.d.ts.map +1 -0
  302. package/dist/i18n/strings.import-export.js +88 -0
  303. package/dist/i18n/strings.overview.d.ts +100 -0
  304. package/dist/i18n/strings.overview.d.ts.map +1 -0
  305. package/dist/i18n/strings.overview.js +107 -0
  306. package/dist/i18n/strings.palette.d.ts +18 -0
  307. package/dist/i18n/strings.palette.d.ts.map +1 -0
  308. package/dist/i18n/strings.palette.js +18 -0
  309. package/dist/i18n/strings.screens.d.ts +31 -0
  310. package/dist/i18n/strings.screens.d.ts.map +1 -0
  311. package/dist/i18n/strings.screens.js +31 -0
  312. package/dist/i18n/strings.workspace.d.ts +49 -0
  313. package/dist/i18n/strings.workspace.d.ts.map +1 -1
  314. package/dist/i18n/strings.workspace.js +49 -0
  315. package/package.json +59 -19
  316. package/dist/browser-ai/adapters/stt/whisper-wasm.d.ts +0 -51
  317. package/dist/browser-ai/adapters/stt/whisper-wasm.d.ts.map +0 -1
  318. package/dist/browser-ai/adapters/stt/whisper-wasm.js +0 -380
@@ -0,0 +1,678 @@
1
+ <script lang="ts">
2
+ import { Alert, ProgressBar } from '@happyvertical/smrt-ui/feedback';
3
+ import {
4
+ Checkbox,
5
+ FilePicker,
6
+ SegmentedControl,
7
+ Select,
8
+ } from '@happyvertical/smrt-ui/forms';
9
+ import { useI18n } from '@happyvertical/smrt-ui/i18n';
10
+ import { Badge, Button, Card } from '@happyvertical/smrt-ui/ui';
11
+ import { onDestroy } from 'svelte';
12
+ import { M } from '../../i18n/strings.import-export.js';
13
+ import { CsvParseError, parseTable } from './csv.js';
14
+ import { downloadFile } from './download.js';
15
+ import { buildExportFile, type ExportFormat } from './export.js';
16
+ import { autoMapColumns, setColumnTarget } from './mapping.js';
17
+ import type { ImportExportProps } from './props.js';
18
+ import { buildErrorReport, type IssueMessages } from './report.js';
19
+ import { runImport } from './runner.js';
20
+ import type {
21
+ ImportIssue,
22
+ ImportIssueCode,
23
+ ImportRunResult,
24
+ ParsedTable,
25
+ } from './types.js';
26
+ import { validateRows } from './validate.js';
27
+
28
+ const PREVIEW_ROWS = 10;
29
+ const ISSUE_ROWS = 50;
30
+ const ISSUE_CODES: ImportIssueCode[] = [
31
+ 'required',
32
+ 'invalid-integer',
33
+ 'out-of-range',
34
+ 'invalid-decimal',
35
+ 'invalid-boolean',
36
+ 'invalid-datetime',
37
+ 'invalid-json',
38
+ 'invalid-enum',
39
+ 'invalid-email',
40
+ 'invalid-url',
41
+ 'invalid-reference',
42
+ 'duplicate-value',
43
+ 'duplicate-mapping',
44
+ 'unmapped-required',
45
+ 'extra-cells',
46
+ 'import-failed',
47
+ ];
48
+
49
+ let {
50
+ fields,
51
+ collectionLabel,
52
+ createRecord,
53
+ loadRows,
54
+ filename = 'export',
55
+ maxFileBytes = 5 * 1024 * 1024,
56
+ maxRows = 10_000,
57
+ concurrency = 3,
58
+ mode = 'both',
59
+ ondownload,
60
+ onimported,
61
+ }: ImportExportProps = $props();
62
+
63
+ const { t } = useI18n();
64
+
65
+ const canImport = $derived(mode !== 'export' && createRecord !== undefined);
66
+ const canExport = $derived(mode !== 'import' && loadRows !== undefined);
67
+ let chosenTab = $state<'import' | 'export'>('import');
68
+ const tab = $derived(
69
+ canImport && canExport ? chosenTab : canImport ? 'import' : 'export',
70
+ );
71
+
72
+ const issueMessages = $derived<IssueMessages>(
73
+ Object.fromEntries(
74
+ ISSUE_CODES.map((code) => [code, t(`ui.importExport.issue.${code}`)]),
75
+ ),
76
+ );
77
+ const fieldByName = $derived(new Map(fields.map((f) => [f.name, f])));
78
+ const importable = $derived(fields.filter((f) => f.importable));
79
+ const exportable = $derived(fields.filter((f) => f.exportable));
80
+
81
+ function deliver(file: Parameters<typeof downloadFile>[0]) {
82
+ if (ondownload) ondownload(file);
83
+ else downloadFile(file);
84
+ }
85
+
86
+ // ---- import ---------------------------------------------------------------
87
+ let fileName = $state('');
88
+ let files = $state<File[]>([]);
89
+ let table = $state<ParsedTable | null>(null);
90
+ let mapping = $state<(string | null)[]>([]);
91
+ let fileError = $state<string | null>(null);
92
+ let reading = $state(false);
93
+ let running = $state(false);
94
+ let progress = $state({ done: 0, total: 0 });
95
+ let runResult = $state<ImportRunResult | null>(null);
96
+ let runController: AbortController | null = null;
97
+
98
+ const validation = $derived(
99
+ table
100
+ ? validateRows({
101
+ headers: table.headers,
102
+ rows: table.rows,
103
+ lines: table.lines,
104
+ mapping,
105
+ fields,
106
+ maxIssues: 1000,
107
+ })
108
+ : null,
109
+ );
110
+ const rowIssueCap = $derived(validation?.issues.slice(0, ISSUE_ROWS) ?? []);
111
+ const invalidLines = $derived(
112
+ new Set(validation?.issues.map((i) => i.line) ?? []),
113
+ );
114
+ const mappedColumns = $derived(
115
+ table
116
+ ? mapping.flatMap((target, index) =>
117
+ target !== null && fieldByName.has(target) ? [index] : [],
118
+ )
119
+ : [],
120
+ );
121
+ const mappingBlocked = $derived((validation?.mappingIssues.length ?? 0) > 0);
122
+ const readyCount = $derived(validation?.records.length ?? 0);
123
+ // After a run the rows are saved: lock the form so the same file cannot be
124
+ // imported twice. "Import another file" starts over.
125
+ const locked = $derived(running || runResult !== null);
126
+
127
+ function delimiterName(delimiter: string): string {
128
+ switch (delimiter) {
129
+ case ';':
130
+ return t(M['ui.importExport.delimiter.semicolon']);
131
+ case '\t':
132
+ return t(M['ui.importExport.delimiter.tab']);
133
+ case '|':
134
+ return t(M['ui.importExport.delimiter.pipe']);
135
+ default:
136
+ return t(M['ui.importExport.delimiter.comma']);
137
+ }
138
+ }
139
+
140
+ // Monotonic token for in-flight file reads. A plain `let` on purpose: it is
141
+ // compared by value and must never trigger rendering. Bumped by every new
142
+ // selection, reset, and teardown, so an older read can never land its table
143
+ // and mapping next to a newer file name.
144
+ let readToken = 0;
145
+ onDestroy(() => {
146
+ readToken += 1;
147
+ });
148
+
149
+ function resetImport() {
150
+ readToken += 1;
151
+ reading = false;
152
+ table = null;
153
+ mapping = [];
154
+ fileName = '';
155
+ files = [];
156
+ fileError = null;
157
+ runResult = null;
158
+ progress = { done: 0, total: 0 };
159
+ }
160
+
161
+ async function onFiles(picked: File[]) {
162
+ const token = ++readToken;
163
+ reading = false;
164
+ runResult = null;
165
+ table = null;
166
+ fileError = null;
167
+ const file = picked[0];
168
+ if (!file) return;
169
+ fileName = file.name;
170
+ if (file.size > maxFileBytes) {
171
+ fileError = t(M['ui.importExport.import.tooLarge'], {
172
+ name: file.name,
173
+ size: (file.size / (1024 * 1024)).toFixed(1),
174
+ limit: (maxFileBytes / (1024 * 1024)).toFixed(1),
175
+ });
176
+ return;
177
+ }
178
+ reading = true;
179
+ try {
180
+ const text = await file.text();
181
+ if (token !== readToken) return;
182
+ // maxRows data rows plus the header record.
183
+ const parsed = parseTable(text, { maxRecords: maxRows + 1 });
184
+ table = parsed;
185
+ mapping = autoMapColumns(parsed.headers, fields);
186
+ } catch (error) {
187
+ if (token !== readToken) return;
188
+ if (error instanceof CsvParseError) {
189
+ fileError =
190
+ error.code === 'too-many-rows'
191
+ ? t(M['ui.importExport.import.tooManyRows'], { limit: maxRows })
192
+ : error.code === 'unterminated-quote'
193
+ ? t(M['ui.importExport.import.unterminatedQuote'], {
194
+ line: error.line,
195
+ })
196
+ : t(M['ui.importExport.import.empty']);
197
+ } else {
198
+ fileError = t(M['ui.importExport.import.readFailed']);
199
+ }
200
+ } finally {
201
+ if (token === readToken) reading = false;
202
+ }
203
+ }
204
+
205
+ function setTarget(index: number, target: string) {
206
+ mapping = setColumnTarget(mapping, index, target === '' ? null : target);
207
+ }
208
+
209
+ function redetect() {
210
+ if (table) mapping = autoMapColumns(table.headers, fields);
211
+ }
212
+
213
+ async function startImport() {
214
+ if (!createRecord || !validation || mappingBlocked) return;
215
+ const records = validation.records;
216
+ runController = new AbortController();
217
+ running = true;
218
+ runResult = null;
219
+ progress = { done: 0, total: records.length };
220
+ try {
221
+ const result = await runImport({
222
+ records,
223
+ createRecord,
224
+ concurrency,
225
+ signal: runController.signal,
226
+ onProgress: (done, total) => {
227
+ progress = { done, total };
228
+ },
229
+ });
230
+ runResult = result;
231
+ onimported?.(result);
232
+ } finally {
233
+ running = false;
234
+ runController = null;
235
+ }
236
+ }
237
+
238
+ function stopImport() {
239
+ runController?.abort();
240
+ }
241
+
242
+ function downloadReport() {
243
+ const issues: ImportIssue[] = [
244
+ ...(validation?.mappingIssues ?? []),
245
+ ...(validation?.issues ?? []),
246
+ ...(runResult?.failed ?? []),
247
+ ];
248
+ deliver(buildErrorReport(issues, issueMessages, 'import-errors'));
249
+ }
250
+
251
+ function issueText(issue: ImportIssue): string {
252
+ const base = issueMessages[issue.code] ?? issue.code;
253
+ return issue.detail ? `${base} (${issue.detail})` : base;
254
+ }
255
+
256
+ function fieldLabel(name: string | undefined): string {
257
+ return (name && fieldByName.get(name)?.label) || name || '';
258
+ }
259
+
260
+ // ---- export ---------------------------------------------------------------
261
+ let selected = $state<string[] | null>(null);
262
+ let format = $state<ExportFormat>('csv');
263
+ let includeHeader = $state(true);
264
+ let headerStyle = $state<'name' | 'label'>('name');
265
+ let exporting = $state(false);
266
+ let exportMessage = $state<{ kind: 'success' | 'error'; text: string } | null>(
267
+ null,
268
+ );
269
+
270
+ // Until the user touches the list, every exportable column is selected, and a
271
+ // fields prop change keeps following that default.
272
+ const selectedColumns = $derived(selected ?? exportable.map((f) => f.name));
273
+
274
+ function toggleColumn(name: string, on: boolean) {
275
+ const current = new Set(selectedColumns);
276
+ if (on) current.add(name);
277
+ else current.delete(name);
278
+ selected = exportable.map((f) => f.name).filter((n) => current.has(n));
279
+ }
280
+
281
+ async function startExport() {
282
+ if (!loadRows || selectedColumns.length === 0) return;
283
+ exporting = true;
284
+ exportMessage = null;
285
+ try {
286
+ const rows = await loadRows({});
287
+ const file = buildExportFile({
288
+ rows,
289
+ fields,
290
+ columns: selectedColumns,
291
+ format,
292
+ includeHeader,
293
+ headerStyle,
294
+ filename,
295
+ });
296
+ deliver(file);
297
+ exportMessage = {
298
+ kind: 'success',
299
+ text: t(M['ui.importExport.export.done'], {
300
+ rows: file.rowCount,
301
+ columns: file.columnCount,
302
+ filename: file.filename,
303
+ }),
304
+ };
305
+ } catch (error) {
306
+ const limit = (error as { maxRows?: number } | null)?.maxRows;
307
+ exportMessage = {
308
+ kind: 'error',
309
+ text:
310
+ typeof limit === 'number'
311
+ ? t(M['ui.importExport.export.limit'], { limit })
312
+ : t(M['ui.importExport.export.failed'], {
313
+ reason: error instanceof Error ? error.message : String(error),
314
+ }),
315
+ };
316
+ } finally {
317
+ exporting = false;
318
+ }
319
+ }
320
+ </script>
321
+
322
+ <section class="smrt-import-export" aria-label={collectionLabel ? `${t(M['ui.importExport.label'])}: ${collectionLabel}` : t(M['ui.importExport.label'])}>
323
+ {#if canImport && canExport}
324
+ <SegmentedControl
325
+ label={t(M['ui.importExport.mode'])}
326
+ options={[
327
+ { value: 'import', label: t(M['ui.importExport.tab.import']) },
328
+ { value: 'export', label: t(M['ui.importExport.tab.export']) },
329
+ ]}
330
+ value={chosenTab}
331
+ onvaluechange={(value) => {
332
+ chosenTab = value === 'export' ? 'export' : 'import';
333
+ }}
334
+ />
335
+ {/if}
336
+
337
+ {#if tab === 'import' && canImport}
338
+ <div class="smrt-import-export__panel">
339
+ <FilePicker
340
+ bind:files
341
+ label={t(M['ui.importExport.import.file'])}
342
+ description={t(M['ui.importExport.import.fileDescription'])}
343
+ accept=".csv,.tsv,.txt,text/csv,text/tab-separated-values,text/plain"
344
+ dropzone
345
+ disabled={running}
346
+ onchangefiles={onFiles}
347
+ />
348
+
349
+ {#if reading}
350
+ <p role="status">{t(M['ui.importExport.import.reading'], { name: fileName })}</p>
351
+ {/if}
352
+ {#if fileError}
353
+ <Alert variant="error">{fileError}</Alert>
354
+ {/if}
355
+
356
+ {#if table && validation}
357
+ <p role="status">
358
+ {t(M['ui.importExport.import.parsed'], {
359
+ name: fileName,
360
+ rows: table.rows.length,
361
+ columns: table.headers.length,
362
+ delimiter: delimiterName(table.delimiter),
363
+ })}
364
+ </p>
365
+
366
+ <Card>
367
+ {#snippet header()}
368
+ <h3>{t(M['ui.importExport.map.heading'])}</h3>
369
+ {/snippet}
370
+ <p>{t(M['ui.importExport.map.help'])}</p>
371
+ <div class="smrt-import-export__scroll">
372
+ <table>
373
+ <thead>
374
+ <tr>
375
+ <th scope="col">{t(M['ui.importExport.map.column'])}</th>
376
+ <th scope="col">{t(M['ui.importExport.map.sample'])}</th>
377
+ <th scope="col">{t(M['ui.importExport.map.target'])}</th>
378
+ </tr>
379
+ </thead>
380
+ <tbody>
381
+ {#each table.headers as header, index (index)}
382
+ <tr>
383
+ <th scope="row">{header || `#${index + 1}`}</th>
384
+ <td>{table.rows[0]?.[index] ?? ''}</td>
385
+ <td>
386
+ <Select
387
+ value={mapping[index] ?? ''}
388
+ disabled={locked}
389
+ aria-label={t(M['ui.importExport.map.select'], { column: header || `#${index + 1}` })}
390
+ onchange={(event) => setTarget(index, event.currentTarget.value)}
391
+ >
392
+ <option value="">{t(M['ui.importExport.map.ignore'])}</option>
393
+ {#each importable as field (field.name)}
394
+ <option value={field.name}>
395
+ {field.required
396
+ ? t(M['ui.importExport.map.required'], { label: field.label })
397
+ : field.label}
398
+ </option>
399
+ {/each}
400
+ </Select>
401
+ </td>
402
+ </tr>
403
+ {/each}
404
+ </tbody>
405
+ </table>
406
+ </div>
407
+ <Button variant="ghost" size="sm" onclick={redetect} disabled={locked}>
408
+ {t(M['ui.importExport.map.reset'])}
409
+ </Button>
410
+ </Card>
411
+
412
+ <Card>
413
+ {#snippet header()}
414
+ <h3>{t(M['ui.importExport.check.heading'])}</h3>
415
+ {/snippet}
416
+ <p role="status">
417
+ {t(M['ui.importExport.check.summary'], {
418
+ valid: readyCount,
419
+ total: validation.totalRows,
420
+ invalid: validation.invalidRows,
421
+ })}
422
+ {t(M['ui.importExport.check.noWrite'])}
423
+ </p>
424
+ {#each validation.mappingIssues as issue, i (i)}
425
+ <Alert variant="warning">
426
+ {fieldLabel(issue.field)}: {issueText(issue)}
427
+ </Alert>
428
+ {/each}
429
+ {#if mappingBlocked}
430
+ <p>{t(M['ui.importExport.check.mappingFixed'])}</p>
431
+ {/if}
432
+
433
+ {#if mappedColumns.length > 0}
434
+ <h4>{t(M['ui.importExport.check.preview'], { count: Math.min(PREVIEW_ROWS, table.rows.length) })}</h4>
435
+ <div class="smrt-import-export__scroll">
436
+ <table>
437
+ <thead>
438
+ <tr>
439
+ <th scope="col">{t(M['ui.importExport.check.line'])}</th>
440
+ {#each mappedColumns as col (col)}
441
+ <th scope="col">{fieldLabel(mapping[col] ?? undefined)}</th>
442
+ {/each}
443
+ <th scope="col">{t(M['ui.importExport.check.status'])}</th>
444
+ </tr>
445
+ </thead>
446
+ <tbody>
447
+ {#each table.rows.slice(0, PREVIEW_ROWS) as row, r (r)}
448
+ {@const line = table.lines[r]}
449
+ <tr>
450
+ <th scope="row">{line}</th>
451
+ {#each mappedColumns as col (col)}
452
+ <td>{row[col] ?? ''}</td>
453
+ {/each}
454
+ <td>
455
+ {#if invalidLines.has(line)}
456
+ <Badge variant="error">{t(M['ui.importExport.check.rowStatus.bad'])}</Badge>
457
+ {:else}
458
+ <Badge variant="success">{t(M['ui.importExport.check.rowStatus.ok'])}</Badge>
459
+ {/if}
460
+ </td>
461
+ </tr>
462
+ {/each}
463
+ </tbody>
464
+ </table>
465
+ </div>
466
+ {/if}
467
+
468
+ {#if rowIssueCap.length > 0}
469
+ <h4>{t(M['ui.importExport.check.problems'])}</h4>
470
+ <div class="smrt-import-export__scroll">
471
+ <table>
472
+ <thead>
473
+ <tr>
474
+ <th scope="col">{t(M['ui.importExport.check.line'])}</th>
475
+ <th scope="col">{t(M['ui.importExport.check.column'])}</th>
476
+ <th scope="col">{t(M['ui.importExport.check.value'])}</th>
477
+ <th scope="col">{t(M['ui.importExport.check.problem'])}</th>
478
+ </tr>
479
+ </thead>
480
+ <tbody>
481
+ {#each rowIssueCap as issue, i (i)}
482
+ <tr>
483
+ <th scope="row">{issue.line}</th>
484
+ <td>{issue.column ?? fieldLabel(issue.field)}</td>
485
+ <td>{issue.value ?? ''}</td>
486
+ <td>{issueText(issue)}</td>
487
+ </tr>
488
+ {/each}
489
+ </tbody>
490
+ </table>
491
+ </div>
492
+ {#if validation.issuesTruncated || validation.issues.length > ISSUE_ROWS}
493
+ <p>{t(M['ui.importExport.check.truncated'])}</p>
494
+ {/if}
495
+ {/if}
496
+
497
+ <div class="smrt-import-export__actions">
498
+ <Button
499
+ onclick={startImport}
500
+ disabled={locked || mappingBlocked || readyCount === 0}
501
+ loading={running}
502
+ >
503
+ {t(M['ui.importExport.run.import'], { count: readyCount })}
504
+ </Button>
505
+ {#if running}
506
+ <Button variant="secondary" onclick={stopImport}>
507
+ {t(M['ui.importExport.run.cancel'])}
508
+ </Button>
509
+ {/if}
510
+ {#if validation.issues.length > 0 || validation.mappingIssues.length > 0}
511
+ <Button variant="secondary" onclick={downloadReport}>
512
+ {t(M['ui.importExport.run.report'])}
513
+ </Button>
514
+ {/if}
515
+ </div>
516
+ {#if !mappingBlocked && readyCount === 0}
517
+ <p>{t(M['ui.importExport.check.nothing'])}</p>
518
+ {/if}
519
+
520
+ {#if running}
521
+ <ProgressBar
522
+ value={progress.done}
523
+ max={Math.max(1, progress.total)}
524
+ label={t(M['ui.importExport.run.progress'], progress)}
525
+ showLabel
526
+ />
527
+ {/if}
528
+ </Card>
529
+
530
+ {#if runResult}
531
+ <Alert variant={runResult.failed.length > 0 || runResult.aborted ? 'warning' : 'success'}>
532
+ <p>
533
+ {t(M['ui.importExport.run.done'], {
534
+ created: runResult.created,
535
+ attempted: runResult.attempted,
536
+ })}
537
+ </p>
538
+ {#if runResult.failed.length > 0}
539
+ <p>{t(M['ui.importExport.run.failed'], { count: runResult.failed.length })}</p>
540
+ {/if}
541
+ {#if runResult.aborted}
542
+ <p>
543
+ {t(M['ui.importExport.run.aborted'], {
544
+ remaining: runResult.attempted < readyCount ? readyCount - runResult.attempted : 0,
545
+ })}
546
+ </p>
547
+ {/if}
548
+ {#snippet action()}
549
+ <Button variant="ghost" size="sm" onclick={resetImport}>
550
+ {t(M['ui.importExport.run.again'])}
551
+ </Button>
552
+ {/snippet}
553
+ </Alert>
554
+ {#if runResult.failed.length > 0}
555
+ <Button variant="secondary" onclick={downloadReport}>
556
+ {t(M['ui.importExport.run.report'])}
557
+ </Button>
558
+ {/if}
559
+ {/if}
560
+ {/if}
561
+ </div>
562
+ {/if}
563
+
564
+ {#if tab === 'export' && canExport}
565
+ <div class="smrt-import-export__panel">
566
+ <Card>
567
+ {#snippet header()}
568
+ <h3>{t(M['ui.importExport.export.heading'])}</h3>
569
+ {/snippet}
570
+ <div class="smrt-import-export__actions">
571
+ <Button variant="ghost" size="sm" onclick={() => (selected = exportable.map((f) => f.name))}>
572
+ {t(M['ui.importExport.export.all'])}
573
+ </Button>
574
+ <Button variant="ghost" size="sm" onclick={() => (selected = [])}>
575
+ {t(M['ui.importExport.export.none'])}
576
+ </Button>
577
+ </div>
578
+ <fieldset class="smrt-import-export__columns">
579
+ <legend>{t(M['ui.importExport.export.columns'])}</legend>
580
+ {#each exportable as field (field.name)}
581
+ <Checkbox
582
+ label={field.label}
583
+ checked={selectedColumns.includes(field.name)}
584
+ disabled={exporting}
585
+ onchange={(event) => toggleColumn(field.name, event.currentTarget.checked)}
586
+ />
587
+ {/each}
588
+ </fieldset>
589
+
590
+ <Select
591
+ value={format}
592
+ disabled={exporting}
593
+ aria-label={t(M['ui.importExport.export.format'])}
594
+ onchange={(event) => (format = event.currentTarget.value === 'tsv' ? 'tsv' : 'csv')}
595
+ >
596
+ <option value="csv">{t(M['ui.importExport.export.formatCsv'])}</option>
597
+ <option value="tsv">{t(M['ui.importExport.export.formatTsv'])}</option>
598
+ </Select>
599
+ <Checkbox
600
+ label={t(M['ui.importExport.export.header'])}
601
+ bind:checked={includeHeader}
602
+ disabled={exporting}
603
+ />
604
+ {#if includeHeader}
605
+ <Select
606
+ value={headerStyle}
607
+ disabled={exporting}
608
+ aria-label={t(M['ui.importExport.export.headerStyle'])}
609
+ onchange={(event) => (headerStyle = event.currentTarget.value === 'label' ? 'label' : 'name')}
610
+ >
611
+ <option value="name">{t(M['ui.importExport.export.headerName'])}</option>
612
+ <option value="label">{t(M['ui.importExport.export.headerLabel'])}</option>
613
+ </Select>
614
+ {/if}
615
+
616
+ <div class="smrt-import-export__actions">
617
+ <Button
618
+ onclick={startExport}
619
+ disabled={exporting || selectedColumns.length === 0}
620
+ loading={exporting}
621
+ >
622
+ {t(M['ui.importExport.export.run'], { count: selectedColumns.length })}
623
+ </Button>
624
+ </div>
625
+ {#if selectedColumns.length === 0}
626
+ <p>{t(M['ui.importExport.export.noColumns'])}</p>
627
+ {/if}
628
+ {#if exporting}
629
+ <p role="status">{t(M['ui.importExport.export.loading'])}</p>
630
+ {/if}
631
+ {#if exportMessage}
632
+ <Alert variant={exportMessage.kind}>{exportMessage.text}</Alert>
633
+ {/if}
634
+ </Card>
635
+ </div>
636
+ {/if}
637
+ </section>
638
+
639
+ <style>
640
+ .smrt-import-export {
641
+ display: flex;
642
+ flex-direction: column;
643
+ gap: var(--smrt-spacing-4);
644
+ }
645
+ .smrt-import-export__panel {
646
+ display: flex;
647
+ flex-direction: column;
648
+ gap: var(--smrt-spacing-4);
649
+ }
650
+ .smrt-import-export__scroll {
651
+ overflow-x: auto;
652
+ }
653
+ .smrt-import-export__scroll table {
654
+ border-collapse: collapse;
655
+ width: 100%;
656
+ }
657
+ .smrt-import-export__scroll th,
658
+ .smrt-import-export__scroll td {
659
+ padding: var(--smrt-spacing-2);
660
+ text-align: start;
661
+ vertical-align: top;
662
+ border-block-end: 1px solid var(--smrt-color-outline-variant, currentColor);
663
+ }
664
+ .smrt-import-export__actions {
665
+ display: flex;
666
+ flex-wrap: wrap;
667
+ gap: var(--smrt-spacing-3);
668
+ align-items: center;
669
+ }
670
+ .smrt-import-export__columns {
671
+ display: grid;
672
+ grid-template-columns: repeat(auto-fill, minmax(14rem, 1fr));
673
+ gap: var(--smrt-spacing-2);
674
+ border: 0;
675
+ padding: 0;
676
+ margin: 0;
677
+ }
678
+ </style>
@@ -0,0 +1,5 @@
1
+ import type { ImportExportProps } from './props.js';
2
+ declare const ImportExport: import("svelte").Component<ImportExportProps, {}, "">;
3
+ type ImportExport = ReturnType<typeof ImportExport>;
4
+ export default ImportExport;
5
+ //# sourceMappingURL=ImportExport.svelte.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ImportExport.svelte.d.ts","sourceRoot":"","sources":["../../../src/components/import-export/ImportExport.svelte.ts"],"names":[],"mappings":"AAkBA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAilBpD,QAAA,MAAM,YAAY,uDAAwC,CAAC;AAC3D,KAAK,YAAY,GAAG,UAAU,CAAC,OAAO,YAAY,CAAC,CAAC;AACpD,eAAe,YAAY,CAAC"}