@svgrid/grid 1.2.33 → 2.0.0

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 (490) hide show
  1. package/README.md +6 -5
  2. package/dist/FlexRender.svelte +96 -96
  3. package/dist/GridFooter.svelte +178 -178
  4. package/dist/SvAccordion.svelte +109 -0
  5. package/dist/SvAccordion.svelte.d.ts +28 -0
  6. package/dist/SvAlert.svelte +92 -0
  7. package/dist/SvAlert.svelte.d.ts +27 -0
  8. package/dist/SvAutoComplete.svelte +47 -18
  9. package/dist/SvAutoComplete.svelte.d.ts +2 -5
  10. package/dist/SvAvatar.svelte +75 -0
  11. package/dist/SvAvatar.svelte.d.ts +14 -0
  12. package/dist/SvAvatarGroup.svelte +48 -0
  13. package/dist/SvAvatarGroup.svelte.d.ts +16 -0
  14. package/dist/SvBadge.svelte +54 -0
  15. package/dist/SvBadge.svelte.d.ts +23 -0
  16. package/dist/SvBreadcrumb.svelte +88 -0
  17. package/dist/SvBreadcrumb.svelte.d.ts +23 -0
  18. package/dist/SvButtonGroup.svelte +121 -0
  19. package/dist/SvButtonGroup.svelte.d.ts +16 -0
  20. package/dist/SvCalendar.svelte +72 -9
  21. package/dist/SvCalendar.svelte.d.ts +34 -1
  22. package/dist/SvCard.svelte +71 -0
  23. package/dist/SvCard.svelte.d.ts +28 -0
  24. package/dist/SvCarousel.svelte +134 -0
  25. package/dist/SvCarousel.svelte.d.ts +28 -0
  26. package/dist/SvCheckBox.svelte +36 -21
  27. package/dist/SvCheckBox.svelte.d.ts +2 -5
  28. package/dist/SvChip.svelte +88 -0
  29. package/dist/SvChip.svelte.d.ts +31 -0
  30. package/dist/SvCircularProgress.svelte +109 -0
  31. package/dist/SvCircularProgress.svelte.d.ts +31 -0
  32. package/dist/SvColorInput.svelte +54 -27
  33. package/dist/SvColorInput.svelte.d.ts +10 -6
  34. package/dist/SvComboBox.svelte +119 -33
  35. package/dist/SvComboBox.svelte.d.ts +18 -6
  36. package/dist/SvCommand.svelte +197 -0
  37. package/dist/SvCommand.svelte.d.ts +26 -0
  38. package/dist/SvContextMenu.svelte +96 -0
  39. package/dist/SvContextMenu.svelte.d.ts +25 -0
  40. package/dist/SvCountryInput.svelte +56 -21
  41. package/dist/SvCountryInput.svelte.d.ts +9 -5
  42. package/dist/SvDateRangeInput.svelte +256 -0
  43. package/dist/SvDateRangeInput.svelte.d.ts +37 -0
  44. package/dist/SvDateTimePicker.svelte +57 -20
  45. package/dist/SvDateTimePicker.svelte.d.ts +12 -4
  46. package/dist/SvDivider.svelte +61 -0
  47. package/dist/SvDivider.svelte.d.ts +22 -0
  48. package/dist/SvDrawer.svelte +226 -0
  49. package/dist/SvDrawer.svelte.d.ts +43 -0
  50. package/dist/SvDropDownList.svelte +114 -35
  51. package/dist/SvDropDownList.svelte.d.ts +7 -6
  52. package/dist/SvDurationInput.svelte +108 -0
  53. package/dist/SvDurationInput.svelte.d.ts +15 -0
  54. package/dist/SvEmptyState.svelte +59 -0
  55. package/dist/SvEmptyState.svelte.d.ts +25 -0
  56. package/dist/SvField.svelte +85 -0
  57. package/dist/SvField.svelte.d.ts +30 -0
  58. package/dist/SvFileUpload.svelte +169 -0
  59. package/dist/SvFileUpload.svelte.d.ts +24 -0
  60. package/dist/SvForm.svelte +7 -1
  61. package/dist/SvForm.svelte.d.ts +3 -0
  62. package/dist/SvGauge.svelte +7 -1
  63. package/dist/SvGauge.svelte.d.ts +11 -0
  64. package/dist/SvGrid.controller.svelte.d.ts +6 -0
  65. package/dist/SvGrid.controller.svelte.js +64 -9
  66. package/dist/SvGrid.css +2376 -2343
  67. package/dist/SvGrid.svelte +2764 -2651
  68. package/dist/SvGrid.types.d.ts +366 -0
  69. package/dist/SvGridBoard.svelte +2281 -0
  70. package/dist/SvGridBoard.svelte.d.ts +31 -0
  71. package/dist/SvGridDropdown.svelte +666 -665
  72. package/dist/SvGridSelect.svelte +255 -0
  73. package/dist/SvGridSelect.svelte.d.ts +32 -0
  74. package/dist/SvGroupCell.svelte +109 -0
  75. package/dist/SvGroupCell.svelte.d.ts +41 -0
  76. package/dist/SvListBox.svelte +123 -36
  77. package/dist/SvListBox.svelte.d.ts +12 -8
  78. package/dist/SvMaskedInput.svelte +53 -13
  79. package/dist/SvMaskedInput.svelte.d.ts +16 -6
  80. package/dist/SvMenu.svelte +101 -0
  81. package/dist/SvMenu.svelte.d.ts +26 -0
  82. package/dist/SvMenuList.svelte +143 -0
  83. package/dist/SvMenuList.svelte.d.ts +24 -0
  84. package/dist/SvModal.svelte +220 -0
  85. package/dist/SvModal.svelte.d.ts +31 -0
  86. package/dist/SvMultiSelect.svelte +277 -0
  87. package/dist/SvMultiSelect.svelte.d.ts +31 -0
  88. package/dist/SvNavPane.svelte +314 -0
  89. package/dist/SvNavPane.svelte.d.ts +59 -0
  90. package/dist/SvNumberInput.svelte +23 -9
  91. package/dist/SvNumberInput.svelte.d.ts +2 -0
  92. package/dist/SvOtpInput.svelte +157 -0
  93. package/dist/SvOtpInput.svelte.d.ts +16 -0
  94. package/dist/SvPagination.svelte +100 -0
  95. package/dist/SvPagination.svelte.d.ts +16 -0
  96. package/dist/SvPasswordInput.svelte +42 -12
  97. package/dist/SvPasswordInput.svelte.d.ts +13 -6
  98. package/dist/SvPhoneInput.svelte +43 -11
  99. package/dist/SvPhoneInput.svelte.d.ts +10 -11
  100. package/dist/SvPopover.svelte +127 -0
  101. package/dist/SvPopover.svelte.d.ts +35 -0
  102. package/dist/SvProgress.svelte +116 -0
  103. package/dist/SvProgress.svelte.d.ts +32 -0
  104. package/dist/SvRadioGroup.svelte +40 -22
  105. package/dist/SvRadioGroup.svelte.d.ts +2 -10
  106. package/dist/SvRating.svelte +51 -30
  107. package/dist/SvRating.svelte.d.ts +10 -7
  108. package/dist/SvRichText.svelte +192 -0
  109. package/dist/SvRichText.svelte.d.ts +16 -0
  110. package/dist/SvRowGroupPanel.svelte +147 -0
  111. package/dist/SvRowGroupPanel.svelte.d.ts +17 -0
  112. package/dist/SvScrollArea.svelte +50 -0
  113. package/dist/SvScrollArea.svelte.d.ts +22 -0
  114. package/dist/SvSkeleton.svelte +76 -0
  115. package/dist/SvSkeleton.svelte.d.ts +25 -0
  116. package/dist/SvSlider.svelte +41 -9
  117. package/dist/SvSlider.svelte.d.ts +4 -4
  118. package/dist/SvSparkline.svelte +77 -0
  119. package/dist/SvSparkline.svelte.d.ts +28 -0
  120. package/dist/SvSplitter.svelte +138 -0
  121. package/dist/SvSplitter.svelte.d.ts +32 -0
  122. package/dist/SvStat.svelte +86 -0
  123. package/dist/SvStat.svelte.d.ts +30 -0
  124. package/dist/SvStepper.svelte +91 -0
  125. package/dist/SvStepper.svelte.d.ts +24 -0
  126. package/dist/SvSwitchButton.svelte +39 -24
  127. package/dist/SvSwitchButton.svelte.d.ts +2 -5
  128. package/dist/SvTabs.svelte +147 -28
  129. package/dist/SvTabs.svelte.d.ts +16 -4
  130. package/dist/SvTagsInput.svelte +59 -22
  131. package/dist/SvTagsInput.svelte.d.ts +9 -4
  132. package/dist/SvTextArea.svelte +113 -0
  133. package/dist/SvTextArea.svelte.d.ts +18 -0
  134. package/dist/SvTextInput.svelte +115 -0
  135. package/dist/SvTextInput.svelte.d.ts +20 -0
  136. package/dist/SvTimePicker.svelte +19 -5
  137. package/dist/SvTimePicker.svelte.d.ts +12 -0
  138. package/dist/SvTimeline.svelte +75 -0
  139. package/dist/SvTimeline.svelte.d.ts +24 -0
  140. package/dist/SvToaster.svelte +124 -0
  141. package/dist/SvToaster.svelte.d.ts +10 -0
  142. package/dist/SvToggleButton.svelte +37 -12
  143. package/dist/SvToggleButton.svelte.d.ts +2 -4
  144. package/dist/SvTooltip.svelte +113 -0
  145. package/dist/SvTooltip.svelte.d.ts +22 -0
  146. package/dist/SvTour.svelte +151 -0
  147. package/dist/SvTour.svelte.d.ts +25 -0
  148. package/dist/SvTree.svelte +286 -44
  149. package/dist/SvTree.svelte.d.ts +26 -9
  150. package/dist/SvTreeSelect.svelte +222 -0
  151. package/dist/SvTreeSelect.svelte.d.ts +24 -0
  152. package/dist/a11y/dismissable.d.ts +32 -0
  153. package/dist/a11y/dismissable.js +54 -0
  154. package/dist/a11y/focus-trap.d.ts +39 -0
  155. package/dist/a11y/focus-trap.js +142 -0
  156. package/dist/a11y/live-region.d.ts +8 -0
  157. package/dist/a11y/live-region.js +60 -0
  158. package/dist/a11y/scroll-lock.d.ts +4 -0
  159. package/dist/a11y/scroll-lock.js +41 -0
  160. package/dist/a11y.d.ts +3 -1
  161. package/dist/a11y.js +1 -1
  162. package/dist/avatar.d.ts +10 -0
  163. package/dist/avatar.js +22 -0
  164. package/dist/builtin-editors.d.ts +5 -0
  165. package/dist/builtin-editors.js +55 -0
  166. package/dist/cdn/svgrid.js +16022 -8235
  167. package/dist/cdn/svgrid.svelte-external.js +14543 -6765
  168. package/dist/columns.js +3 -2
  169. package/dist/core.d.ts +7 -1
  170. package/dist/countries.d.ts +12 -0
  171. package/dist/countries.js +24 -0
  172. package/dist/createAccordion.svelte.d.ts +71 -0
  173. package/dist/createAccordion.svelte.js +99 -0
  174. package/dist/createAutocomplete.svelte.d.ts +13 -4
  175. package/dist/createAutocomplete.svelte.js +11 -1
  176. package/dist/createButtonGroup.svelte.d.ts +62 -0
  177. package/dist/createButtonGroup.svelte.js +154 -0
  178. package/dist/createCalendar.svelte.d.ts +5 -0
  179. package/dist/createCalendar.svelte.js +2 -0
  180. package/dist/createCheckbox.svelte.d.ts +9 -17
  181. package/dist/createCheckbox.svelte.js +28 -1
  182. package/dist/createColorInput.svelte.d.ts +12 -22
  183. package/dist/createColorInput.svelte.js +13 -0
  184. package/dist/createCombobox.svelte.d.ts +16 -5
  185. package/dist/createCombobox.svelte.js +13 -2
  186. package/dist/createCountryInput.svelte.d.ts +14 -3
  187. package/dist/createCountryInput.svelte.js +12 -2
  188. package/dist/createDateTimePicker.svelte.d.ts +17 -2
  189. package/dist/createDateTimePicker.svelte.js +12 -2
  190. package/dist/createDropdownList.svelte.d.ts +14 -5
  191. package/dist/createDropdownList.svelte.js +50 -1
  192. package/dist/createFileUpload.svelte.d.ts +68 -0
  193. package/dist/createFileUpload.svelte.js +122 -0
  194. package/dist/createListbox.svelte.d.ts +10 -1
  195. package/dist/createListbox.svelte.js +48 -1
  196. package/dist/createMaskedInput.svelte.d.ts +11 -2
  197. package/dist/createMaskedInput.svelte.js +11 -1
  198. package/dist/createNumberInput.svelte.d.ts +1 -0
  199. package/dist/createNumberInput.svelte.js +1 -0
  200. package/dist/createPasswordInput.svelte.d.ts +19 -21
  201. package/dist/createPasswordInput.svelte.js +16 -4
  202. package/dist/createPhoneInput.svelte.d.ts +26 -7
  203. package/dist/createPhoneInput.svelte.js +24 -3
  204. package/dist/createPopoverSelect.svelte.d.ts +86 -0
  205. package/dist/createPopoverSelect.svelte.js +196 -0
  206. package/dist/createRadioGroup.svelte.d.ts +9 -0
  207. package/dist/createRadioGroup.svelte.js +11 -1
  208. package/dist/createRating.svelte.d.ts +11 -0
  209. package/dist/createRating.svelte.js +12 -1
  210. package/dist/createSlider.svelte.d.ts +2 -0
  211. package/dist/createSlider.svelte.js +16 -5
  212. package/dist/createSplitter.svelte.d.ts +67 -0
  213. package/dist/createSplitter.svelte.js +99 -0
  214. package/dist/createSwitch.svelte.d.ts +9 -16
  215. package/dist/createSwitch.svelte.js +28 -1
  216. package/dist/createTabs.svelte.d.ts +7 -0
  217. package/dist/createTabs.svelte.js +17 -2
  218. package/dist/createTagsInput.svelte.d.ts +13 -1
  219. package/dist/createTagsInput.svelte.js +12 -3
  220. package/dist/createToggle.svelte.d.ts +9 -0
  221. package/dist/createToggle.svelte.js +12 -1
  222. package/dist/createTree.svelte.d.ts +19 -0
  223. package/dist/createTree.svelte.js +108 -15
  224. package/dist/debounce.d.ts +11 -0
  225. package/dist/debounce.js +30 -0
  226. package/dist/duration.d.ts +15 -0
  227. package/dist/duration.js +51 -0
  228. package/dist/editor-contract.d.ts +62 -7
  229. package/dist/editor-contract.js +45 -5
  230. package/dist/editor-registry.d.ts +67 -0
  231. package/dist/editor-registry.js +38 -0
  232. package/dist/editors/cell-editors.d.ts +1 -1
  233. package/dist/editors/cell-editors.js +5 -0
  234. package/dist/fuzzy.d.ts +3 -0
  235. package/dist/fuzzy.js +41 -0
  236. package/dist/grid-select.d.ts +9 -0
  237. package/dist/grid-select.js +8 -0
  238. package/dist/index.d.ts +79 -6
  239. package/dist/index.js +78 -4
  240. package/dist/keyboard-handlers.js +19 -0
  241. package/dist/list-option.d.ts +36 -0
  242. package/dist/list-option.js +68 -0
  243. package/dist/otp.d.ts +16 -0
  244. package/dist/otp.js +26 -0
  245. package/dist/paginate.d.ts +20 -0
  246. package/dist/paginate.js +40 -0
  247. package/dist/popover.d.ts +15 -1
  248. package/dist/popover.js +29 -3
  249. package/dist/recurrence.d.ts +36 -0
  250. package/dist/recurrence.js +90 -0
  251. package/dist/server-data-source.d.ts +89 -0
  252. package/dist/server-data-source.js +4 -0
  253. package/dist/server-group-model.d.ts +98 -0
  254. package/dist/server-group-model.js +263 -0
  255. package/dist/toast-store.svelte.d.ts +41 -0
  256. package/dist/toast-store.svelte.js +113 -0
  257. package/dist/tree-select.d.ts +19 -0
  258. package/dist/tree-select.js +40 -0
  259. package/dist/ui-app.types.d.ts +80 -0
  260. package/dist/ui-app.types.js +7 -0
  261. package/dist/validators.d.ts +43 -0
  262. package/dist/validators.js +53 -0
  263. package/dist/virtual.d.ts +35 -0
  264. package/dist/virtual.js +34 -0
  265. package/package.json +85 -85
  266. package/src/FlexRender.svelte +96 -96
  267. package/src/GridFooter.svelte +178 -178
  268. package/src/SvAccordion.svelte +109 -0
  269. package/src/SvAccordion.test.ts +66 -0
  270. package/src/SvAlert.svelte +92 -0
  271. package/src/SvAutoComplete.svelte +47 -18
  272. package/src/SvAvatar.svelte +75 -0
  273. package/src/SvAvatarGroup.svelte +48 -0
  274. package/src/SvBadge.svelte +54 -0
  275. package/src/SvBreadcrumb.svelte +88 -0
  276. package/src/SvButtonGroup.svelte +121 -0
  277. package/src/SvButtonGroup.test.ts +72 -0
  278. package/src/SvCalendar.svelte +72 -9
  279. package/src/SvCard.svelte +71 -0
  280. package/src/SvCarousel.svelte +134 -0
  281. package/src/SvCheckBox.svelte +36 -21
  282. package/src/SvChip.svelte +88 -0
  283. package/src/SvCircularProgress.svelte +109 -0
  284. package/src/SvColorInput.svelte +54 -27
  285. package/src/SvComboBox.svelte +119 -33
  286. package/src/SvCommand.svelte +197 -0
  287. package/src/SvContextMenu.svelte +96 -0
  288. package/src/SvCountryInput.svelte +56 -21
  289. package/src/SvDateRangeInput.svelte +256 -0
  290. package/src/SvDateRangeInput.test.ts +80 -0
  291. package/src/SvDateTimePicker.svelte +57 -20
  292. package/src/SvDivider.svelte +61 -0
  293. package/src/SvDrawer.svelte +226 -0
  294. package/src/SvDrawer.test.ts +125 -0
  295. package/src/SvDropDownList.svelte +114 -35
  296. package/src/SvDurationInput.svelte +108 -0
  297. package/src/SvEmptyState.svelte +59 -0
  298. package/src/SvField.svelte +85 -0
  299. package/src/SvFileUpload.svelte +169 -0
  300. package/src/SvFileUpload.test.ts +59 -0
  301. package/src/SvForm.svelte +7 -1
  302. package/src/SvGauge.svelte +7 -1
  303. package/src/SvGrid.controller.svelte.ts +2553 -2494
  304. package/src/SvGrid.css +2376 -2343
  305. package/src/SvGrid.svelte +2764 -2651
  306. package/src/SvGrid.types.ts +944 -570
  307. package/src/SvGridBoard.svelte +2281 -0
  308. package/src/SvGridDropdown.svelte +666 -665
  309. package/src/SvGridSelect.svelte +255 -0
  310. package/src/SvGridSelect.test.ts +100 -0
  311. package/src/SvGroupCell.svelte +109 -0
  312. package/src/SvListBox.svelte +123 -36
  313. package/src/SvMaskedInput.svelte +53 -13
  314. package/src/SvMenu.svelte +101 -0
  315. package/src/SvMenu.test.ts +73 -0
  316. package/src/SvMenuList.svelte +143 -0
  317. package/src/SvModal.svelte +220 -0
  318. package/src/SvMultiSelect.svelte +277 -0
  319. package/src/SvMultiSelect.test.ts +167 -0
  320. package/src/SvNavPane.svelte +314 -0
  321. package/src/SvNavPane.test.ts +70 -0
  322. package/src/SvNumberInput.svelte +23 -9
  323. package/src/SvOtpInput.svelte +157 -0
  324. package/src/SvPagination.svelte +100 -0
  325. package/src/SvPasswordInput.svelte +42 -12
  326. package/src/SvPhoneInput.svelte +43 -11
  327. package/src/SvPopover.svelte +127 -0
  328. package/src/SvProgress.svelte +116 -0
  329. package/src/SvRadioGroup.svelte +40 -22
  330. package/src/SvRating.svelte +51 -30
  331. package/src/SvRichText.svelte +192 -0
  332. package/src/SvRowGroupPanel.svelte +147 -0
  333. package/src/SvScrollArea.svelte +50 -0
  334. package/src/SvSkeleton.svelte +76 -0
  335. package/src/SvSlider.svelte +41 -9
  336. package/src/SvSparkline.svelte +77 -0
  337. package/src/SvSplitter.svelte +138 -0
  338. package/src/SvSplitter.test.ts +55 -0
  339. package/src/SvStat.svelte +86 -0
  340. package/src/SvStepper.svelte +91 -0
  341. package/src/SvSwitchButton.svelte +39 -24
  342. package/src/SvTabs.svelte +147 -28
  343. package/src/SvTagsInput.svelte +59 -22
  344. package/src/SvTextArea.svelte +113 -0
  345. package/src/SvTextInput.svelte +115 -0
  346. package/src/SvTimePicker.svelte +19 -5
  347. package/src/SvTimeline.svelte +75 -0
  348. package/src/SvToaster.svelte +124 -0
  349. package/src/SvToaster.test.ts +63 -0
  350. package/src/SvToggleButton.svelte +37 -12
  351. package/src/SvTooltip.svelte +113 -0
  352. package/src/SvTour.svelte +151 -0
  353. package/src/SvTree.svelte +286 -44
  354. package/src/SvTreeSelect.svelte +222 -0
  355. package/src/SvTreeSelect.test.ts +87 -0
  356. package/src/a11y/dismissable.test.ts +95 -0
  357. package/src/a11y/dismissable.ts +94 -0
  358. package/src/a11y/focus-trap.test.ts +110 -0
  359. package/src/a11y/focus-trap.ts +134 -0
  360. package/src/a11y/live-region.test.ts +40 -0
  361. package/src/a11y/live-region.ts +65 -0
  362. package/src/a11y/scroll-lock.test.ts +38 -0
  363. package/src/a11y/scroll-lock.ts +41 -0
  364. package/src/a11y.contract.test.ts +49 -49
  365. package/src/a11y.test.ts +59 -59
  366. package/src/a11y.ts +61 -59
  367. package/src/avatar.test.ts +32 -0
  368. package/src/avatar.ts +21 -0
  369. package/src/board.test.ts +927 -0
  370. package/src/build-api.ts +798 -798
  371. package/src/builtin-editors.grid.test.ts +85 -0
  372. package/src/builtin-editors.test.ts +58 -0
  373. package/src/builtin-editors.ts +56 -0
  374. package/src/cell-formatting.ts +169 -169
  375. package/src/cell-render.ts +469 -469
  376. package/src/collaboration.test.ts +104 -104
  377. package/src/collaboration.ts +167 -167
  378. package/src/columns.ts +3 -2
  379. package/src/core.performance.test.ts +30 -30
  380. package/src/core.ts +1111 -1101
  381. package/src/countries.ts +25 -0
  382. package/src/createAccordion.svelte.ts +126 -0
  383. package/src/createAutocomplete.svelte.ts +18 -1
  384. package/src/createButtonGroup.svelte.ts +166 -0
  385. package/src/createCalendar.svelte.ts +6 -0
  386. package/src/createCheckbox.svelte.ts +23 -1
  387. package/src/createColorInput.svelte.ts +20 -0
  388. package/src/createCombobox.svelte.ts +22 -2
  389. package/src/createCountryInput.svelte.ts +21 -2
  390. package/src/createDateTimePicker.svelte.ts +23 -2
  391. package/src/createDropdownList.svelte.ts +31 -2
  392. package/src/createFileUpload.svelte.ts +144 -0
  393. package/src/createGrid.svelte.ts +42 -42
  394. package/src/createGrid.test.ts +10 -10
  395. package/src/createGridState.svelte.ts +17 -17
  396. package/src/createListbox.svelte.ts +35 -3
  397. package/src/createMaskedInput.svelte.ts +18 -1
  398. package/src/createNumberInput.svelte.ts +2 -0
  399. package/src/createPasswordInput.svelte.ts +31 -5
  400. package/src/createPhoneInput.svelte.ts +38 -4
  401. package/src/createPopoverSelect.svelte.ts +208 -0
  402. package/src/createRadioGroup.svelte.ts +23 -1
  403. package/src/createRating.svelte.ts +26 -1
  404. package/src/createSlider.svelte.ts +14 -3
  405. package/src/createSplitter.svelte.ts +119 -0
  406. package/src/createSwitch.svelte.ts +26 -3
  407. package/src/createTabs.svelte.ts +20 -3
  408. package/src/createTagsInput.svelte.ts +24 -3
  409. package/src/createToggle.svelte.ts +25 -2
  410. package/src/createTree.svelte.ts +104 -14
  411. package/src/debounce.test.ts +50 -0
  412. package/src/debounce.ts +41 -0
  413. package/src/duration.test.ts +41 -0
  414. package/src/duration.ts +51 -0
  415. package/src/editing.test.ts +859 -859
  416. package/src/editing.ts +675 -675
  417. package/src/editor-contract.ts +87 -8
  418. package/src/editor-registry.grid.test.ts +98 -0
  419. package/src/editor-registry.test.ts +86 -0
  420. package/src/editor-registry.ts +106 -0
  421. package/src/editors/cell-editors.ts +10 -1
  422. package/src/export-data-api.test.ts +126 -126
  423. package/src/export-format.test.ts +107 -107
  424. package/src/export-format.ts +598 -598
  425. package/src/flex-render.ts +3 -3
  426. package/src/fuzzy.test.ts +40 -0
  427. package/src/fuzzy.ts +39 -0
  428. package/src/grid-select.test.ts +28 -0
  429. package/src/grid-select.ts +20 -0
  430. package/src/index.ts +463 -318
  431. package/src/keyboard-handlers.ts +20 -0
  432. package/src/keyboard.test.ts +59 -59
  433. package/src/keyboard.ts +97 -97
  434. package/src/list-option.ts +74 -0
  435. package/src/list-power.test.ts +71 -0
  436. package/src/menus.ts +582 -582
  437. package/src/merge-objects.ts +48 -48
  438. package/src/otp.test.ts +28 -0
  439. package/src/otp.ts +28 -0
  440. package/src/overlays.test.ts +85 -0
  441. package/src/paginate.test.ts +41 -0
  442. package/src/paginate.ts +61 -0
  443. package/src/phone-valid.test.ts +26 -0
  444. package/src/popover.ts +31 -3
  445. package/src/progress.test.ts +55 -0
  446. package/src/recurrence.test.ts +91 -0
  447. package/src/recurrence.ts +111 -0
  448. package/src/render-component.ts +28 -28
  449. package/src/selection.test.ts +754 -754
  450. package/src/selection.ts +600 -600
  451. package/src/server-data-source.test.ts +289 -289
  452. package/src/server-data-source.ts +413 -311
  453. package/src/server-group-model.test.ts +294 -0
  454. package/src/server-group-model.ts +370 -0
  455. package/src/sparkline.test.ts +68 -68
  456. package/src/sparkline.ts +169 -169
  457. package/src/spreadsheet.test.ts +489 -489
  458. package/src/spreadsheet.ts +304 -304
  459. package/src/static-functions.ts +11 -11
  460. package/src/subscribe.ts +38 -38
  461. package/src/svgrid-wrapper.types.ts +439 -439
  462. package/src/svgrid.behavior.test.ts +706 -706
  463. package/src/svgrid.features.test.ts +157 -157
  464. package/src/svgrid.new-features.wrapper.test.ts +251 -251
  465. package/src/svgrid.responsive.test.ts +72 -0
  466. package/src/svgrid.wrapper.test.ts +40 -40
  467. package/src/toast-store.svelte.ts +148 -0
  468. package/src/toast-store.test.ts +86 -0
  469. package/src/tree-edit.test.ts +49 -0
  470. package/src/tree-filter.test.ts +56 -0
  471. package/src/tree-select.test.ts +48 -0
  472. package/src/tree-select.ts +62 -0
  473. package/src/ui-app.test.ts +130 -0
  474. package/src/ui-app.types.ts +88 -0
  475. package/src/ui-display.test.ts +79 -0
  476. package/src/ui-inputs.test.ts +1 -1
  477. package/src/ui-status.test.ts +141 -0
  478. package/src/ui-tier1.test.ts +142 -0
  479. package/src/ui-tier2.test.ts +124 -0
  480. package/src/ui-tier3.test.ts +139 -0
  481. package/src/validators.test.ts +58 -0
  482. package/src/validators.ts +105 -0
  483. package/src/virtual.test.ts +72 -0
  484. package/src/virtual.ts +67 -0
  485. package/src/virtualization/column-virtualizer.test.ts +27 -27
  486. package/src/virtualization/column-virtualizer.ts +30 -30
  487. package/src/virtualization/svelte-virtualizer.svelte.ts +26 -26
  488. package/src/virtualization/types.ts +30 -30
  489. package/src/virtualization/virtualizer.test.ts +47 -47
  490. package/src/virtualization/virtualizer.ts +296 -296
@@ -17,6 +17,7 @@
17
17
  */
18
18
  import { formatDate, parseDate } from './datetime/date-format'
19
19
  import { toDate, clampDate, withTime, startOfDay, type DateLike } from './datetime/date-core'
20
+ import { editorAria, type EditorAriaState } from './editor-contract'
20
21
 
21
22
  export type DateTimeValue = Date | string | number | null
22
23
  export type DropDownDisplayMode = 'both' | 'calendar' | 'time'
@@ -40,6 +41,17 @@ export type DateTimePickerConfig = {
40
41
  stepMinutes?: () => number
41
42
  disabled?: () => boolean
42
43
  readonly?: () => boolean
44
+ /** Accessible label for the open-picker toggle (localizable). */
45
+ toggleLabel?: () => string | undefined
46
+ /** Accessible label for the clear button (localizable). */
47
+ clearLabel?: () => string | undefined
48
+ // Editor contract (ARIA + validation) - folded into inputProps().
49
+ id?: () => string | undefined
50
+ invalid?: () => boolean
51
+ required?: () => boolean
52
+ error?: () => string | undefined
53
+ hint?: () => string | undefined
54
+ ariaLabel?: () => string | undefined
43
55
  }
44
56
 
45
57
  const defaultLocale = () => (typeof navigator !== 'undefined' ? navigator.language : 'en-US')
@@ -164,9 +176,18 @@ export function createDateTimePicker(config: DateTimePickerConfig) {
164
176
  * alongside `bind:value={dtp.text}`. */
165
177
  inputProps() {
166
178
  return {
179
+ id: config.id?.(),
167
180
  type: 'text' as const,
168
181
  disabled: isDisabled(),
169
182
  readonly: isReadonly(),
183
+ ...editorAria({
184
+ id: config.id?.(),
185
+ invalid: config.invalid?.(),
186
+ required: config.required?.(),
187
+ error: config.error?.(),
188
+ hint: config.hint?.(),
189
+ ariaLabel: config.ariaLabel?.(),
190
+ } satisfies EditorAriaState),
170
191
  onblur: commitFromText,
171
192
  onkeydown: onInputKeydown,
172
193
  }
@@ -175,7 +196,7 @@ export function createDateTimePicker(config: DateTimePickerConfig) {
175
196
  toggleProps() {
176
197
  return {
177
198
  type: 'button' as const,
178
- 'aria-label': 'Open picker',
199
+ 'aria-label': config.toggleLabel?.() ?? 'Open picker',
179
200
  'aria-haspopup': 'dialog' as const,
180
201
  'aria-expanded': open,
181
202
  disabled: !isInteractive,
@@ -187,7 +208,7 @@ export function createDateTimePicker(config: DateTimePickerConfig) {
187
208
  clearProps() {
188
209
  return {
189
210
  type: 'button' as const,
190
- 'aria-label': 'Clear',
211
+ 'aria-label': config.clearLabel?.() ?? 'Clear',
191
212
  onclick: () => commit(null),
192
213
  }
193
214
  },
@@ -19,7 +19,8 @@
19
19
  * {/if}
20
20
  * ```
21
21
  */
22
- import type { ListOption } from './list-option'
22
+ import { createTypeaheadBuffer, isTypeaheadKey, nextTypeaheadIndex, type ListOption } from './list-option'
23
+ import { editorAria, type EditorAriaState } from './editor-contract'
23
24
 
24
25
  export type DropdownValue = string | number | null
25
26
 
@@ -32,12 +33,27 @@ export type DropdownListConfig = {
32
33
  ariaLabel?: () => string | undefined
33
34
  /** DOM focus hook provided by the renderer; the core never touches the DOM. */
34
35
  focusTrigger?: () => void
36
+ // Editor contract (ARIA + validation) - folded into triggerProps().
37
+ id?: () => string | undefined
38
+ invalid?: () => boolean
39
+ required?: () => boolean
40
+ error?: () => string | undefined
41
+ hint?: () => string | undefined
35
42
  }
36
43
 
37
44
  export function createDropdownList(config: DropdownListConfig) {
38
45
  const opts = () => config.options()
39
46
  const disabled = () => config.disabled?.() ?? false
40
47
 
48
+ const ariaState = (): EditorAriaState => ({
49
+ id: config.id?.(),
50
+ invalid: config.invalid?.(),
51
+ required: config.required?.(),
52
+ error: config.error?.(),
53
+ hint: config.hint?.(),
54
+ ariaLabel: config.ariaLabel?.(),
55
+ })
56
+
41
57
  let open = $state(false)
42
58
  let active = $state(-1)
43
59
 
@@ -61,8 +77,20 @@ export function createDropdownList(config: DropdownListConfig) {
61
77
  const pos = enabledIdx.indexOf(active)
62
78
  active = enabledIdx[(pos + d + enabledIdx.length) % enabledIdx.length] ?? active
63
79
  }
80
+ // Type-ahead: typing a label prefix jumps the active option (and selects it
81
+ // when the list is closed, matching a native <select>).
82
+ const typeahead = createTypeaheadBuffer()
83
+ function onTypeahead(char: string) {
84
+ const buffer = typeahead.push(char.toLowerCase())
85
+ const from = active >= 0 ? active : opts().findIndex((o) => o.value === config.value())
86
+ const next = nextTypeaheadIndex(opts(), buffer, from)
87
+ if (next < 0) return
88
+ active = next
89
+ if (!open) config.onChange?.(opts()[next]!.value)
90
+ }
64
91
  function onKeydown(e: KeyboardEvent) {
65
92
  if (disabled()) return
93
+ if (isTypeaheadKey(e)) { onTypeahead(e.key); return }
66
94
  if (!open && (e.key === 'ArrowDown' || e.key === 'Enter' || e.key === ' ')) { e.preventDefault(); openPanel(); return }
67
95
  if (!open) return
68
96
  if (e.key === 'ArrowDown') { e.preventDefault(); move(1) }
@@ -93,10 +121,11 @@ export function createDropdownList(config: DropdownListConfig) {
93
121
  onKeydown,
94
122
  /** Spread onto the trigger <button>. */
95
123
  triggerProps: () => ({
124
+ id: config.id?.(),
96
125
  type: 'button' as const,
97
126
  'aria-haspopup': 'listbox' as const,
98
127
  'aria-expanded': open,
99
- 'aria-label': config.ariaLabel?.(),
128
+ ...editorAria(ariaState()),
100
129
  disabled: disabled(),
101
130
  onclick: toggle,
102
131
  onkeydown: onKeydown,
@@ -0,0 +1,144 @@
1
+ /**
2
+ * createFileUpload - the HEADLESS core behind <SvFileUpload>: a drag-and-drop
3
+ * file field with accept / size / count validation, exposed as **prop-getters**
4
+ * you spread onto YOUR OWN markup. The DataTransfer / File reading is a DOM
5
+ * concern that stays in the renderer; the core owns the list, validation, drag
6
+ * state and ARIA. Parity: Smart `smart-file-upload`.
7
+ *
8
+ * ```svelte
9
+ * <script lang="ts">
10
+ * import { createFileUpload } from '@svgrid/grid'
11
+ * let files = $state<File[]>([])
12
+ * const fu = createFileUpload({ files: () => files, onChange: (f) => (files = f) })
13
+ * </script>
14
+ * <div {...fu.dropzoneProps()} ondrop={(e) => fu.addFiles([...e.dataTransfer.files])}>...</div>
15
+ * <input {...fu.inputProps()} />
16
+ * ```
17
+ */
18
+ import { editorAria, type EditorAriaState } from './editor-contract'
19
+
20
+ export type FileRejectReason = 'type' | 'size' | 'count'
21
+ export type FileRejection = { file: File; reason: FileRejectReason }
22
+
23
+ /** Reactive inputs are passed as getters so the core tracks live prop changes. */
24
+ export type FileUploadConfig = {
25
+ files: () => File[]
26
+ onChange?: (files: File[]) => void
27
+ /** Rejected files (wrong type / too big / over the count cap). */
28
+ onReject?: (rejections: FileRejection[]) => void
29
+ /** Comma list like "image/*,.pdf" (matches MIME or extension). */
30
+ accept?: () => string | undefined
31
+ multiple?: () => boolean
32
+ /** Max size per file in bytes. */
33
+ maxSize?: () => number | undefined
34
+ /** Max number of files (multiple mode). */
35
+ maxFiles?: () => number | undefined
36
+ disabled?: () => boolean
37
+ readonly?: () => boolean
38
+ // Editor contract (ARIA + validation) - folded into dropzoneProps().
39
+ id?: () => string | undefined
40
+ invalid?: () => boolean
41
+ required?: () => boolean
42
+ error?: () => string | undefined
43
+ hint?: () => string | undefined
44
+ ariaLabel?: () => string | undefined
45
+ }
46
+
47
+ /** Whether `file` satisfies an `accept` list (MIME globs or extensions). Pure. */
48
+ export function fileMatchesAccept(file: File, accept?: string): boolean {
49
+ if (!accept || !accept.trim()) return true
50
+ const name = file.name.toLowerCase()
51
+ const type = file.type.toLowerCase()
52
+ return accept.split(',').map((s) => s.trim().toLowerCase()).filter(Boolean).some((tok) => {
53
+ if (tok.startsWith('.')) return name.endsWith(tok)
54
+ if (tok.endsWith('/*')) return type.startsWith(tok.slice(0, -1))
55
+ return type === tok
56
+ })
57
+ }
58
+
59
+ export function createFileUpload(config: FileUploadConfig) {
60
+ const accept = () => config.accept?.()
61
+ const multiple = () => config.multiple?.() ?? false
62
+ const maxSize = () => config.maxSize?.()
63
+ const maxFiles = () => config.maxFiles?.()
64
+ const disabled = () => config.disabled?.() ?? false
65
+ const readonly = () => config.readonly?.() ?? false
66
+ const isInteractive = $derived(!disabled() && !readonly())
67
+
68
+ let dragging = $state(false)
69
+
70
+ function addFiles(incoming: File[]) {
71
+ if (!isInteractive || !incoming.length) return
72
+ const accepted: File[] = []
73
+ const rejected: FileRejection[] = []
74
+ for (const f of incoming) {
75
+ if (!fileMatchesAccept(f, accept())) { rejected.push({ file: f, reason: 'type' }); continue }
76
+ const cap = maxSize()
77
+ if (cap != null && f.size > cap) { rejected.push({ file: f, reason: 'size' }); continue }
78
+ accepted.push(f)
79
+ }
80
+ let next = multiple() ? [...config.files(), ...accepted] : accepted.slice(-1)
81
+ const limit = maxFiles()
82
+ if (multiple() && limit != null && next.length > limit) {
83
+ for (const f of next.slice(limit)) rejected.push({ file: f, reason: 'count' })
84
+ next = next.slice(0, limit)
85
+ }
86
+ if (rejected.length) config.onReject?.(rejected)
87
+ config.onChange?.(next)
88
+ }
89
+
90
+ function removeAt(index: number) {
91
+ if (!isInteractive) return
92
+ config.onChange?.(config.files().filter((_, i) => i !== index))
93
+ }
94
+ function clear() { if (isInteractive) config.onChange?.([]) }
95
+
96
+ const setDragging = (v: boolean) => { if (isInteractive) dragging = v }
97
+
98
+ const ariaState = (): EditorAriaState => ({
99
+ id: config.id?.(),
100
+ invalid: config.invalid?.(),
101
+ required: config.required?.(),
102
+ error: config.error?.(),
103
+ hint: config.hint?.(),
104
+ ariaLabel: config.ariaLabel?.(),
105
+ })
106
+
107
+ return {
108
+ /** Whether files are being dragged over the dropzone. */
109
+ get dragging() { return dragging },
110
+ /** Whether interaction is allowed. */
111
+ get isInteractive() { return isInteractive },
112
+ /** Selected files (controlled value). */
113
+ get files() { return config.files() },
114
+ addFiles,
115
+ removeAt,
116
+ clear,
117
+ setDragging,
118
+ /** Spread onto the dropzone element (click opens the picker; Enter/Space too).
119
+ * Wire drag events yourself (they carry a DataTransfer): call
120
+ * `setDragging(true/false)` and `addFiles([...e.dataTransfer.files])`. */
121
+ dropzoneProps: () => ({
122
+ role: 'button' as const,
123
+ tabindex: isInteractive ? 0 : -1,
124
+ 'data-dragging': dragging ? '' : undefined,
125
+ 'aria-disabled': !isInteractive || undefined,
126
+ ...editorAria(ariaState()),
127
+ }),
128
+ /** Spread onto the visually-hidden <input type="file">. */
129
+ inputProps: () => ({
130
+ type: 'file' as const,
131
+ accept: accept(),
132
+ multiple: multiple(),
133
+ disabled: !isInteractive,
134
+ tabindex: -1,
135
+ }),
136
+ /** Spread onto a selected file's remove <button> at `index`. */
137
+ removeProps: (index: number) => ({
138
+ type: 'button' as const,
139
+ onclick: () => removeAt(index),
140
+ }),
141
+ }
142
+ }
143
+
144
+ export type FileUpload = ReturnType<typeof createFileUpload>
@@ -1,42 +1,42 @@
1
- import { createSvGridCore } from './core'
2
- import type {
3
- RowData,
4
- SvGrid,
5
- SvGridOptions,
6
- TableFeatures,
7
- } from './core'
8
-
9
- export type SvelteGrid<
10
- TFeatures extends TableFeatures,
11
- TData extends RowData,
12
- TSelected = {},
13
- > = SvGrid<TData> & {
14
- readonly state: Readonly<TSelected>
15
- }
16
-
17
- export function createSvGrid<
18
- TFeatures extends TableFeatures,
19
- TData extends RowData,
20
- TSelected = {},
21
- >(
22
- gridOptions: SvGridOptions<TFeatures, TData>,
23
- selector: (state: Record<string, any>) => TSelected = () => ({}) as TSelected,
24
- ): SvelteGrid<TFeatures, TData, TSelected> {
25
- const grid = createSvGridCore(gridOptions) as SvelteGrid<TFeatures, TData, TSelected>
26
- let selected = $state(selector(grid.store.state))
27
- grid.store.subscribe(() => {
28
- selected = selector(grid.store.state)
29
- })
30
-
31
- Object.defineProperty(grid, 'state', {
32
- get() {
33
- return selected
34
- },
35
- configurable: true,
36
- enumerable: true,
37
- })
38
-
39
- return grid
40
- }
41
-
42
- export const createGrid = createSvGrid
1
+ import { createSvGridCore } from './core'
2
+ import type {
3
+ RowData,
4
+ SvGrid,
5
+ SvGridOptions,
6
+ TableFeatures,
7
+ } from './core'
8
+
9
+ export type SvelteGrid<
10
+ TFeatures extends TableFeatures,
11
+ TData extends RowData,
12
+ TSelected = {},
13
+ > = SvGrid<TData> & {
14
+ readonly state: Readonly<TSelected>
15
+ }
16
+
17
+ export function createSvGrid<
18
+ TFeatures extends TableFeatures,
19
+ TData extends RowData,
20
+ TSelected = {},
21
+ >(
22
+ gridOptions: SvGridOptions<TFeatures, TData>,
23
+ selector: (state: Record<string, any>) => TSelected = () => ({}) as TSelected,
24
+ ): SvelteGrid<TFeatures, TData, TSelected> {
25
+ const grid = createSvGridCore(gridOptions) as SvelteGrid<TFeatures, TData, TSelected>
26
+ let selected = $state(selector(grid.store.state))
27
+ grid.store.subscribe(() => {
28
+ selected = selector(grid.store.state)
29
+ })
30
+
31
+ Object.defineProperty(grid, 'state', {
32
+ get() {
33
+ return selected
34
+ },
35
+ configurable: true,
36
+ enumerable: true,
37
+ })
38
+
39
+ return grid
40
+ }
41
+
42
+ export const createGrid = createSvGrid
@@ -1,10 +1,10 @@
1
- import { describe, expect, it } from 'vitest'
2
- import { createGridState } from './index'
3
-
4
- describe('createGrid', () => {
5
- it('createGridState updates controlled values', () => {
6
- const [sorting, setSorting] = createGridState([{ id: 'age', desc: false }])
7
- setSorting((prev) => prev.map((entry) => ({ ...entry, desc: true })))
8
- expect(sorting()[0]?.desc).toBe(true)
9
- })
10
- })
1
+ import { describe, expect, it } from 'vitest'
2
+ import { createGridState } from './index'
3
+
4
+ describe('createGrid', () => {
5
+ it('createGridState updates controlled values', () => {
6
+ const [sorting, setSorting] = createGridState([{ id: 'age', desc: false }])
7
+ setSorting((prev) => prev.map((entry) => ({ ...entry, desc: true })))
8
+ expect(sorting()[0]?.desc).toBe(true)
9
+ })
10
+ })
@@ -1,17 +1,17 @@
1
- import type { Updater } from './core'
2
-
3
- export function createGridState<TState>(
4
- initialValue: TState,
5
- ): [() => TState, (updater: Updater<TState>) => void] {
6
- let value = $state(initialValue)
7
-
8
- return [
9
- () => value,
10
- (updater: Updater<TState>) => {
11
- if (updater instanceof Function) value = updater(value)
12
- else value = updater
13
- },
14
- ]
15
- }
16
-
17
- export const createSvGridState = createGridState
1
+ import type { Updater } from './core'
2
+
3
+ export function createGridState<TState>(
4
+ initialValue: TState,
5
+ ): [() => TState, (updater: Updater<TState>) => void] {
6
+ let value = $state(initialValue)
7
+
8
+ return [
9
+ () => value,
10
+ (updater: Updater<TState>) => {
11
+ if (updater instanceof Function) value = updater(value)
12
+ else value = updater
13
+ },
14
+ ]
15
+ }
16
+
17
+ export const createSvGridState = createGridState
@@ -22,7 +22,8 @@
22
22
  *
23
23
  * The styled <SvListBox> is just one renderer over this core.
24
24
  */
25
- import type { ListOption } from './list-option'
25
+ import { createTypeaheadBuffer, isTypeaheadKey, nextTypeaheadIndex, type ListOption } from './list-option'
26
+ import { editorAria, type EditorAriaState } from './editor-contract'
26
27
 
27
28
  export type ListboxValue = string | number | Array<string | number> | null
28
29
 
@@ -35,6 +36,12 @@ export type ListboxConfig = {
35
36
  multiple?: () => boolean
36
37
  disabled?: () => boolean
37
38
  ariaLabel?: () => string | undefined
39
+ // Editor contract (ARIA + validation) - folded into rootProps().
40
+ id?: () => string | undefined
41
+ invalid?: () => boolean
42
+ required?: () => boolean
43
+ error?: () => string | undefined
44
+ hint?: () => string | undefined
38
45
  }
39
46
 
40
47
  export type OptionProps = {
@@ -51,10 +58,14 @@ export type OptionProps = {
51
58
 
52
59
  export type ListboxRootProps = {
53
60
  role: 'listbox'
61
+ id: string | undefined
54
62
  'aria-multiselectable': boolean
55
63
  'aria-label': string | undefined
56
64
  'aria-disabled': boolean
57
65
  'aria-activedescendant': string | undefined
66
+ 'aria-invalid': 'true' | undefined
67
+ 'aria-required': 'true' | undefined
68
+ 'aria-describedby': string | undefined
58
69
  tabindex: number
59
70
  onkeydown: (e: KeyboardEvent) => void
60
71
  }
@@ -136,6 +147,14 @@ export function createListbox(config: ListboxConfig): Listbox {
136
147
  const first = () => { active = enabledIdx[0] ?? 0 }
137
148
  const last = () => { active = enabledIdx.at(-1) ?? 0 }
138
149
 
150
+ // Type-ahead: typing a label prefix jumps the active highlight to it.
151
+ const typeahead = createTypeaheadBuffer()
152
+ function onTypeahead(char: string) {
153
+ const buffer = typeahead.push(char.toLowerCase())
154
+ const next = nextTypeaheadIndex(opts(), buffer, active)
155
+ if (next >= 0) active = next
156
+ }
157
+
139
158
  function onKeydown(e: KeyboardEvent) {
140
159
  if (disabled()) return
141
160
  switch (e.key) {
@@ -145,9 +164,20 @@ export function createListbox(config: ListboxConfig): Listbox {
145
164
  case 'End': e.preventDefault(); last(); break
146
165
  case ' ':
147
166
  case 'Enter': e.preventDefault(); pick(active); break
167
+ default: if (isTypeaheadKey(e)) onTypeahead(e.key)
148
168
  }
149
169
  }
150
170
 
171
+ // Editor-contract ARIA state, folded onto the focusable listbox root.
172
+ const ariaState = (): EditorAriaState => ({
173
+ id: config.id?.(),
174
+ invalid: config.invalid?.(),
175
+ required: config.required?.(),
176
+ error: config.error?.(),
177
+ hint: config.hint?.(),
178
+ ariaLabel: config.ariaLabel?.(),
179
+ })
180
+
151
181
  return {
152
182
  get activeIndex() { return active },
153
183
  get selectedValues() { return selected },
@@ -160,11 +190,13 @@ export function createListbox(config: ListboxConfig): Listbox {
160
190
  last,
161
191
  onKeydown,
162
192
  rootProps: () => ({
163
- role: 'listbox',
193
+ role: 'listbox' as const,
194
+ id: config.id?.(),
164
195
  'aria-multiselectable': multiple(),
165
- 'aria-label': config.ariaLabel?.(),
166
196
  'aria-disabled': disabled(),
167
197
  'aria-activedescendant': opts()[active] ? optionId(active) : undefined,
198
+ // aria-label + aria-invalid/required/describedby from the editor contract.
199
+ ...editorAria(ariaState()),
168
200
  tabindex: disabled() ? -1 : 0,
169
201
  onkeydown: onKeydown,
170
202
  }),
@@ -16,6 +16,7 @@
16
16
  * The styled <SvMaskedInput> is just one renderer over this core.
17
17
  */
18
18
  import { applyMask, unmask, isMaskComplete } from './datetime/mask'
19
+ import { editorAria, type EditorAriaState } from './editor-contract'
19
20
 
20
21
  /** Reactive inputs are passed as getters so the core tracks live prop changes. */
21
22
  export type MaskedInputConfig = {
@@ -26,6 +27,12 @@ export type MaskedInputConfig = {
26
27
  placeholder?: () => string | undefined
27
28
  disabled?: () => boolean
28
29
  readonly?: () => boolean
30
+ // Editor contract (ARIA + validation) - folded into inputProps().
31
+ id?: () => string | undefined
32
+ invalid?: () => boolean
33
+ required?: () => boolean
34
+ error?: () => string | undefined
35
+ hint?: () => string | undefined
29
36
  ariaLabel?: () => string | undefined
30
37
  }
31
38
 
@@ -58,6 +65,15 @@ export function createMaskedInput(config: MaskedInputConfig) {
58
65
  config.onChange?.(masked, raw, m ? isMaskComplete(masked, m) : true)
59
66
  }
60
67
 
68
+ const ariaState = (): EditorAriaState => ({
69
+ id: config.id?.(),
70
+ invalid: config.invalid?.(),
71
+ required: config.required?.(),
72
+ error: config.error?.(),
73
+ hint: config.hint?.(),
74
+ ariaLabel: config.ariaLabel?.(),
75
+ })
76
+
61
77
  return {
62
78
  /** The current masked display text. */
63
79
  get masked() { return text },
@@ -67,12 +83,13 @@ export function createMaskedInput(config: MaskedInputConfig) {
67
83
  get complete() { return mask() ? isMaskComplete(text, mask()) : true },
68
84
  /** Spread onto the text input element. */
69
85
  inputProps: () => ({
86
+ id: config.id?.(),
70
87
  value: text,
71
88
  type: 'text' as const,
72
89
  placeholder: config.placeholder?.() ?? mask(),
73
90
  disabled: disabled(),
74
91
  readonly: readonly(),
75
- 'aria-label': config.ariaLabel?.(),
92
+ ...editorAria(ariaState()),
76
93
  oninput: onInput,
77
94
  }),
78
95
  }
@@ -39,6 +39,7 @@ export type NumberInputConfig = {
39
39
  invalid?: () => boolean
40
40
  required?: () => boolean
41
41
  error?: () => string | undefined
42
+ hint?: () => string | undefined
42
43
  ariaLabel?: () => string | undefined
43
44
  }
44
45
 
@@ -138,6 +139,7 @@ export function createNumberInput(config: NumberInputConfig) {
138
139
  invalid: config.invalid?.(),
139
140
  required: config.required?.(),
140
141
  error: config.error?.(),
142
+ hint: config.hint?.(),
141
143
  ariaLabel: config.ariaLabel?.(),
142
144
  })
143
145
 
@@ -15,6 +15,7 @@
15
15
  *
16
16
  * The styled <SvPasswordInput> is just one renderer over this core.
17
17
  */
18
+ import { editorAria, type EditorAriaState } from './editor-contract'
18
19
 
19
20
  export const STRENGTH_LABELS = ['', 'Weak', 'Fair', 'Good', 'Strong']
20
21
 
@@ -36,8 +37,21 @@ export type PasswordInputConfig = {
36
37
  placeholder?: () => string | undefined
37
38
  disabled?: () => boolean
38
39
  readonly?: () => boolean
39
- ariaLabel?: () => string | undefined
40
40
  autocomplete?: () => string | undefined
41
+ // Localizable strings (fall back to the built-in English defaults).
42
+ /** Accessible label for the reveal toggle when the value is hidden. */
43
+ showLabel?: () => string | undefined
44
+ /** Accessible label for the reveal toggle when the value is shown. */
45
+ hideLabel?: () => string | undefined
46
+ /** Strength labels indexed 0-4 (index 0 unused; 1..4 = weak..strong). */
47
+ strengthLabels?: () => readonly string[]
48
+ // Editor contract (ARIA + validation) - folded into inputProps().
49
+ id?: () => string | undefined
50
+ invalid?: () => boolean
51
+ required?: () => boolean
52
+ error?: () => string | undefined
53
+ hint?: () => string | undefined
54
+ ariaLabel?: () => string | undefined
41
55
  }
42
56
 
43
57
  export function createPasswordInput(config: PasswordInputConfig) {
@@ -53,29 +67,41 @@ export function createPasswordInput(config: PasswordInputConfig) {
53
67
  }
54
68
  const toggle = () => (revealed = !revealed)
55
69
 
70
+ const ariaState = (): EditorAriaState => ({
71
+ id: config.id?.(),
72
+ invalid: config.invalid?.(),
73
+ required: config.required?.(),
74
+ error: config.error?.(),
75
+ hint: config.hint?.(),
76
+ ariaLabel: config.ariaLabel?.(),
77
+ })
78
+
56
79
  return {
57
80
  /** Whether the value is currently shown as plain text. */
58
81
  get revealed() { return revealed },
59
82
  /** Strength score, 0-4. */
60
83
  get strength() { return strength },
61
- /** Human label for the strength score. */
62
- get strengthLabel() { return STRENGTH_LABELS[strength] },
84
+ /** Human label for the strength score (localizable via `strengthLabels`). */
85
+ get strengthLabel() { return (config.strengthLabels?.() ?? STRENGTH_LABELS)[strength] },
63
86
  toggle,
64
87
  /** Spread onto the text/password input element. */
65
88
  inputProps: () => ({
89
+ id: config.id?.(),
66
90
  value: config.value(),
67
91
  type: (revealed ? 'text' : 'password') as 'text' | 'password',
68
92
  placeholder: config.placeholder?.(),
69
93
  disabled: disabled(),
70
94
  readonly: readonly(),
71
95
  autocomplete: (config.autocomplete?.() ?? 'current-password') as AutoFill,
72
- 'aria-label': config.ariaLabel?.(),
96
+ ...editorAria(ariaState()),
73
97
  oninput: onInput,
74
98
  }),
75
99
  /** Spread onto the reveal (show/hide) toggle button. */
76
100
  toggleProps: () => ({
77
101
  type: 'button' as const,
78
- 'aria-label': revealed ? 'Hide password' : 'Show password',
102
+ 'aria-label': revealed
103
+ ? (config.hideLabel?.() ?? 'Hide password')
104
+ : (config.showLabel?.() ?? 'Show password'),
79
105
  'aria-pressed': revealed,
80
106
  disabled: disabled(),
81
107
  tabindex: -1,