@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,289 @@
1
+ /**
2
+ * Pure value handling for the manifest-derived record screens (#3718):
3
+ * draft <-> payload conversion for edit forms and display formatting for list
4
+ * and view screens. No DOM and no i18n: components map error codes and the
5
+ * Yes/No labels through `useI18n`.
6
+ *
7
+ * Money is integer minor units end to end. Editing shows major units, but the
8
+ * conversion is exact string math (never `* 100` on a float), and anything
9
+ * that is not a JavaScript-safe integer is rejected rather than rounded.
10
+ */
11
+ import { ISO_4217_MINOR_UNITS } from '@happyvertical/smrt-ui/currency';
12
+ /** Currency used for money fields when the screen is not told otherwise. */
13
+ export const DEFAULT_SCREEN_CURRENCY = 'USD';
14
+ /** Decimal places of a currency's minor unit (2 for an unknown code). */
15
+ export function currencyMinorDigits(currency) {
16
+ return ISO_4217_MINOR_UNITS.get(currency.trim().toUpperCase()) ?? 2;
17
+ }
18
+ /** `1999`, 2 digits -> `19.99`. Exact; `null` for a non-safe integer. */
19
+ export function minorUnitsToMajorString(minor, digits) {
20
+ if (typeof minor !== 'number' || !Number.isSafeInteger(minor))
21
+ return null;
22
+ const negative = minor < 0;
23
+ const absolute = String(Math.abs(minor));
24
+ let text;
25
+ if (digits <= 0) {
26
+ text = absolute;
27
+ }
28
+ else {
29
+ const padded = absolute.padStart(digits + 1, '0');
30
+ text = `${padded.slice(0, -digits)}.${padded.slice(-digits)}`;
31
+ }
32
+ return negative ? `-${text}` : text;
33
+ }
34
+ /**
35
+ * `19.99`, 2 digits -> `1999`. Accepts a leading sign and `,` grouping;
36
+ * rejects more fraction digits than the currency has and non-safe integers.
37
+ */
38
+ export function majorStringToMinorUnits(text, digits) {
39
+ const cleaned = text.trim().replace(/[,\s]/g, '');
40
+ const pattern = digits > 0 ? /^(-?)(\d+)(?:\.(\d*))?$/ : /^(-?)(\d+)$/;
41
+ const match = pattern.exec(cleaned);
42
+ if (!match)
43
+ return null;
44
+ const [, sign, whole, fraction = ''] = match;
45
+ if (fraction.length > Math.max(0, digits))
46
+ return null;
47
+ const minor = Number(`${whole}${fraction.padEnd(Math.max(0, digits), '0')}`);
48
+ if (!Number.isSafeInteger(minor))
49
+ return null;
50
+ return sign === '-' && minor !== 0 ? -minor : minor;
51
+ }
52
+ function pad(value) {
53
+ return String(value).padStart(2, '0');
54
+ }
55
+ /** A record datetime as a `datetime-local` input value (local time). */
56
+ export function toDatetimeLocal(value) {
57
+ if (value === null || value === undefined || value === '')
58
+ return '';
59
+ const date = value instanceof Date ? value : new Date(value);
60
+ if (Number.isNaN(date.getTime()))
61
+ return '';
62
+ return `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())}T${pad(date.getHours())}:${pad(date.getMinutes())}`;
63
+ }
64
+ /** One field's value as the draft representation its control edits. */
65
+ export function toDraftValue(field, value, context = {}) {
66
+ if (field.kind === 'boolean')
67
+ return value === true || value === 'true';
68
+ if (value === null || value === undefined)
69
+ return '';
70
+ switch (field.kind) {
71
+ case 'money':
72
+ return (minorUnitsToMajorString(value, currencyMinorDigits(context.currency ?? DEFAULT_SCREEN_CURRENCY)) ?? '');
73
+ case 'datetime':
74
+ return toDatetimeLocal(value);
75
+ case 'json':
76
+ return typeof value === 'string' ? value : JSON.stringify(value, null, 2);
77
+ default:
78
+ return String(value);
79
+ }
80
+ }
81
+ /** Draft for editing an existing record. */
82
+ export function draftFromRecord(fields, record, context = {}) {
83
+ const draft = {};
84
+ for (const field of fields) {
85
+ draft[field.name] = toDraftValue(field, record[field.name], context);
86
+ }
87
+ return draft;
88
+ }
89
+ /**
90
+ * Draft for a new record: the resolved policy default when one resolved
91
+ * (an explicit `null` default included), else the manifest default.
92
+ */
93
+ export function draftForCreate(fields, policy, context = {}) {
94
+ const draft = {};
95
+ for (const field of fields) {
96
+ const policyField = policy?.fields[field.name];
97
+ const seeded = policyField?.hasDefault === true
98
+ ? policyField.defaultValue
99
+ : field.definition.default;
100
+ draft[field.name] = toDraftValue(field, seeded, context);
101
+ }
102
+ return draft;
103
+ }
104
+ /**
105
+ * Convert a draft into a write payload. An empty optional text field becomes
106
+ * `null` when the field is nullable and `''` otherwise; every other empty
107
+ * optional field becomes `null`. A required empty field is an error.
108
+ */
109
+ export function parseDraft(fields, draft, context = {}) {
110
+ const values = {};
111
+ const errors = {};
112
+ const digits = currencyMinorDigits(context.currency ?? DEFAULT_SCREEN_CURRENCY);
113
+ for (const field of fields) {
114
+ const raw = draft[field.name];
115
+ if (field.kind === 'boolean') {
116
+ values[field.name] = raw === true || raw === 'true';
117
+ continue;
118
+ }
119
+ const text = typeof raw === 'string' ? raw : '';
120
+ const trimmed = text.trim();
121
+ if (trimmed === '') {
122
+ if (field.required) {
123
+ errors[field.name] = 'required';
124
+ }
125
+ else if ((field.kind === 'text' ||
126
+ field.kind === 'textarea' ||
127
+ field.kind === 'email' ||
128
+ field.kind === 'url' ||
129
+ field.kind === 'tel') &&
130
+ field.definition.nullable !== true) {
131
+ values[field.name] = '';
132
+ }
133
+ else {
134
+ values[field.name] = null;
135
+ }
136
+ continue;
137
+ }
138
+ switch (field.kind) {
139
+ case 'integer': {
140
+ const parsed = /^-?\d+$/.test(trimmed) ? Number(trimmed) : Number.NaN;
141
+ if (Number.isSafeInteger(parsed))
142
+ values[field.name] = parsed;
143
+ else
144
+ errors[field.name] = 'invalid_integer';
145
+ break;
146
+ }
147
+ case 'decimal': {
148
+ const parsed = Number(trimmed);
149
+ if (Number.isFinite(parsed))
150
+ values[field.name] = parsed;
151
+ else
152
+ errors[field.name] = 'invalid_decimal';
153
+ break;
154
+ }
155
+ case 'money': {
156
+ const minor = majorStringToMinorUnits(trimmed, digits);
157
+ if (minor === null)
158
+ errors[field.name] = 'invalid_money';
159
+ else
160
+ values[field.name] = minor;
161
+ break;
162
+ }
163
+ case 'datetime': {
164
+ const original = context.record?.[field.name];
165
+ const originalDate = original === null || original === undefined || original === ''
166
+ ? null
167
+ : original instanceof Date
168
+ ? original
169
+ : new Date(original);
170
+ if (originalDate &&
171
+ !Number.isNaN(originalDate.getTime()) &&
172
+ trimmed === toDatetimeLocal(originalDate)) {
173
+ // Unchanged at the control's precision: keep the full-precision
174
+ // original instead of truncating to the minute.
175
+ values[field.name] = originalDate.toISOString();
176
+ break;
177
+ }
178
+ const date = new Date(trimmed);
179
+ if (Number.isNaN(date.getTime()))
180
+ errors[field.name] = 'invalid_datetime';
181
+ else
182
+ values[field.name] = date.toISOString();
183
+ break;
184
+ }
185
+ case 'json': {
186
+ try {
187
+ values[field.name] = JSON.parse(trimmed);
188
+ }
189
+ catch {
190
+ errors[field.name] = 'invalid_json';
191
+ }
192
+ break;
193
+ }
194
+ case 'reference':
195
+ values[field.name] = trimmed;
196
+ break;
197
+ default:
198
+ // Free text keeps the user's whitespace.
199
+ values[field.name] = text;
200
+ }
201
+ }
202
+ return { values, errors };
203
+ }
204
+ /** A record value as display text for a list cell or a view row. */
205
+ export function formatScreenValue(field, value, context = {}) {
206
+ if (field.kind === 'boolean') {
207
+ if (value === null || value === undefined)
208
+ return '';
209
+ return value === true || value === 'true'
210
+ ? (context.yes ?? 'Yes')
211
+ : (context.no ?? 'No');
212
+ }
213
+ if (value === null || value === undefined || value === '')
214
+ return '';
215
+ try {
216
+ switch (field.kind) {
217
+ case 'integer':
218
+ return typeof value === 'number'
219
+ ? new Intl.NumberFormat(context.locale, {
220
+ maximumFractionDigits: 0,
221
+ }).format(value)
222
+ : String(value);
223
+ case 'decimal':
224
+ return typeof value === 'number'
225
+ ? new Intl.NumberFormat(context.locale, {
226
+ maximumFractionDigits: 6,
227
+ }).format(value)
228
+ : String(value);
229
+ case 'money': {
230
+ const currency = (context.currency ?? DEFAULT_SCREEN_CURRENCY)
231
+ .trim()
232
+ .toUpperCase();
233
+ const digits = currencyMinorDigits(currency);
234
+ if (typeof value !== 'number' || !Number.isSafeInteger(value)) {
235
+ return String(value);
236
+ }
237
+ return new Intl.NumberFormat(context.locale, {
238
+ style: 'currency',
239
+ currency,
240
+ }).format(value / 10 ** digits);
241
+ }
242
+ case 'datetime': {
243
+ const date = value instanceof Date ? value : new Date(value);
244
+ if (Number.isNaN(date.getTime()))
245
+ return String(value);
246
+ return new Intl.DateTimeFormat(context.locale, {
247
+ dateStyle: 'medium',
248
+ timeStyle: 'short',
249
+ ...(context.timeZone ? { timeZone: context.timeZone } : {}),
250
+ }).format(date);
251
+ }
252
+ case 'json':
253
+ return typeof value === 'string' ? value : JSON.stringify(value);
254
+ default:
255
+ return String(value);
256
+ }
257
+ }
258
+ catch {
259
+ // An unsupported currency code or locale must not break a row render.
260
+ return String(value);
261
+ }
262
+ }
263
+ /**
264
+ * Order two record values for a list column: empty values last (whichever
265
+ * way the column sorts), numbers numerically, everything else as text.
266
+ */
267
+ export function compareScreenValues(left, right, direction) {
268
+ if (!direction)
269
+ return 0;
270
+ const leftEmpty = left === null || left === undefined || left === '';
271
+ const rightEmpty = right === null || right === undefined || right === '';
272
+ if (leftEmpty && rightEmpty)
273
+ return 0;
274
+ if (leftEmpty)
275
+ return 1;
276
+ if (rightEmpty)
277
+ return -1;
278
+ let result;
279
+ if (typeof left === 'number' && typeof right === 'number') {
280
+ result = left - right;
281
+ }
282
+ else if (typeof left === 'boolean' && typeof right === 'boolean') {
283
+ result = Number(left) - Number(right);
284
+ }
285
+ else {
286
+ result = String(left).localeCompare(String(right));
287
+ }
288
+ return direction === 'asc' ? result : -result;
289
+ }
@@ -1,6 +1,7 @@
1
1
  <script lang="ts" generics="Item extends SortableItem, Container extends SortableContainer">
2
2
  import { useI18n } from '@happyvertical/smrt-ui/i18n';
3
3
  import { M } from '../../i18n/strings.sortable.js';
4
+ import { formatSortableAnnouncement } from './announce.js';
4
5
  import {
5
6
  createSortable,
6
7
  type SortableAnnouncement,
@@ -53,35 +54,7 @@ const containersById = $derived(
53
54
  );
54
55
 
55
56
  function itemMessage(announcement: SortableAnnouncement): string {
56
- switch (announcement.type) {
57
- case 'pickup':
58
- return t(M['ui.sortable.pickup'], {
59
- item: announcement.item,
60
- destinations: announcement.destinations.join(', '),
61
- });
62
- case 'position':
63
- return t(M['ui.sortable.position'], {
64
- item: announcement.item,
65
- container: announcement.container,
66
- position: announcement.position,
67
- count: announcement.count,
68
- });
69
- case 'drop':
70
- return t(M['ui.sortable.drop'], {
71
- item: announcement.item,
72
- container: announcement.container,
73
- position: announcement.position,
74
- count: announcement.count,
75
- });
76
- case 'unavailable':
77
- return t(M['ui.sortable.unavailable'], {
78
- container: announcement.container,
79
- });
80
- case 'failed':
81
- return t(M['ui.sortable.failed'], { item: announcement.item });
82
- case 'cancel':
83
- return t(M['ui.sortable.cancel'], { item: announcement.item });
84
- }
57
+ return formatSortableAnnouncement(t, announcement);
85
58
  }
86
59
 
87
60
  const itemSortable = createSortable({
@@ -338,14 +311,14 @@ function containerRank(id: string): number {
338
311
  </div>
339
312
 
340
313
  <style>
341
- .smrt-sortable { display: grid; gap: var(--smrt-spacing-3); min-width: 0; position: relative; }
342
- .smrt-sortable__containers { display: grid; gap: var(--smrt-spacing-3); }
343
- .smrt-sortable__container { display: grid; gap: var(--smrt-spacing-2); padding: var(--smrt-spacing-3); border: 1px solid var(--smrt-color-outline-variant); border-radius: var(--smrt-radius-md); background: var(--smrt-color-surface-container); min-width: 0; }
314
+ .smrt-sortable { display: grid; grid-template-columns: minmax(0, 1fr); gap: var(--smrt-spacing-3); min-width: 0; position: relative; }
315
+ .smrt-sortable__containers { display: grid; grid-template-columns: minmax(0, 1fr); gap: var(--smrt-spacing-3); min-width: 0; }
316
+ .smrt-sortable__container { display: grid; grid-template-columns: minmax(0, 1fr); gap: var(--smrt-spacing-2); padding: var(--smrt-spacing-3); border: 1px solid var(--smrt-color-outline-variant); border-radius: var(--smrt-radius-md); background: var(--smrt-color-surface-container); min-width: 0; }
344
317
  .smrt-sortable__container--disabled { opacity: 0.6; }
345
318
  .smrt-sortable__container--dragging { opacity: 0.55; }
346
319
  .smrt-sortable__header { display: flex; align-items: center; gap: var(--smrt-spacing-2); min-block-size: 2.25rem; }
347
320
  .smrt-sortable__content { flex: 1 1 auto; min-width: 0; display: flex; align-items: center; gap: var(--smrt-spacing-2); }
348
- .smrt-sortable__items { display: grid; gap: var(--smrt-spacing-1); min-block-size: 2.25rem; }
321
+ .smrt-sortable__items { display: grid; grid-template-columns: minmax(0, 1fr); gap: var(--smrt-spacing-1); min-block-size: 2.25rem; min-width: 0; }
349
322
  .smrt-sortable__item { display: flex; align-items: center; gap: var(--smrt-spacing-2); padding: var(--smrt-spacing-1) var(--smrt-spacing-2); border: 1px solid var(--smrt-color-outline-variant); border-radius: var(--smrt-radius-sm); background: var(--smrt-color-surface); min-width: 0; }
350
323
  .smrt-sortable__item--dragging { opacity: 0.55; }
351
324
  .smrt-sortable__handle { display: inline-grid; place-items: center; flex: 0 0 auto; inline-size: 2rem; block-size: 2rem; padding: 0; border: 0; border-radius: var(--smrt-radius-sm); background: transparent; color: var(--smrt-color-on-surface-variant); cursor: grab; touch-action: none; }
@@ -1 +1 @@
1
- {"version":3,"file":"Sortable.svelte.d.ts","sourceRoot":"","sources":["../../../src/components/sortable/Sortable.svelte.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EACV,iBAAiB,EACjB,YAAY,EACZ,aAAa,EACd,MAAM,YAAY,CAAC;AACpB,iBAAS,QAAQ,CAAC,IAAI,SAAS,YAAY,EAAE,SAAS,SAAS,iBAAiB;WAiRnD,aAAa,CAAC,IAAI,EAAE,SAAS,CAAC;;;;;EAA4E;AACvI,cAAM,iBAAiB,CAAC,IAAI,SAAS,YAAY,EAAC,SAAS,SAAS,iBAAiB;IACjF,KAAK,IAAI,UAAU,CAAC,OAAO,QAAQ,CAAC,IAAI,EAAC,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC;IAC7D,MAAM,IAAI,UAAU,CAAC,OAAO,QAAQ,CAAC,IAAI,EAAC,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC;IAC/D,KAAK,IAAI,UAAU,CAAC,OAAO,QAAQ,CAAC,IAAI,EAAC,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC;IAC7D,QAAQ;IACR,OAAO;CACV;AAED,UAAU,qBAAqB;IAC3B,KAAK,IAAI,SAAS,YAAY,EAAC,SAAS,SAAS,iBAAiB,EAAE,OAAO,EAAE,OAAO,QAAQ,EAAE,2BAA2B,CAAC,UAAU,CAAC,iBAAiB,CAAC,IAAI,EAAC,SAAS,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,QAAQ,EAAE,eAAe,CAAC,UAAU,CAAC,iBAAiB,CAAC,IAAI,EAAC,SAAS,CAAC,CAAC,OAAO,CAAC,CAAC,EAAE,UAAU,CAAC,iBAAiB,CAAC,IAAI,EAAC,SAAS,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,UAAU,CAAC,iBAAiB,CAAC,IAAI,EAAC,SAAS,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG;QAAE,UAAU,CAAC,EAAE,UAAU,CAAC,iBAAiB,CAAC,IAAI,EAAC,SAAS,CAAC,CAAC,UAAU,CAAC,CAAC,CAAA;KAAE,GAAG,UAAU,CAAC,iBAAiB,CAAC,IAAI,EAAC,SAAS,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC;IACtgB,CAAC,IAAI,SAAS,YAAY,EAAC,SAAS,SAAS,iBAAiB,EAAE,QAAQ,EAAE,OAAO,EAAE,KAAK,EAAE,UAAU,CAAC,iBAAiB,CAAC,IAAI,EAAC,SAAS,CAAC,CAAC,OAAO,CAAC,CAAC,GAAG,EAAE,GAAG,UAAU,CAAC,iBAAiB,CAAC,IAAI,EAAC,SAAS,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC;IACjN,YAAY,CAAC,EAAE,UAAU,CAAC,iBAAiB,CAAC,GAAG,EAAC,GAAG,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC;CACrE;AACD,QAAA,MAAM,QAAQ,EAAE,qBAAmC,CAAC;AAClC,KAAK,QAAQ,CAAC,IAAI,SAAS,YAAY,EAAC,SAAS,SAAS,iBAAiB,IAAI,YAAY,CAAC,OAAO,QAAQ,CAAC,IAAI,EAAC,SAAS,CAAC,CAAC,CAAC;AAC/H,eAAe,QAAQ,CAAC"}
1
+ {"version":3,"file":"Sortable.svelte.d.ts","sourceRoot":"","sources":["../../../src/components/sortable/Sortable.svelte.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EACV,iBAAiB,EACjB,YAAY,EACZ,aAAa,EACd,MAAM,YAAY,CAAC;AACpB,iBAAS,QAAQ,CAAC,IAAI,SAAS,YAAY,EAAE,SAAS,SAAS,iBAAiB;WAsPnD,aAAa,CAAC,IAAI,EAAE,SAAS,CAAC;;;;;EAA4E;AACvI,cAAM,iBAAiB,CAAC,IAAI,SAAS,YAAY,EAAC,SAAS,SAAS,iBAAiB;IACjF,KAAK,IAAI,UAAU,CAAC,OAAO,QAAQ,CAAC,IAAI,EAAC,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC;IAC7D,MAAM,IAAI,UAAU,CAAC,OAAO,QAAQ,CAAC,IAAI,EAAC,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC;IAC/D,KAAK,IAAI,UAAU,CAAC,OAAO,QAAQ,CAAC,IAAI,EAAC,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC;IAC7D,QAAQ;IACR,OAAO;CACV;AAED,UAAU,qBAAqB;IAC3B,KAAK,IAAI,SAAS,YAAY,EAAC,SAAS,SAAS,iBAAiB,EAAE,OAAO,EAAE,OAAO,QAAQ,EAAE,2BAA2B,CAAC,UAAU,CAAC,iBAAiB,CAAC,IAAI,EAAC,SAAS,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,QAAQ,EAAE,eAAe,CAAC,UAAU,CAAC,iBAAiB,CAAC,IAAI,EAAC,SAAS,CAAC,CAAC,OAAO,CAAC,CAAC,EAAE,UAAU,CAAC,iBAAiB,CAAC,IAAI,EAAC,SAAS,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,UAAU,CAAC,iBAAiB,CAAC,IAAI,EAAC,SAAS,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG;QAAE,UAAU,CAAC,EAAE,UAAU,CAAC,iBAAiB,CAAC,IAAI,EAAC,SAAS,CAAC,CAAC,UAAU,CAAC,CAAC,CAAA;KAAE,GAAG,UAAU,CAAC,iBAAiB,CAAC,IAAI,EAAC,SAAS,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC;IACtgB,CAAC,IAAI,SAAS,YAAY,EAAC,SAAS,SAAS,iBAAiB,EAAE,QAAQ,EAAE,OAAO,EAAE,KAAK,EAAE,UAAU,CAAC,iBAAiB,CAAC,IAAI,EAAC,SAAS,CAAC,CAAC,OAAO,CAAC,CAAC,GAAG,EAAE,GAAG,UAAU,CAAC,iBAAiB,CAAC,IAAI,EAAC,SAAS,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC;IACjN,YAAY,CAAC,EAAE,UAAU,CAAC,iBAAiB,CAAC,GAAG,EAAC,GAAG,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC;CACrE;AACD,QAAA,MAAM,QAAQ,EAAE,qBAAmC,CAAC;AAClC,KAAK,QAAQ,CAAC,IAAI,SAAS,YAAY,EAAC,SAAS,SAAS,iBAAiB,IAAI,YAAY,CAAC,OAAO,QAAQ,CAAC,IAAI,EAAC,SAAS,CAAC,CAAC,CAAC;AAC/H,eAAe,QAAQ,CAAC"}
@@ -0,0 +1,5 @@
1
+ import type { useI18n } from '@happyvertical/smrt-ui/i18n';
2
+ import type { SortableAnnouncement } from './controller.svelte.js';
3
+ /** Localized screen-reader text for a sortable engine announcement. */
4
+ export declare function formatSortableAnnouncement(t: ReturnType<typeof useI18n>['t'], announcement: SortableAnnouncement): string;
5
+ //# sourceMappingURL=announce.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"announce.d.ts","sourceRoot":"","sources":["../../../src/components/sortable/announce.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,6BAA6B,CAAC;AAE3D,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AAEnE,uEAAuE;AACvE,wBAAgB,0BAA0B,CACxC,CAAC,EAAE,UAAU,CAAC,OAAO,OAAO,CAAC,CAAC,GAAG,CAAC,EAClC,YAAY,EAAE,oBAAoB,GACjC,MAAM,CA8BR"}
@@ -0,0 +1,33 @@
1
+ import { M } from '../../i18n/strings.sortable.js';
2
+ /** Localized screen-reader text for a sortable engine announcement. */
3
+ export function formatSortableAnnouncement(t, announcement) {
4
+ switch (announcement.type) {
5
+ case 'pickup':
6
+ return t(M['ui.sortable.pickup'], {
7
+ item: announcement.item,
8
+ destinations: announcement.destinations.join(', '),
9
+ });
10
+ case 'position':
11
+ return t(M['ui.sortable.position'], {
12
+ item: announcement.item,
13
+ container: announcement.container,
14
+ position: announcement.position,
15
+ count: announcement.count,
16
+ });
17
+ case 'drop':
18
+ return t(M['ui.sortable.drop'], {
19
+ item: announcement.item,
20
+ container: announcement.container,
21
+ position: announcement.position,
22
+ count: announcement.count,
23
+ });
24
+ case 'unavailable':
25
+ return t(M['ui.sortable.unavailable'], {
26
+ container: announcement.container,
27
+ });
28
+ case 'failed':
29
+ return t(M['ui.sortable.failed'], { item: announcement.item });
30
+ case 'cancel':
31
+ return t(M['ui.sortable.cancel'], { item: announcement.item });
32
+ }
33
+ }
@@ -76,6 +76,15 @@ export interface SortableControllerOptions {
76
76
  * adjacent container at either end.
77
77
  */
78
78
  orientation?: () => 'horizontal' | 'vertical';
79
+ /**
80
+ * `true` for a single list laid out as a wrapping flow (a CSS grid of
81
+ * tiles): every arrow key steps one position along the reading order
82
+ * (Left/Right mirrored in right-to-left), and a pointer drop over an item
83
+ * that shares its row with others decides before/after by the horizontal
84
+ * midpoint; an item that fills the row (stacked layouts) still uses the
85
+ * vertical midpoint.
86
+ */
87
+ flow?: () => boolean;
79
88
  /**
80
89
  * Persist a move. May be async; a rejection restores the presentation and
81
90
  * is announced. The engine allows the next move only after it settles.
@@ -113,6 +122,7 @@ export declare class SortableController {
113
122
  pickup(itemId: string, mode: DragState['mode']): void;
114
123
  private announcePosition;
115
124
  private moveKeyboardTarget;
125
+ private isRtl;
116
126
  drop(): Promise<void>;
117
127
  /** Cancel the move in flight. Focus returns to the item when `restoreFocus`. */
118
128
  cancel(announce?: boolean, restoreFocus?: boolean): void;
@@ -1 +1 @@
1
- {"version":3,"file":"controller.svelte.d.ts","sourceRoot":"","sources":["../../../src/components/sortable/controller.svelte.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"controller.svelte.d.ts","sourceRoot":"","sources":["../../../src/components/sortable/controller.svelte.ts"],"names":[],"mappings":"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"}
@@ -112,6 +112,14 @@ export class SortableController {
112
112
  return;
113
113
  const vertical = this.options.orientation?.() === 'vertical';
114
114
  const target = { ...drag.target };
115
+ if (this.options.flow?.()) {
116
+ const mirrored = direction === 'horizontal' && this.isRtl();
117
+ const max = this.itemsIn(target.containerId, drag.itemId).length;
118
+ target.index = clamp(target.index + (mirrored ? -delta : delta), max);
119
+ this.drag = { ...drag, target };
120
+ this.announcePosition(this.drag);
121
+ return;
122
+ }
115
123
  // With same-container reordering off, the source container pins the
116
124
  // position (as it does for pointer moves): a vertical step leaves it.
117
125
  const pinned = !this.options.allowSameContainerReorder() &&
@@ -160,6 +168,12 @@ export class SortableController {
160
168
  this.drag = { ...drag, target };
161
169
  this.announcePosition(this.drag);
162
170
  }
171
+ isRtl() {
172
+ const root = this.options.root();
173
+ return (root !== undefined &&
174
+ typeof getComputedStyle === 'function' &&
175
+ getComputedStyle(root).direction === 'rtl');
176
+ }
163
177
  async drop() {
164
178
  const state = this.drag;
165
179
  if (!state)
@@ -325,7 +339,7 @@ export class SortableController {
325
339
  return (document.elementFromPoint?.(event.clientX, event.clientY) ??
326
340
  event.target);
327
341
  }
328
- setPointerTargetFromElement(element, clientY) {
342
+ setPointerTargetFromElement(element, clientY, clientX) {
329
343
  // Container ids belong to the host's domain and may repeat in another
330
344
  // instance. Pointer hit-testing must never escape this one's root.
331
345
  const root = this.options.root();
@@ -347,13 +361,21 @@ export class SortableController {
347
361
  const rawIndex = this.itemsIn(containerId).indexOf(itemElement.dataset[selectors.itemKey] ?? '');
348
362
  if (rawIndex < 0)
349
363
  return container;
350
- this.pointerTarget(containerId, this.insertionIndex(containerId, rawIndex, itemElement, clientY));
364
+ this.pointerTarget(containerId, this.insertionIndex(containerId, rawIndex, itemElement, clientY, clientX));
351
365
  return container;
352
366
  }
353
367
  /** Index to insert at when hovering item `rawIndex`, after removing the dragged item. */
354
- insertionIndex(containerId, rawIndex, itemElement, clientY) {
368
+ insertionIndex(containerId, rawIndex, itemElement, clientY, clientX) {
355
369
  const rect = itemElement.getBoundingClientRect();
356
- const before = clientY < rect.top + rect.height / 2;
370
+ let before = clientY < rect.top + rect.height / 2;
371
+ if (this.options.flow?.() && clientX !== undefined) {
372
+ const rootWidth = this.options.root()?.getBoundingClientRect().width ?? 0;
373
+ // A tile narrower than the list shares its row: order is horizontal.
374
+ if (rect.width < rootWidth * 0.95) {
375
+ const mid = rect.left + rect.width / 2;
376
+ before = this.isRtl() ? clientX > mid : clientX < mid;
377
+ }
378
+ }
357
379
  let targetIndex = rawIndex + (before ? 0 : 1);
358
380
  const drag = this.drag;
359
381
  if (drag?.source.containerId === containerId &&
@@ -375,7 +397,7 @@ export class SortableController {
375
397
  this.cancel();
376
398
  return;
377
399
  }
378
- const container = this.setPointerTargetFromElement(this.elementAtPointer(event), event.clientY);
400
+ const container = this.setPointerTargetFromElement(this.elementAtPointer(event), event.clientY, event.clientX);
379
401
  if (container?.disabled) {
380
402
  this.say({ type: 'unavailable', container: container.label });
381
403
  this.cancel(false);
@@ -405,7 +427,7 @@ export class SortableController {
405
427
  this.pointerSession = { ...session, active: true };
406
428
  }
407
429
  event.preventDefault();
408
- this.setPointerTargetFromElement(this.elementAtPointer(event), event.clientY);
430
+ this.setPointerTargetFromElement(this.elementAtPointer(event), event.clientY, event.clientX);
409
431
  }
410
432
  pointerTarget(containerId, index) {
411
433
  const drag = this.drag;
@@ -431,7 +453,7 @@ export class SortableController {
431
453
  this.cancel(false);
432
454
  return;
433
455
  }
434
- this.pointerTarget(containerId, this.insertionIndex(containerId, rawIndex, event.currentTarget, event.clientY));
456
+ this.pointerTarget(containerId, this.insertionIndex(containerId, rawIndex, event.currentTarget, event.clientY, event.clientX));
435
457
  void this.drop();
436
458
  }
437
459
  /** Native drop on a container's empty space: append. */