@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,220 @@
1
+ <script lang="ts">
2
+ /**
3
+ * DetailScreen - a read-only record view for any model, derived from its
4
+ * manifest definition and resolved field policy (#3718).
5
+ *
6
+ * Basic-tier fields show first, grouped by the policy/manifest `group`;
7
+ * advanced-tier fields and the read-only created/updated timestamps sit
8
+ * behind a "More details" disclosure. Hidden fields and fields outside the
9
+ * policy never render, so a sensitive field the policy omits cannot leak
10
+ * through this screen.
11
+ */
12
+ import { Alert, ConfirmDialog } from '@happyvertical/smrt-ui/feedback';
13
+ import { useI18n } from '@happyvertical/smrt-ui/i18n';
14
+ import { PageHeader } from '@happyvertical/smrt-ui/layout';
15
+ import { Button, Disclosure } from '@happyvertical/smrt-ui/ui';
16
+ import { M } from '../../i18n/strings.screens.js';
17
+ import {
18
+ deriveScreenFields,
19
+ groupScreenFields,
20
+ screenSourceError,
21
+ screenTitles,
22
+ } from './fields.js';
23
+ import type {
24
+ DetailScreenProps,
25
+ ScreenCollectionDefinition,
26
+ ScreenField,
27
+ ScreenPolicy,
28
+ ScreenRecord,
29
+ } from './types.js';
30
+ import { formatScreenValue } from './values.js';
31
+
32
+ let {
33
+ definition,
34
+ policy = null,
35
+ record,
36
+ title,
37
+ fields: include,
38
+ currency,
39
+ locale,
40
+ showHeader = true,
41
+ backLabel,
42
+ deleting = false,
43
+ onback,
44
+ onedit,
45
+ ondelete,
46
+ extraActions,
47
+ children,
48
+ }: DetailScreenProps = $props();
49
+
50
+ const { t } = useI18n();
51
+
52
+ const titles = $derived(screenTitles(definition));
53
+ const sourceError = $derived(screenSourceError(definition, policy));
54
+
55
+ const allFields = $derived(
56
+ sourceError
57
+ ? []
58
+ : deriveScreenFields(definition, policy, { mode: 'view', include }),
59
+ );
60
+ const primary = $derived(allFields.filter((f) => f.tier === 'basic'));
61
+ const secondary = $derived(allFields.filter((f) => f.tier === 'advanced'));
62
+
63
+ const heading = $derived.by(() => {
64
+ if (title) return title;
65
+ const label = allFields.find((f) => f.kind === 'text' && f.tier === 'basic');
66
+ const value = label ? record[label.name] : undefined;
67
+ return typeof value === 'string' && value.trim() !== ''
68
+ ? value
69
+ : titles.singular;
70
+ });
71
+
72
+ const formatContext = $derived({
73
+ currency,
74
+ locale,
75
+ yes: t(M['ui.screens.yes']),
76
+ no: t(M['ui.screens.no']),
77
+ });
78
+
79
+ function display(field: ScreenField): string {
80
+ return formatScreenValue(field, record[field.name], formatContext);
81
+ }
82
+
83
+ /** Only http(s) URLs become links; anything else renders as text. */
84
+ function safeHref(field: ScreenField, text: string): string | null {
85
+ if (field.kind === 'email') return `mailto:${text}`;
86
+ if (field.kind === 'url' && /^https?:\/\//i.test(text)) return text;
87
+ return null;
88
+ }
89
+
90
+ let confirmOpen = $state(false);
91
+ let deleteError = $state(false);
92
+
93
+ async function confirmDelete(): Promise<void> {
94
+ deleteError = false;
95
+ try {
96
+ await ondelete?.();
97
+ confirmOpen = false;
98
+ } catch {
99
+ deleteError = true;
100
+ confirmOpen = false;
101
+ }
102
+ }
103
+ </script>
104
+
105
+ {#snippet fieldList(list: ScreenField[])}
106
+ {#each groupScreenFields(list) as [group, groupFields] (group ?? '')}
107
+ <section class="smrt-detail-screen__group">
108
+ {#if group}<h2 class="smrt-detail-screen__group-title">{group}</h2>{/if}
109
+ <dl class="smrt-detail-screen__fields">
110
+ {#each groupFields as field (field.name)}
111
+ {@const text = display(field)}
112
+ <div class="smrt-detail-screen__field">
113
+ <dt>{field.label}</dt>
114
+ <dd>
115
+ {#if text === ''}
116
+ <span class="smrt-detail-screen__empty">{t(M['ui.screens.not_set'])}</span>
117
+ {:else if field.kind === 'json' || field.kind === 'textarea'}
118
+ <pre class="smrt-detail-screen__block">{text}</pre>
119
+ {:else if safeHref(field, text)}
120
+ <a href={safeHref(field, text)}>{text}</a>
121
+ {:else if field.kind === 'reference'}
122
+ <code>{text}</code>
123
+ {:else}
124
+ {text}
125
+ {/if}
126
+ </dd>
127
+ </div>
128
+ {/each}
129
+ </dl>
130
+ </section>
131
+ {/each}
132
+ {/snippet}
133
+
134
+ {#if showHeader}
135
+ <PageHeader title={heading}>
136
+ {#snippet actions()}
137
+ {#if onback}
138
+ <Button variant="ghost" onclick={onback}>
139
+ {backLabel ?? t(M['ui.screens.back'], { name: titles.plural.toLowerCase() })}
140
+ </Button>
141
+ {/if}
142
+ {#if extraActions}{@render extraActions()}{/if}
143
+ {#if onedit}
144
+ <Button variant="secondary" onclick={onedit}>{t(M['ui.screens.edit'])}</Button>
145
+ {/if}
146
+ {#if ondelete}
147
+ <Button variant="danger" onclick={() => (confirmOpen = true)}>
148
+ {t(M['ui.screens.delete'])}
149
+ </Button>
150
+ {/if}
151
+ {/snippet}
152
+ </PageHeader>
153
+ {/if}
154
+
155
+ <article class="smrt-detail-screen" aria-label={heading}>
156
+ {#if sourceError}
157
+ <Alert variant="error">{sourceError}</Alert>
158
+ {:else}
159
+ {#if deleteError}
160
+ <Alert variant="error" dismissible ondismiss={() => (deleteError = false)}>
161
+ {t(M['ui.screens.delete_failed'])}
162
+ </Alert>
163
+ {/if}
164
+ {@render fieldList(primary)}
165
+ {#if secondary.length > 0}
166
+ <Disclosure title={t(M['ui.screens.more_details'])}>
167
+ {@render fieldList(secondary)}
168
+ </Disclosure>
169
+ {/if}
170
+ {@render children?.()}
171
+ {/if}
172
+ </article>
173
+
174
+ {#if ondelete}
175
+ <ConfirmDialog
176
+ open={confirmOpen}
177
+ title={t(M['ui.screens.delete_title'], { name: titles.singular.toLowerCase() })}
178
+ message={t(M['ui.screens.delete_message'])}
179
+ confirmLabel={t(M['ui.screens.delete'])}
180
+ cancelLabel={t(M['ui.screens.cancel'])}
181
+ destructive
182
+ loading={deleting}
183
+ onconfirm={confirmDelete}
184
+ oncancel={() => (confirmOpen = false)}
185
+ />
186
+ {/if}
187
+
188
+ <style>
189
+ .smrt-detail-screen {
190
+ display: flex;
191
+ flex-direction: column;
192
+ gap: var(--smrt-spacing-lg, 1.5rem);
193
+ }
194
+ .smrt-detail-screen__group-title {
195
+ margin: 0 0 var(--smrt-spacing-sm, 0.5rem);
196
+ font-size: var(--smrt-typography-title-medium-size, 1rem);
197
+ }
198
+ .smrt-detail-screen__fields {
199
+ display: grid;
200
+ grid-template-columns: repeat(auto-fill, minmax(14rem, 1fr));
201
+ gap: var(--smrt-spacing-md, 1rem);
202
+ margin: 0;
203
+ }
204
+ .smrt-detail-screen__field dt {
205
+ color: var(--smrt-color-on-surface-variant, #5f6368);
206
+ font-size: var(--smrt-typography-body-medium-size, 0.875rem);
207
+ }
208
+ .smrt-detail-screen__field dd {
209
+ margin: 0;
210
+ overflow-wrap: anywhere;
211
+ }
212
+ .smrt-detail-screen__empty {
213
+ color: var(--smrt-color-on-surface-variant, #5f6368);
214
+ }
215
+ .smrt-detail-screen__block {
216
+ margin: 0;
217
+ white-space: pre-wrap;
218
+ font-family: inherit;
219
+ }
220
+ </style>
@@ -0,0 +1,5 @@
1
+ import type { DetailScreenProps } from './types.js';
2
+ declare const DetailScreen: import("svelte").Component<DetailScreenProps, {}, "">;
3
+ type DetailScreen = ReturnType<typeof DetailScreen>;
4
+ export default DetailScreen;
5
+ //# sourceMappingURL=DetailScreen.svelte.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"DetailScreen.svelte.d.ts","sourceRoot":"","sources":["../../../src/components/screens/DetailScreen.svelte.ts"],"names":[],"mappings":"AAwBA,OAAO,KAAK,EACV,iBAAiB,EAKlB,MAAM,YAAY,CAAC;AAoKpB,QAAA,MAAM,YAAY,uDAAwC,CAAC;AAC3D,KAAK,YAAY,GAAG,UAAU,CAAC,OAAO,YAAY,CAAC,CAAC;AACpD,eAAe,YAAY,CAAC"}
@@ -0,0 +1,313 @@
1
+ <script lang="ts">
2
+ /**
3
+ * EditForm - a create / edit form for any model, derived from its manifest
4
+ * definition and resolved field policy (#3718).
5
+ *
6
+ * Policy behavior: basic-tier fields render up front and advanced-tier fields
7
+ * sit behind an "Advanced fields" disclosure (opened automatically when one
8
+ * has a problem); hidden fields and fields outside the policy never render;
9
+ * policy labels, help and order win over the manifest; on create, resolved
10
+ * policy defaults prefill the draft. System fields are never editable.
11
+ *
12
+ * The form is transport-neutral. `onsubmit` receives a payload already
13
+ * converted to wire values (safe integers, integer minor units for money,
14
+ * ISO datetimes, parsed JSON); throw to report a failed save, or return
15
+ * `{ fieldErrors }` to attach server-side validation messages to fields.
16
+ * Remount with `{#key}` when switching to another record.
17
+ *
18
+ * For the policy gear, usage telemetry and per-field renderer registry use
19
+ * `ObjectForm` from `@happyvertical/smrt-fields/svelte` instead.
20
+ */
21
+ import { Alert } from '@happyvertical/smrt-ui/feedback';
22
+ import {
23
+ Checkbox,
24
+ Form,
25
+ FormActionBar,
26
+ FormGroup,
27
+ Input,
28
+ Textarea,
29
+ } from '@happyvertical/smrt-ui/forms';
30
+ import { useI18n } from '@happyvertical/smrt-ui/i18n';
31
+ import { PageHeader } from '@happyvertical/smrt-ui/layout';
32
+ import { Button, Disclosure } from '@happyvertical/smrt-ui/ui';
33
+ import { untrack } from 'svelte';
34
+ import { M } from '../../i18n/strings.screens.js';
35
+ import {
36
+ deriveScreenFields,
37
+ groupScreenFields,
38
+ screenSourceError,
39
+ screenTitles,
40
+ } from './fields.js';
41
+ import type {
42
+ EditFormProps,
43
+ ScreenCollectionDefinition,
44
+ ScreenDraft,
45
+ ScreenField,
46
+ ScreenFieldErrorCode,
47
+ ScreenPolicy,
48
+ ScreenRecord,
49
+ } from './types.js';
50
+ import {
51
+ DEFAULT_SCREEN_CURRENCY,
52
+ draftForCreate,
53
+ draftFromRecord,
54
+ parseDraft,
55
+ } from './values.js';
56
+
57
+ let {
58
+ definition,
59
+ policy = null,
60
+ record,
61
+ title,
62
+ fields: include,
63
+ currency = DEFAULT_SCREEN_CURRENCY,
64
+ showHeader = true,
65
+ submitting = false,
66
+ fieldErrors = {},
67
+ error = null,
68
+ onsubmit,
69
+ oncancel,
70
+ }: EditFormProps = $props();
71
+
72
+ const { t } = useI18n();
73
+
74
+ const isNew = $derived(record === undefined);
75
+ const titles = $derived(screenTitles(definition));
76
+ const sourceError = $derived(screenSourceError(definition, policy));
77
+ const heading = $derived(
78
+ title ??
79
+ t(M[isNew ? 'ui.screens.create_title' : 'ui.screens.edit_title'], {
80
+ name: titles.singular.toLowerCase(),
81
+ }),
82
+ );
83
+
84
+ const allFields = $derived(
85
+ sourceError
86
+ ? []
87
+ : deriveScreenFields(definition, policy, { mode: 'edit', include }),
88
+ );
89
+ const basicFields = $derived(allFields.filter((f) => f.tier === 'basic'));
90
+ const advancedFields = $derived(allFields.filter((f) => f.tier === 'advanced'));
91
+
92
+ function initialDraft(): ScreenDraft {
93
+ return record
94
+ ? draftFromRecord(allFields, record, { currency })
95
+ : draftForCreate(allFields, policy, { currency });
96
+ }
97
+
98
+ let draft = $state<ScreenDraft>(initialDraft());
99
+ let localErrors = $state<Record<string, ScreenFieldErrorCode>>({});
100
+ let hostErrors = $state<Record<string, string>>({});
101
+ let failed = $state(false);
102
+ let working = $state(false);
103
+ let advancedOpen = $state(false);
104
+
105
+ // Re-seed when the host swaps the record (or the field set) under a mounted
106
+ // form; typing never re-seeds because only the identity is tracked.
107
+ const sessionKey = $derived(
108
+ `${definition.objectRef}:${record ? String(record[definition.idField ?? 'id']) : 'new'}:${allFields.map((f) => f.name).join(',')}`,
109
+ );
110
+ let appliedKey = untrack(() => sessionKey);
111
+ $effect(() => {
112
+ const key = sessionKey;
113
+ if (key === appliedKey) return;
114
+ appliedKey = key;
115
+ untrack(() => {
116
+ draft = initialDraft();
117
+ localErrors = {};
118
+ hostErrors = {};
119
+ failed = false;
120
+ });
121
+ });
122
+
123
+ function text(name: string): string {
124
+ const value = draft[name];
125
+ return typeof value === 'string' ? value : '';
126
+ }
127
+
128
+ function setText(name: string, value: string | number | undefined): void {
129
+ draft[name] = String(value ?? '');
130
+ }
131
+
132
+ function messageFor(field: ScreenField): string | undefined {
133
+ const code = localErrors[field.name];
134
+ if (code) return t(M[`ui.screens.error.${code}`]);
135
+ return fieldErrors[field.name] ?? hostErrors[field.name];
136
+ }
137
+
138
+ const advancedHasProblem = $derived(
139
+ advancedFields.some(
140
+ (f) => localErrors[f.name] || fieldErrors[f.name] || hostErrors[f.name],
141
+ ),
142
+ );
143
+
144
+ function hint(field: ScreenField): string | undefined {
145
+ return field.help ?? undefined;
146
+ }
147
+
148
+ function label(field: ScreenField): string {
149
+ return field.kind === 'money' ? `${field.label} (${currency})` : field.label;
150
+ }
151
+
152
+ async function submit(): Promise<void> {
153
+ if (working || submitting) return;
154
+ failed = false;
155
+ hostErrors = {};
156
+ const parsed = parseDraft(allFields, draft, { currency, record });
157
+ localErrors = parsed.errors;
158
+ if (Object.keys(parsed.errors).length > 0) {
159
+ if (advancedFields.some((f) => parsed.errors[f.name])) advancedOpen = true;
160
+ return;
161
+ }
162
+ working = true;
163
+ try {
164
+ const result = await onsubmit(parsed.values, { isNew });
165
+ if (result?.fieldErrors) {
166
+ hostErrors = { ...result.fieldErrors };
167
+ if (advancedFields.some((f) => result.fieldErrors?.[f.name])) {
168
+ advancedOpen = true;
169
+ }
170
+ }
171
+ } catch {
172
+ failed = true;
173
+ } finally {
174
+ working = false;
175
+ }
176
+ }
177
+
178
+ const busy = $derived(working || submitting);
179
+ const formError = $derived(
180
+ error ?? (failed ? t(M['ui.screens.save_failed']) : null),
181
+ );
182
+ </script>
183
+
184
+ {#snippet control(field: ScreenField)}
185
+ {#if field.kind === 'boolean'}
186
+ <div class="smrt-edit-form__check">
187
+ <Checkbox
188
+ name={field.name}
189
+ label={field.label}
190
+ disabled={busy}
191
+ bind:checked={() => draft[field.name] === true, (v) => (draft[field.name] = v)}
192
+ />
193
+ {#if field.help}
194
+ <small class="smrt-edit-form__hint">{field.help}</small>
195
+ {/if}
196
+ {#if messageFor(field)}
197
+ <small class="smrt-edit-form__error" role="alert">{messageFor(field)}</small>
198
+ {/if}
199
+ </div>
200
+ {:else}
201
+ <FormGroup
202
+ label={label(field)}
203
+ hint={hint(field)}
204
+ error={messageFor(field)}
205
+ required={field.required}
206
+ >
207
+ {#if field.kind === 'textarea' || field.kind === 'json'}
208
+ <Textarea
209
+ name={field.name}
210
+ rows={field.kind === 'json' ? 8 : 4}
211
+ disabled={busy}
212
+ required={field.required}
213
+ bind:value={() => text(field.name), (v) => setText(field.name, v)}
214
+ />
215
+ {:else}
216
+ <Input
217
+ name={field.name}
218
+ type={field.kind === 'email'
219
+ ? 'email'
220
+ : field.kind === 'url'
221
+ ? 'url'
222
+ : field.kind === 'tel'
223
+ ? 'tel'
224
+ : field.kind === 'integer' || field.kind === 'decimal'
225
+ ? 'number'
226
+ : field.kind === 'datetime'
227
+ ? 'datetime-local'
228
+ : 'text'}
229
+ step={field.kind === 'integer' ? '1' : field.kind === 'decimal' ? 'any' : undefined}
230
+ inputmode={field.kind === 'money' ? 'decimal' : undefined}
231
+ disabled={busy}
232
+ required={field.required}
233
+ bind:value={() => text(field.name), (v) => setText(field.name, v)}
234
+ />
235
+ {/if}
236
+ </FormGroup>
237
+ {/if}
238
+ {/snippet}
239
+
240
+ {#snippet fieldList(list: ScreenField[])}
241
+ {#each groupScreenFields(list) as [group, groupFields] (group ?? '')}
242
+ <fieldset class="smrt-edit-form__group">
243
+ {#if group}<legend>{group}</legend>{/if}
244
+ {#each groupFields as field (field.name)}
245
+ {@render control(field)}
246
+ {/each}
247
+ </fieldset>
248
+ {/each}
249
+ {/snippet}
250
+
251
+ {#if showHeader}
252
+ <PageHeader title={heading} />
253
+ {/if}
254
+
255
+ <section class="smrt-edit-form" aria-label={heading}>
256
+ {#if sourceError}
257
+ <Alert variant="error">{sourceError}</Alert>
258
+ {:else}
259
+ <Form onsubmit={submit} novalidate>
260
+ {#if formError}
261
+ <Alert variant="error">{formError}</Alert>
262
+ {/if}
263
+ {@render fieldList(basicFields)}
264
+ {#if advancedFields.length > 0}
265
+ <Disclosure
266
+ title={t(M['ui.screens.advanced_fields'])}
267
+ bind:open={() => advancedOpen || advancedHasProblem, (v) => (advancedOpen = v)}
268
+ >
269
+ {@render fieldList(advancedFields)}
270
+ </Disclosure>
271
+ {/if}
272
+ <FormActionBar>
273
+ {#if oncancel}
274
+ <Button type="button" variant="ghost" disabled={busy} onclick={oncancel}>
275
+ {t(M['ui.screens.cancel'])}
276
+ </Button>
277
+ {/if}
278
+ <Button type="submit" variant="primary" loading={busy} disabled={busy}>
279
+ {t(M['ui.screens.save'])}
280
+ </Button>
281
+ </FormActionBar>
282
+ </Form>
283
+ {/if}
284
+ </section>
285
+
286
+ <style>
287
+ .smrt-edit-form {
288
+ max-width: 40rem;
289
+ }
290
+ .smrt-edit-form__group {
291
+ border: 0;
292
+ margin: 0 0 var(--smrt-spacing-md, 1rem);
293
+ padding: 0;
294
+ display: flex;
295
+ flex-direction: column;
296
+ gap: var(--smrt-spacing-md, 1rem);
297
+ }
298
+ .smrt-edit-form__group legend {
299
+ font-weight: var(--smrt-typography-weight-semibold, 600);
300
+ margin-bottom: var(--smrt-spacing-sm, 0.5rem);
301
+ }
302
+ .smrt-edit-form__check {
303
+ display: flex;
304
+ flex-direction: column;
305
+ gap: var(--smrt-spacing-xs, 0.25rem);
306
+ }
307
+ .smrt-edit-form__hint {
308
+ color: var(--smrt-color-on-surface-variant, #5f6368);
309
+ }
310
+ .smrt-edit-form__error {
311
+ color: var(--smrt-color-error, #b42318);
312
+ }
313
+ </style>
@@ -0,0 +1,5 @@
1
+ import type { EditFormProps } from './types.js';
2
+ declare const EditForm: import("svelte").Component<EditFormProps, {}, "">;
3
+ type EditForm = ReturnType<typeof EditForm>;
4
+ export default EditForm;
5
+ //# sourceMappingURL=EditForm.svelte.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"EditForm.svelte.d.ts","sourceRoot":"","sources":["../../../src/components/screens/EditForm.svelte.ts"],"names":[],"mappings":"AA0CA,OAAO,KAAK,EACV,aAAa,EAOd,MAAM,YAAY,CAAC;AAmOpB,QAAA,MAAM,QAAQ,mDAAwC,CAAC;AACvD,KAAK,QAAQ,GAAG,UAAU,CAAC,OAAO,QAAQ,CAAC,CAAC;AAC5C,eAAe,QAAQ,CAAC"}