@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
package/dist/columns.js CHANGED
@@ -16,9 +16,10 @@ export function createColumns(ctx) {
16
16
  return "";
17
17
  }
18
18
  function isColumnPinned(columnId) {
19
- if (ctx.columnPinning.left.includes(columnId))
19
+ const pinning = ctx.effectivePinning ?? ctx.columnPinning;
20
+ if (pinning.left.includes(columnId))
20
21
  return "left";
21
- if (ctx.columnPinning.right.includes(columnId))
22
+ if (pinning.right.includes(columnId))
22
23
  return "right";
23
24
  return null;
24
25
  }
package/dist/core.d.ts CHANGED
@@ -160,6 +160,12 @@ export type ColumnDef<TFeatures extends TableFeatures, TData extends RowData> =
160
160
  * this from the first data row for columns that declare neither.
161
161
  */
162
162
  cellDataType?: 'text' | 'number' | 'boolean' | 'date' | 'dateString';
163
+ /**
164
+ * Hide this column when the grid's `responsive` mode is on and the grid is
165
+ * narrower than this many pixels - drop low-priority columns on small
166
+ * screens. No effect unless the grid has `responsive` set.
167
+ */
168
+ hideBelow?: number;
163
169
  /**
164
170
  * For a column INSIDE a collapsible column group: `'open'` shows this column
165
171
  * only while the group is expanded, `'closed'` only while collapsed. Omit to
@@ -173,7 +179,7 @@ export type ColumnDef<TFeatures extends TableFeatures, TData extends RowData> =
173
179
  * and `columnGroupShow: 'closed'` children show until the user expands it.
174
180
  */
175
181
  openByDefault?: boolean;
176
- editorType?: 'text' | 'number' | 'date' | 'datetime' | 'time' | 'date-native' | 'datetime-native' | 'time-native' | 'password' | 'checkbox' | 'list' | 'chips' | 'select' | 'rich-select' | 'autocomplete' | 'textarea' | 'color' | 'rating';
182
+ editorType?: 'text' | 'number' | 'date' | 'datetime' | 'time' | 'date-native' | 'datetime-native' | 'time-native' | 'password' | 'checkbox' | 'list' | 'chips' | 'select' | 'rich-select' | 'autocomplete' | 'textarea' | 'color' | 'rating' | (string & {});
177
183
  /**
178
184
  * Custom in-cell editor. Receives the cell context PLUS a `commit(value)`
179
185
  * and `cancel()` helper. Use when none of the built-in `editorType`s fit;
@@ -12,4 +12,16 @@ export type Country = {
12
12
  /** Regional-indicator flag emoji from an ISO alpha-2 code. */
13
13
  export declare function flagEmoji(code: string): string;
14
14
  export declare const COUNTRIES: Country[];
15
+ /**
16
+ * Expected national (post-dial-code) significant-digit count per country, as an
17
+ * exact length or an inclusive [min, max] range. A pragmatic length-based check
18
+ * (not full libphonenumber). Countries without an entry accept any non-empty
19
+ * number.
20
+ */
21
+ export declare const PHONE_NATIONAL_LENGTHS: Record<string, number | [number, number]>;
22
+ /**
23
+ * Whether `nationalDigits` is a plausible national number for `code` (length
24
+ * check). Unknown countries pass on any non-empty input. Pure.
25
+ */
26
+ export declare function phoneDigitsValid(code: string, nationalDigits: string): boolean;
15
27
  export declare const COUNTRY_BY_CODE: Map<string, Country>;
package/dist/countries.js CHANGED
@@ -58,4 +58,28 @@ export const COUNTRIES = [
58
58
  { code: 'CO', name: 'Colombia', dial: '+57' },
59
59
  { code: 'MX', name: 'Mexico', dial: '+52' },
60
60
  ];
61
+ /**
62
+ * Expected national (post-dial-code) significant-digit count per country, as an
63
+ * exact length or an inclusive [min, max] range. A pragmatic length-based check
64
+ * (not full libphonenumber). Countries without an entry accept any non-empty
65
+ * number.
66
+ */
67
+ export const PHONE_NATIONAL_LENGTHS = {
68
+ US: 10, CA: 10, GB: 10, IE: 9, FR: 9, DE: [10, 11], ES: 9, IT: [9, 10], NL: 9, BE: [8, 9],
69
+ CH: 9, AT: [10, 12], SE: [7, 9], NO: 8, DK: 8, FI: [9, 10], PL: 9, PT: 9, GR: 10, CZ: 9,
70
+ RU: 10, TR: 10, IL: 9, AE: 9, SA: 9, IN: 10, PK: 10, CN: 11, HK: 8, JP: 10, KR: [9, 10],
71
+ SG: 8, MY: [9, 10], TH: 9, ID: [9, 11], PH: 10, VN: 9, AU: 9, NZ: [8, 10], ZA: 9, NG: 10,
72
+ EG: 10, KE: 9, MA: 9, BR: 11, AR: 10, CL: 9, CO: 10, MX: 10,
73
+ };
74
+ /**
75
+ * Whether `nationalDigits` is a plausible national number for `code` (length
76
+ * check). Unknown countries pass on any non-empty input. Pure.
77
+ */
78
+ export function phoneDigitsValid(code, nationalDigits) {
79
+ const n = (nationalDigits.match(/\d/g) ?? []).length;
80
+ const rule = PHONE_NATIONAL_LENGTHS[code.toUpperCase()];
81
+ if (rule == null)
82
+ return n > 0;
83
+ return typeof rule === 'number' ? n === rule : n >= rule[0] && n <= rule[1];
84
+ }
61
85
  export const COUNTRY_BY_CODE = new Map(COUNTRIES.map((c) => [c.code, c]));
@@ -0,0 +1,71 @@
1
+ /**
2
+ * createAccordion - the HEADLESS core behind <SvAccordion>: a WAI-ARIA accordion
3
+ * (collapsible sections) with single- or multiple-expand, roving header focus
4
+ * (Up/Down/Home/End) and full ARIA, exposed as **prop-getters** you spread onto
5
+ * YOUR OWN markup. No styles, no DOM. Parity: Smart `smart-accordion`.
6
+ *
7
+ * ```svelte
8
+ * <script lang="ts">
9
+ * import { createAccordion } from '@svgrid/grid'
10
+ * let expanded = $state<string[]>(['a'])
11
+ * const acc = createAccordion({ items: () => items, expanded: () => expanded, onChange: (ids) => (expanded = ids) })
12
+ * </script>
13
+ * {#each items as it, i (it.id)}
14
+ * <h3><button {...acc.headerProps(i)}>{it.label}</button></h3>
15
+ * {#if acc.isExpanded(it.id)}<div {...acc.panelProps(i)}>...</div>{/if}
16
+ * {/each}
17
+ * ```
18
+ *
19
+ * The styled <SvAccordion> is one renderer over this core. DOM focus movement is
20
+ * a render concern: the component watches `focusTick`/`focusIndex` and calls
21
+ * `.focus()` itself.
22
+ */
23
+ export type AccordionItem = {
24
+ id: string;
25
+ label: string;
26
+ disabled?: boolean;
27
+ };
28
+ /** `single` keeps at most one panel open; `multiple` allows any number. */
29
+ export type AccordionExpandMode = 'single' | 'multiple';
30
+ /** Reactive inputs are passed as getters so the core tracks live prop changes. */
31
+ export type AccordionConfig = {
32
+ items: () => ReadonlyArray<AccordionItem>;
33
+ /** Expanded item ids (controlled). */
34
+ expanded: () => string[];
35
+ onChange?: (expandedIds: string[]) => void;
36
+ expandMode?: () => AccordionExpandMode;
37
+ disabled?: () => boolean;
38
+ dir?: () => 'ltr' | 'rtl' | 'auto' | undefined;
39
+ };
40
+ export declare function createAccordion(config: AccordionConfig): {
41
+ /** Header index that should hold DOM focus after the latest keyboard move. */
42
+ readonly focusIndex: number;
43
+ /** Monotonic counter; changes only on keyboard navigation. */
44
+ readonly focusTick: number;
45
+ /** Currently-expanded item ids. */
46
+ readonly expandedIds: string[];
47
+ isExpanded: (itemId: string) => boolean;
48
+ toggle: (i: number) => void;
49
+ /** Spread onto the accordion root container. */
50
+ rootProps: () => {
51
+ 'data-orientation': "vertical";
52
+ };
53
+ /** Spread onto the header <button> at `index`. */
54
+ headerProps: (index: number) => {
55
+ type: "button";
56
+ id: string;
57
+ 'data-idx': number;
58
+ 'aria-expanded': boolean;
59
+ 'aria-controls': string;
60
+ disabled: true | undefined;
61
+ onclick: () => void;
62
+ onkeydown: (e: KeyboardEvent) => void;
63
+ };
64
+ /** Spread onto the panel/region element at `index`. */
65
+ panelProps: (index: number) => {
66
+ role: "region";
67
+ id: string;
68
+ 'aria-labelledby': string;
69
+ };
70
+ };
71
+ export type Accordion = ReturnType<typeof createAccordion>;
@@ -0,0 +1,99 @@
1
+ let uid = 0;
2
+ export function createAccordion(config) {
3
+ const id = `sv-acc-${uid++}`;
4
+ const items = () => config.items();
5
+ const expandMode = () => config.expandMode?.() ?? 'single';
6
+ const disabled = () => config.disabled?.() ?? false;
7
+ const expandedSet = $derived(new Set(config.expanded()));
8
+ const enabledIdx = $derived(items().map((it, i) => (it.disabled ? -1 : i)).filter((i) => i >= 0));
9
+ let focusIndex = $state(0);
10
+ let focusTick = $state(0);
11
+ const requestFocus = (i) => { focusIndex = i; focusTick++; };
12
+ const headerId = (i) => `${id}-h-${i}`;
13
+ const panelId = (i) => `${id}-p-${i}`;
14
+ const isExpanded = (itemId) => expandedSet.has(itemId);
15
+ function toggle(i) {
16
+ const it = items()[i];
17
+ if (!it || it.disabled || disabled())
18
+ return;
19
+ const open = expandedSet.has(it.id);
20
+ if (expandMode() === 'single') {
21
+ config.onChange?.(open ? [] : [it.id]);
22
+ }
23
+ else {
24
+ const next = new Set(expandedSet);
25
+ open ? next.delete(it.id) : next.add(it.id);
26
+ config.onChange?.([...next]);
27
+ }
28
+ }
29
+ function move(delta) {
30
+ if (!enabledIdx.length)
31
+ return;
32
+ const pos = enabledIdx.indexOf(focusIndex);
33
+ const base = pos < 0 ? 0 : pos;
34
+ const next = enabledIdx[(base + delta + enabledIdx.length) % enabledIdx.length];
35
+ if (next != null)
36
+ requestFocus(next);
37
+ }
38
+ function onHeaderKeydown(e, i) {
39
+ if (disabled())
40
+ return;
41
+ switch (e.key) {
42
+ case 'ArrowDown':
43
+ e.preventDefault();
44
+ move(1);
45
+ break;
46
+ case 'ArrowUp':
47
+ e.preventDefault();
48
+ move(-1);
49
+ break;
50
+ case 'Home':
51
+ e.preventDefault();
52
+ requestFocus(enabledIdx[0] ?? 0);
53
+ break;
54
+ case 'End':
55
+ e.preventDefault();
56
+ requestFocus(enabledIdx.at(-1) ?? 0);
57
+ break;
58
+ case 'Enter':
59
+ case ' ':
60
+ e.preventDefault();
61
+ toggle(i);
62
+ break;
63
+ }
64
+ }
65
+ return {
66
+ /** Header index that should hold DOM focus after the latest keyboard move. */
67
+ get focusIndex() { return focusIndex; },
68
+ /** Monotonic counter; changes only on keyboard navigation. */
69
+ get focusTick() { return focusTick; },
70
+ /** Currently-expanded item ids. */
71
+ get expandedIds() { return [...expandedSet]; },
72
+ isExpanded,
73
+ toggle,
74
+ /** Spread onto the accordion root container. */
75
+ rootProps: () => ({
76
+ 'data-orientation': 'vertical',
77
+ }),
78
+ /** Spread onto the header <button> at `index`. */
79
+ headerProps: (index) => {
80
+ const it = items()[index];
81
+ return {
82
+ type: 'button',
83
+ id: headerId(index),
84
+ 'data-idx': index,
85
+ 'aria-expanded': it ? isExpanded(it.id) : false,
86
+ 'aria-controls': panelId(index),
87
+ disabled: disabled() || it?.disabled || undefined,
88
+ onclick: () => toggle(index),
89
+ onkeydown: (e) => onHeaderKeydown(e, index),
90
+ };
91
+ },
92
+ /** Spread onto the panel/region element at `index`. */
93
+ panelProps: (index) => ({
94
+ role: 'region',
95
+ id: panelId(index),
96
+ 'aria-labelledby': headerId(index),
97
+ }),
98
+ };
99
+ }
@@ -31,6 +31,11 @@ export type AutocompleteConfig = {
31
31
  ariaLabel?: () => string | undefined;
32
32
  /** DOM focus hook provided by the renderer; the core never touches the DOM. */
33
33
  focusInput?: () => void;
34
+ id?: () => string | undefined;
35
+ invalid?: () => boolean;
36
+ required?: () => boolean;
37
+ error?: () => string | undefined;
38
+ hint?: () => string | undefined;
34
39
  };
35
40
  export declare function createAutocomplete(config: AutocompleteConfig): {
36
41
  /** Panel open state. */
@@ -50,15 +55,19 @@ export declare function createAutocomplete(config: AutocompleteConfig): {
50
55
  onKeydown: (e: KeyboardEvent) => void;
51
56
  /** Spread onto the text <input>. */
52
57
  inputProps: () => {
53
- role: "combobox";
54
- 'aria-expanded': boolean;
55
- 'aria-autocomplete': "list";
56
- 'aria-label': string | undefined;
57
58
  value: string;
58
59
  disabled: boolean;
59
60
  oninput: (e: Event) => void;
60
61
  onfocus: () => void;
61
62
  onkeydown: (e: KeyboardEvent) => void;
63
+ 'aria-invalid': "true" | undefined;
64
+ 'aria-required': "true" | undefined;
65
+ 'aria-describedby': string | undefined;
66
+ 'aria-label': string | undefined;
67
+ id: string | undefined;
68
+ role: "combobox";
69
+ 'aria-expanded': boolean;
70
+ 'aria-autocomplete': "list";
62
71
  };
63
72
  /** Spread onto the listbox container. */
64
73
  listboxProps: () => {
@@ -20,8 +20,17 @@
20
20
  * ```
21
21
  */
22
22
  import { filterOptions } from './list-option';
23
+ import { editorAria } from './editor-contract';
23
24
  export function createAutocomplete(config) {
24
25
  const minChars = () => config.minChars?.() ?? 1;
26
+ const ariaState = () => ({
27
+ id: config.id?.(),
28
+ invalid: config.invalid?.(),
29
+ required: config.required?.(),
30
+ error: config.error?.(),
31
+ hint: config.hint?.(),
32
+ ariaLabel: config.ariaLabel?.(),
33
+ });
25
34
  let open = $state(false);
26
35
  let active = $state(0);
27
36
  const asOptions = $derived(config.suggestions().map((s) => (typeof s === 'string' ? { value: s, label: s } : s)));
@@ -73,10 +82,11 @@ export function createAutocomplete(config) {
73
82
  onKeydown,
74
83
  /** Spread onto the text <input>. */
75
84
  inputProps: () => ({
85
+ id: config.id?.(),
76
86
  role: 'combobox',
77
87
  'aria-expanded': open,
78
88
  'aria-autocomplete': 'list',
79
- 'aria-label': config.ariaLabel?.(),
89
+ ...editorAria(ariaState()),
80
90
  value: config.value(),
81
91
  disabled: config.disabled?.() ?? false,
82
92
  oninput: onInput,
@@ -0,0 +1,62 @@
1
+ export type ButtonGroupItem = {
2
+ value: string | number;
3
+ label?: string;
4
+ disabled?: boolean;
5
+ };
6
+ /** `single` = radio semantics; `multiple` = toggle set; `none` = action buttons. */
7
+ export type ButtonGroupMode = 'single' | 'multiple' | 'none';
8
+ export type ButtonGroupValue = string | number | Array<string | number> | null;
9
+ /** Reactive inputs are passed as getters so the core tracks live prop changes. */
10
+ export type ButtonGroupConfig = {
11
+ items: () => ReadonlyArray<ButtonGroupItem>;
12
+ value: () => ButtonGroupValue;
13
+ onChange?: (value: string | number | Array<string | number>) => void;
14
+ mode?: () => ButtonGroupMode;
15
+ disabled?: () => boolean;
16
+ orientation?: () => 'horizontal' | 'vertical';
17
+ /** Under `'rtl'` the horizontal Left/Right arrow direction flips. */
18
+ dir?: () => 'ltr' | 'rtl' | 'auto' | undefined;
19
+ id?: () => string | undefined;
20
+ invalid?: () => boolean;
21
+ required?: () => boolean;
22
+ error?: () => string | undefined;
23
+ hint?: () => string | undefined;
24
+ ariaLabel?: () => string | undefined;
25
+ };
26
+ /** Normalize the value to an array (pure). */
27
+ export declare function toGroupArray(value: ButtonGroupValue): Array<string | number>;
28
+ export declare function createButtonGroup(config: ButtonGroupConfig): {
29
+ /** Roving-focus target index (follows the selection in single mode). */
30
+ readonly activeIndex: number;
31
+ /** Selected values as an array (single mode -> 0 or 1 entry). */
32
+ readonly selectedValues: (string | number)[];
33
+ isSelected: (v: string | number) => boolean;
34
+ isActive: (i: number) => boolean;
35
+ pick: (i: number) => void;
36
+ move: (delta: number) => void;
37
+ onKeydown: (e: KeyboardEvent) => void;
38
+ /** Spread onto the group container element. */
39
+ rootProps: () => {
40
+ onkeydown: (e: KeyboardEvent) => void;
41
+ 'aria-invalid': "true" | undefined;
42
+ 'aria-required': "true" | undefined;
43
+ 'aria-describedby': string | undefined;
44
+ 'aria-label': string | undefined;
45
+ role: string;
46
+ id: string | undefined;
47
+ 'aria-orientation': "horizontal" | "vertical";
48
+ };
49
+ /** Spread onto the button element at `index`. */
50
+ buttonProps: (index: number) => {
51
+ type: "button";
52
+ role: "radio" | undefined;
53
+ 'data-idx': number;
54
+ 'aria-checked': boolean | undefined;
55
+ 'aria-pressed': boolean | undefined;
56
+ 'data-selected': string | undefined;
57
+ disabled: true | undefined;
58
+ tabindex: number;
59
+ onclick: () => void;
60
+ };
61
+ };
62
+ export type ButtonGroup = ReturnType<typeof createButtonGroup>;
@@ -0,0 +1,154 @@
1
+ /**
2
+ * createButtonGroup - the HEADLESS core behind <SvButtonGroup>: a segmented
3
+ * button bar with single- or multi-select (or plain action buttons), roving
4
+ * tabindex + full keyboard, exposed as **prop-getters** you spread onto YOUR OWN
5
+ * markup. No styles, no DOM. Parity: Smart `smart-button-group`.
6
+ *
7
+ * ```svelte
8
+ * <script lang="ts">
9
+ * import { createButtonGroup } from '@svgrid/grid'
10
+ * let value = $state<string | null>('day')
11
+ * const g = createButtonGroup({ items: () => items, value: () => value, onChange: (v) => (value = v) })
12
+ * </script>
13
+ * <div {...g.rootProps()}>
14
+ * {#each items as it, i (it.value)}<button {...g.buttonProps(i)}>{it.label}</button>{/each}
15
+ * </div>
16
+ * ```
17
+ *
18
+ * The styled <SvButtonGroup> is one renderer over this core.
19
+ */
20
+ import { editorAria } from './editor-contract';
21
+ /** Normalize the value to an array (pure). */
22
+ export function toGroupArray(value) {
23
+ if (value == null)
24
+ return [];
25
+ return Array.isArray(value) ? [...value] : [value];
26
+ }
27
+ export function createButtonGroup(config) {
28
+ const items = () => config.items();
29
+ const mode = () => config.mode?.() ?? 'single';
30
+ const disabled = () => config.disabled?.() ?? false;
31
+ const isVert = () => (config.orientation?.() ?? 'horizontal') === 'vertical';
32
+ const rtl = () => config.dir?.() === 'rtl';
33
+ const selected = $derived(toGroupArray(config.value()));
34
+ const enabledIdx = $derived(items().map((it, i) => (it.disabled ? -1 : i)).filter((i) => i >= 0));
35
+ const isSelected = (v) => selected.includes(v);
36
+ const selectedIdx = $derived(items().findIndex((it) => isSelected(it.value)));
37
+ // Focus cursor. In single (radio) mode moving the cursor also selects, so the
38
+ // roving-tabindex target follows the selection; multiple/none keep their own
39
+ // cursor in `active`.
40
+ let active = $state(0);
41
+ $effect(() => {
42
+ const it = items()[active];
43
+ if (!it || it.disabled)
44
+ active = enabledIdx[0] ?? 0;
45
+ });
46
+ const cursor = $derived(mode() === 'single' ? (selectedIdx >= 0 ? selectedIdx : enabledIdx[0] ?? 0) : active);
47
+ function pick(i) {
48
+ const it = items()[i];
49
+ if (!it || it.disabled || disabled())
50
+ return;
51
+ active = i;
52
+ if (mode() === 'none') {
53
+ config.onChange?.(it.value);
54
+ return;
55
+ }
56
+ if (mode() === 'multiple') {
57
+ const set = new Set(selected);
58
+ set.has(it.value) ? set.delete(it.value) : set.add(it.value);
59
+ config.onChange?.([...set]);
60
+ }
61
+ else {
62
+ config.onChange?.(it.value);
63
+ }
64
+ }
65
+ function goto(i) {
66
+ // Radio semantics select on move; toggle/action only move focus.
67
+ if (mode() === 'single')
68
+ pick(i);
69
+ else
70
+ active = i;
71
+ }
72
+ function move(delta) {
73
+ if (!enabledIdx.length)
74
+ return;
75
+ const pos = enabledIdx.indexOf(cursor);
76
+ const next = enabledIdx[(pos + delta + enabledIdx.length) % enabledIdx.length];
77
+ if (next != null)
78
+ goto(next);
79
+ }
80
+ function onKeydown(e) {
81
+ if (disabled())
82
+ return;
83
+ const horiz = !isVert();
84
+ const rtlH = horiz && rtl();
85
+ const fwd = horiz ? (rtlH ? 'ArrowLeft' : 'ArrowRight') : 'ArrowDown';
86
+ const back = horiz ? (rtlH ? 'ArrowRight' : 'ArrowLeft') : 'ArrowUp';
87
+ if (e.key === fwd) {
88
+ e.preventDefault();
89
+ move(1);
90
+ }
91
+ else if (e.key === back) {
92
+ e.preventDefault();
93
+ move(-1);
94
+ }
95
+ else if (e.key === 'Home') {
96
+ e.preventDefault();
97
+ goto(enabledIdx[0] ?? 0);
98
+ }
99
+ else if (e.key === 'End') {
100
+ e.preventDefault();
101
+ goto(enabledIdx.at(-1) ?? 0);
102
+ }
103
+ else if (e.key === ' ' || e.key === 'Enter') {
104
+ e.preventDefault();
105
+ pick(cursor);
106
+ }
107
+ }
108
+ const ariaState = () => ({
109
+ id: config.id?.(),
110
+ invalid: config.invalid?.(),
111
+ required: config.required?.(),
112
+ error: config.error?.(),
113
+ hint: config.hint?.(),
114
+ ariaLabel: config.ariaLabel?.(),
115
+ });
116
+ const groupRole = () => (mode() === 'single' ? 'radiogroup' : 'group');
117
+ return {
118
+ /** Roving-focus target index (follows the selection in single mode). */
119
+ get activeIndex() { return cursor; },
120
+ /** Selected values as an array (single mode -> 0 or 1 entry). */
121
+ get selectedValues() { return selected; },
122
+ isSelected,
123
+ isActive: (i) => i === cursor,
124
+ pick,
125
+ move,
126
+ onKeydown,
127
+ /** Spread onto the group container element. */
128
+ rootProps: () => ({
129
+ role: groupRole(),
130
+ id: config.id?.(),
131
+ 'aria-orientation': isVert() ? 'vertical' : 'horizontal',
132
+ ...editorAria(ariaState()),
133
+ onkeydown: onKeydown,
134
+ }),
135
+ /** Spread onto the button element at `index`. */
136
+ buttonProps: (index) => {
137
+ const it = items()[index];
138
+ const on = it ? isSelected(it.value) : false;
139
+ const single = mode() === 'single';
140
+ return {
141
+ type: 'button',
142
+ role: single ? 'radio' : undefined,
143
+ 'data-idx': index,
144
+ 'aria-checked': single ? on : undefined,
145
+ 'aria-pressed': mode() === 'multiple' ? on : undefined,
146
+ 'data-selected': on ? '' : undefined,
147
+ disabled: disabled() || it?.disabled || undefined,
148
+ // Roving tabindex: only the cursor (selection in single mode) is tabbable.
149
+ tabindex: mode() === 'none' ? 0 : index === cursor ? 0 : -1,
150
+ onclick: () => pick(index),
151
+ };
152
+ },
153
+ };
154
+ }
@@ -28,6 +28,7 @@
28
28
  import { type DateLike, type MonthMatrixCell } from './datetime/date-core';
29
29
  import { type SelectionMode } from './datetime/date-selection';
30
30
  import { type RestrictOptions } from './datetime/date-restrict';
31
+ import { type RecurrenceRule } from './recurrence';
31
32
  export type DisplayMode = 'month' | 'year' | 'decade';
32
33
  export type CalendarNameFormat = 'narrow' | 'short' | 'long';
33
34
  /** Selected value(s). Single Date for one/zeroOrOne, array for multi modes. */
@@ -53,6 +54,8 @@ export type CalendarDayState = {
53
54
  outside: boolean;
54
55
  focused: boolean;
55
56
  preview: boolean;
57
+ /** Matches one of the `recurrence` rules (repeat pattern). */
58
+ recurring: boolean;
56
59
  };
57
60
  /** Reactive inputs are passed as getters so the core tracks live prop changes;
58
61
  * callbacks are plain closures. */
@@ -75,6 +78,8 @@ export type CalendarConfig = {
75
78
  dayNameFormat?: () => CalendarNameFormat;
76
79
  monthNameFormat?: () => CalendarNameFormat;
77
80
  dateTooltip?: () => ((date: Date) => string | null | undefined) | undefined;
81
+ /** Repeat pattern(s) - matching days get `dayState().recurring = true`. */
82
+ recurrence?: () => RecurrenceRule | ReadonlyArray<RecurrenceRule> | null;
78
83
  };
79
84
  /** Normalize a calendar value to an ordered day-midnight list (pure). */
80
85
  export declare function normalizeCalendarValue(v: CalendarValue): Date[];
@@ -28,6 +28,7 @@
28
28
  import { addDays, addMonths, addYears, monthMatrix, weekdayOrder, startOfDay, isSameDay, isSameMonth, toDate, decadeRange, } from './datetime/date-core';
29
29
  import { selectDate, isSelected, rangeDays, emptySelection, } from './datetime/date-selection';
30
30
  import { isDisabledDay, isImportant } from './datetime/date-restrict';
31
+ import { matchesRecurrence } from './recurrence';
31
32
  const defaultLocale = () => (typeof navigator !== 'undefined' ? navigator.language : 'en-US');
32
33
  /** Normalize a calendar value to an ordered day-midnight list (pure). */
33
34
  export function normalizeCalendarValue(v) {
@@ -127,6 +128,7 @@ export function createCalendar(config) {
127
128
  outside: !isSameMonth(d, panelMonth),
128
129
  focused: isSameDay(d, focusDate),
129
130
  preview: inPreview(d),
131
+ recurring: matchesRecurrence(d, config.recurrence?.() ?? null),
130
132
  };
131
133
  }
132
134
  const title = $derived(mode === 'month'
@@ -1,31 +1,23 @@
1
- /**
2
- * createCheckbox - the HEADLESS core behind <SvCheckBox>: a controlled tri-state
3
- * checkbox (checked / unchecked / indeterminate, ARIA `checkbox` with
4
- * `aria-checked="mixed"`), exposed as **prop-getters** you spread onto YOUR OWN
5
- * markup. A native <button> supplies Space/Enter activation.
6
- *
7
- * ```svelte
8
- * <script lang="ts">
9
- * import { createCheckbox } from '@svgrid/grid'
10
- * let checked = $state(false)
11
- * const cb = createCheckbox({ checked: () => checked, onChange: (v) => (checked = v) })
12
- * </script>
13
- * <button {...cb.boxProps()}>{cb.checked ? '✓' : ''}</button>
14
- * ```
15
- *
16
- * The styled <SvCheckBox> is just one renderer over this core.
17
- */
18
1
  export type CheckboxConfig = {
19
2
  checked: () => boolean;
20
3
  indeterminate?: () => boolean;
21
4
  onChange?: (checked: boolean) => void;
22
5
  disabled?: () => boolean;
6
+ id?: () => string | undefined;
7
+ invalid?: () => boolean;
8
+ required?: () => boolean;
9
+ error?: () => string | undefined;
10
+ hint?: () => string | undefined;
23
11
  ariaLabel?: () => string | undefined;
24
12
  };
25
13
  export type CheckboxBoxProps = {
26
14
  type: 'button';
27
15
  role: 'checkbox';
16
+ id: string | undefined;
28
17
  'aria-checked': boolean | 'mixed';
18
+ 'aria-invalid': 'true' | undefined;
19
+ 'aria-required': 'true' | undefined;
20
+ 'aria-describedby': string | undefined;
29
21
  'aria-label': string | undefined;
30
22
  disabled: boolean;
31
23
  'data-checked': '' | undefined;
@@ -1,3 +1,21 @@
1
+ /**
2
+ * createCheckbox - the HEADLESS core behind <SvCheckBox>: a controlled tri-state
3
+ * checkbox (checked / unchecked / indeterminate, ARIA `checkbox` with
4
+ * `aria-checked="mixed"`), exposed as **prop-getters** you spread onto YOUR OWN
5
+ * markup. A native <button> supplies Space/Enter activation.
6
+ *
7
+ * ```svelte
8
+ * <script lang="ts">
9
+ * import { createCheckbox } from '@svgrid/grid'
10
+ * let checked = $state(false)
11
+ * const cb = createCheckbox({ checked: () => checked, onChange: (v) => (checked = v) })
12
+ * </script>
13
+ * <button {...cb.boxProps()}>{cb.checked ? '✓' : ''}</button>
14
+ * ```
15
+ *
16
+ * The styled <SvCheckBox> is just one renderer over this core.
17
+ */
18
+ import { editorAria } from './editor-contract';
1
19
  export function createCheckbox(config) {
2
20
  const checked = () => config.checked();
3
21
  const indeterminate = () => config.indeterminate?.() ?? false;
@@ -7,6 +25,14 @@ export function createCheckbox(config) {
7
25
  return;
8
26
  config.onChange?.(indeterminate() ? true : !checked());
9
27
  }
28
+ const ariaState = () => ({
29
+ id: config.id?.(),
30
+ invalid: config.invalid?.(),
31
+ required: config.required?.(),
32
+ error: config.error?.(),
33
+ hint: config.hint?.(),
34
+ ariaLabel: config.ariaLabel?.(),
35
+ });
10
36
  return {
11
37
  get checked() { return checked(); },
12
38
  get indeterminate() { return indeterminate(); },
@@ -15,11 +41,12 @@ export function createCheckbox(config) {
15
41
  boxProps: () => ({
16
42
  type: 'button',
17
43
  role: 'checkbox',
44
+ id: config.id?.(),
18
45
  'aria-checked': indeterminate() ? 'mixed' : checked(),
19
- 'aria-label': config.ariaLabel?.(),
20
46
  disabled: disabled(),
21
47
  'data-checked': checked() && !indeterminate() ? '' : undefined,
22
48
  'data-indeterminate': indeterminate() ? '' : undefined,
49
+ ...editorAria(ariaState()),
23
50
  onclick: toggle,
24
51
  }),
25
52
  };