@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
@@ -0,0 +1,100 @@
1
+ <script lang="ts">
2
+ /**
3
+ * SvPagination - a standalone pager (page numbers with ellipsis + prev/next
4
+ * and optional first/last). Pairs with the grid or any paged list. Controlled
5
+ * via `page` + `onChange`; the page-range math lives in the pure `paginate`
6
+ * helper. Parity: Smart pager.
7
+ *
8
+ * ```svelte
9
+ * <SvPagination page={p} pageCount={20} onChange={(n) => (p = n)} />
10
+ * ```
11
+ */
12
+ import { paginationRange } from './paginate'
13
+
14
+ type Props = {
15
+ /** 1-based current page. */
16
+ page: number
17
+ pageCount: number
18
+ onChange?: (page: number) => void
19
+ siblingCount?: number
20
+ boundaryCount?: number
21
+ showFirstLast?: boolean
22
+ showPrevNext?: boolean
23
+ size?: 'sm' | 'md' | 'lg'
24
+ disabled?: boolean
25
+ ariaLabel?: string
26
+ }
27
+
28
+ let {
29
+ page,
30
+ pageCount,
31
+ onChange,
32
+ siblingCount = 1,
33
+ boundaryCount = 1,
34
+ showFirstLast = false,
35
+ showPrevNext = true,
36
+ size = 'md',
37
+ disabled = false,
38
+ ariaLabel = 'Pagination',
39
+ }: Props = $props()
40
+
41
+ const items = $derived(paginationRange({ page, pageCount, siblingCount, boundaryCount }))
42
+ const go = (p: number) => {
43
+ if (disabled) return
44
+ const next = Math.min(Math.max(p, 1), pageCount)
45
+ if (next !== page) onChange?.(next)
46
+ }
47
+ </script>
48
+
49
+ <nav class="sv-pg sv-pg--{size}" aria-label={ariaLabel}>
50
+ <ul class="sv-pg__list">
51
+ {#if showFirstLast}
52
+ <li><button type="button" class="sv-pg__btn" aria-label="First page" onclick={() => go(1)} disabled={disabled || page <= 1}>&laquo;</button></li>
53
+ {/if}
54
+ {#if showPrevNext}
55
+ <li><button type="button" class="sv-pg__btn" aria-label="Previous page" onclick={() => go(page - 1)} disabled={disabled || page <= 1}>&lsaquo;</button></li>
56
+ {/if}
57
+ {#each items as it, i (typeof it === 'number' ? `p${it}` : `${it}-${i}`)}
58
+ {#if it === 'ellipsis-left' || it === 'ellipsis-right'}
59
+ <li><span class="sv-pg__ellipsis" aria-hidden="true">&hellip;</span></li>
60
+ {:else}
61
+ <li>
62
+ <button
63
+ type="button"
64
+ class="sv-pg__btn"
65
+ class:is-active={it === page}
66
+ aria-current={it === page ? 'page' : undefined}
67
+ aria-label={`Page ${it}`}
68
+ {disabled}
69
+ onclick={() => go(it)}
70
+ >{it}</button>
71
+ </li>
72
+ {/if}
73
+ {/each}
74
+ {#if showPrevNext}
75
+ <li><button type="button" class="sv-pg__btn" aria-label="Next page" onclick={() => go(page + 1)} disabled={disabled || page >= pageCount}>&rsaquo;</button></li>
76
+ {/if}
77
+ {#if showFirstLast}
78
+ <li><button type="button" class="sv-pg__btn" aria-label="Last page" onclick={() => go(pageCount)} disabled={disabled || page >= pageCount}>&raquo;</button></li>
79
+ {/if}
80
+ </ul>
81
+ </nav>
82
+
83
+ <style>
84
+ .sv-pg { --_accent: var(--sg-accent, #2563eb); }
85
+ .sv-pg__list { display: flex; align-items: center; gap: 4px; list-style: none; margin: 0; padding: 0; }
86
+ .sv-pg__btn {
87
+ display: inline-grid; place-items: center; box-sizing: border-box;
88
+ min-width: 32px; height: 32px; padding: 0 7px;
89
+ background: var(--sg-input-bg, #fff); color: var(--sg-fg, #0f172a);
90
+ border: 1px solid var(--sg-border, #cbd5e1); border-radius: var(--sg-radius, 8px);
91
+ font: inherit; font-size: 13px; cursor: pointer; transition: background 0.12s, border-color 0.12s;
92
+ }
93
+ .sv-pg--sm .sv-pg__btn { min-width: 28px; height: 28px; font-size: 12px; }
94
+ .sv-pg--lg .sv-pg__btn { min-width: 38px; height: 38px; font-size: 14px; }
95
+ .sv-pg__btn:hover:not(:disabled):not(.is-active) { background: var(--sg-row-hover-bg, #f1f5f9); border-color: color-mix(in srgb, var(--_accent) 40%, var(--sg-border, #cbd5e1)); }
96
+ .sv-pg__btn:focus-visible { outline: none; box-shadow: 0 0 0 2px color-mix(in srgb, var(--_accent) 30%, transparent); }
97
+ .sv-pg__btn.is-active { background: var(--_accent); border-color: var(--_accent); color: var(--sg-on-accent, #fff); font-weight: 650; }
98
+ .sv-pg__btn:disabled { opacity: 0.45; cursor: not-allowed; }
99
+ .sv-pg__ellipsis { display: inline-grid; place-items: center; min-width: 32px; height: 32px; color: var(--sg-muted, #64748b); }
100
+ </style>
@@ -6,22 +6,28 @@
6
6
  * The styled renderer over the headless `createPasswordInput` core: the reveal
7
7
  * toggle + strength heuristic come from the core, spread here via prop-getters.
8
8
  */
9
+ import SvField from './SvField.svelte'
10
+ import { nextEditorId, resolveMessages, type SvEditorProps } from './editor-contract'
9
11
  import { createPasswordInput } from './createPasswordInput.svelte'
10
12
 
11
- type Props = {
13
+ /** User-facing strings for the password input (localizable via `messages`). */
14
+ type PasswordMessages = { show: string; hide: string; weak: string; fair: string; good: string; strong: string }
15
+ const DEFAULT_MESSAGES: PasswordMessages = {
16
+ show: 'Show password', hide: 'Hide password',
17
+ weak: 'Weak', fair: 'Fair', good: 'Good', strong: 'Strong',
18
+ }
19
+
20
+ type Props = SvEditorProps & {
12
21
  value?: string
13
22
  onChange?: (value: string) => void
14
23
  placeholder?: string
15
- disabled?: boolean
16
- readonly?: boolean
17
24
  /** Show the show/hide eye toggle. */
18
25
  revealable?: boolean
19
26
  /** Show a 4-level strength meter. */
20
27
  showStrength?: boolean
21
- name?: string
22
- size?: 'sm' | 'md' | 'lg'
23
- ariaLabel?: string
24
28
  autocomplete?: string
29
+ /** Override the built-in strings (reveal toggle + strength labels). */
30
+ messages?: Partial<PasswordMessages>
25
31
  }
26
32
 
27
33
  let {
@@ -35,9 +41,21 @@
35
41
  name,
36
42
  size = 'md',
37
43
  ariaLabel,
44
+ invalid = false,
45
+ required = false,
46
+ error,
47
+ label,
48
+ hint,
49
+ dir,
50
+ id,
38
51
  autocomplete = 'current-password',
52
+ messages,
39
53
  }: Props = $props()
40
54
 
55
+ const autoId = nextEditorId('sv-pass')
56
+ const uid = $derived(id ?? autoId)
57
+ const M = $derived(resolveMessages(DEFAULT_MESSAGES, messages))
58
+
41
59
  const pw = createPasswordInput({
42
60
  value: () => value,
43
61
  onChange: (v) => onChange?.(v),
@@ -46,11 +64,20 @@
46
64
  readonly: () => readonly,
47
65
  ariaLabel: () => ariaLabel,
48
66
  autocomplete: () => autocomplete,
67
+ showLabel: () => M.show,
68
+ hideLabel: () => M.hide,
69
+ strengthLabels: () => ['', M.weak, M.fair, M.good, M.strong],
70
+ id: () => uid,
71
+ invalid: () => invalid,
72
+ required: () => required,
73
+ error: () => error,
74
+ hint: () => hint,
49
75
  })
50
76
  </script>
51
77
 
78
+ <SvField id={uid} {label} {hint} {error} {required} {dir}>
52
79
  <div class="sv-pw sv-pw--{size}" class:is-disabled={disabled}>
53
- <div class="sv-pw__field">
80
+ <div class="sv-pw__field" class:is-invalid={invalid}>
54
81
  <input class="sv-pw__input" {...pw.inputProps()} />
55
82
  {#if revealable}
56
83
  <button class="sv-pw__eye" {...pw.toggleProps()}>
@@ -72,6 +99,7 @@
72
99
  {/if}
73
100
  {#if name}<input type="hidden" {name} value={value} />{/if}
74
101
  </div>
102
+ </SvField>
75
103
 
76
104
  <style>
77
105
  .sv-pw { --_accent: var(--sg-accent, #2563eb); display: inline-flex; flex-direction: column; gap: 5px; width: 220px; }
@@ -82,6 +110,8 @@
82
110
  border: 1px solid var(--sg-input-border, var(--sg-border, #cbd5e1)); border-radius: var(--sg-radius, 8px);
83
111
  }
84
112
  .sv-pw__field:focus-within { border-color: var(--_accent); box-shadow: 0 0 0 2px color-mix(in srgb, var(--_accent) 22%, transparent); }
113
+ .sv-pw__field.is-invalid { border-color: var(--sg-danger, #dc2626); }
114
+ .sv-pw__field.is-invalid:focus-within { box-shadow: 0 0 0 2px color-mix(in srgb, var(--sg-danger, #dc2626) 22%, transparent); }
85
115
  .sv-pw__input { flex: 1; min-width: 0; border: 0; background: none; outline: none; color: inherit; font: inherit; padding: 0 10px; }
86
116
  .sv-pw--sm .sv-pw__field { height: 28px; font-size: 12px; }
87
117
  .sv-pw--md .sv-pw__field { height: 34px; font-size: 13px; }
@@ -90,11 +120,11 @@
90
120
  .sv-pw__eye:hover { color: var(--_accent); }
91
121
  .sv-pw__meter { display: flex; gap: 4px; }
92
122
  .sv-pw__bar { flex: 1; height: 4px; border-radius: 2px; background: var(--sg-border, #e2e8f0); transition: background 0.15s; }
93
- .sv-pw__bar.on.is-lvl1 { background: #dc2626; }
94
- .sv-pw__bar.on.is-lvl2 { background: #f59e0b; }
123
+ .sv-pw__bar.on.is-lvl1 { background: var(--sg-danger, #dc2626); }
124
+ .sv-pw__bar.on.is-lvl2 { background: var(--sg-warning, #f59e0b); }
95
125
  .sv-pw__bar.on.is-lvl3 { background: #eab308; }
96
- .sv-pw__bar.on.is-lvl4 { background: #16a34a; }
126
+ .sv-pw__bar.on.is-lvl4 { background: var(--sg-success, #16a34a); }
97
127
  .sv-pw__strength { font-size: 11px; font-weight: 600; color: var(--sg-muted, #64748b); }
98
- .sv-pw__strength.is-lvl1 { color: #dc2626; }
99
- .sv-pw__strength.is-lvl4 { color: #16a34a; }
128
+ .sv-pw__strength.is-lvl1 { color: var(--sg-danger, #dc2626); }
129
+ .sv-pw__strength.is-lvl4 { color: var(--sg-success, #16a34a); }
100
130
  </style>
@@ -8,19 +8,22 @@
8
8
  * state + parsing live in the core, spread here via prop-getters.
9
9
  */
10
10
  import { COUNTRIES, flagEmoji } from './countries'
11
- import { createPhoneInput } from './createPhoneInput.svelte'
11
+ import SvField from './SvField.svelte'
12
+ import { nextEditorId, resolveMessages, type SvEditorProps } from './editor-contract'
13
+ import { createPhoneInput, type PhoneParts } from './createPhoneInput.svelte'
12
14
 
13
- type Props = {
15
+ /** User-facing strings for the phone input (localizable via `messages`). */
16
+ type PhoneMessages = { country: string }
17
+ const DEFAULT_MESSAGES: PhoneMessages = { country: 'Country' }
18
+
19
+ type Props = SvEditorProps & {
14
20
  value?: string
15
- onChange?: (value: string, parts: { country: string; dial: string; national: string }) => void
21
+ onChange?: (value: string, parts: PhoneParts) => void
16
22
  /** Default country ISO code. */
17
23
  country?: string
18
- disabled?: boolean
19
- readonly?: boolean
20
24
  placeholder?: string
21
- name?: string
22
- size?: 'sm' | 'md' | 'lg'
23
- ariaLabel?: string
25
+ /** Override the built-in strings (e.g. the country selector aria-label). */
26
+ messages?: Partial<PhoneMessages>
24
27
  }
25
28
 
26
29
  let {
@@ -33,8 +36,20 @@
33
36
  name,
34
37
  size = 'md',
35
38
  ariaLabel,
39
+ invalid = false,
40
+ required = false,
41
+ error,
42
+ label,
43
+ hint,
44
+ dir,
45
+ id,
46
+ messages,
36
47
  }: Props = $props()
37
48
 
49
+ const autoId = nextEditorId('sv-phone')
50
+ const uid = $derived(id ?? autoId)
51
+ const M = $derived(resolveMessages(DEFAULT_MESSAGES, messages))
52
+
38
53
  const ph = createPhoneInput({
39
54
  value: () => value,
40
55
  onChange: (v, parts) => onChange?.(v, parts),
@@ -42,11 +57,18 @@
42
57
  disabled: () => disabled,
43
58
  readonly: () => readonly,
44
59
  placeholder: () => placeholder,
60
+ countryLabel: () => M.country,
61
+ id: () => uid,
62
+ invalid: () => invalid,
63
+ required: () => required,
64
+ error: () => error,
65
+ hint: () => hint,
45
66
  ariaLabel: () => ariaLabel,
46
67
  })
47
68
  </script>
48
69
 
49
- <div class="sv-phone sv-phone--{size}" class:is-disabled={disabled}>
70
+ <SvField id={uid} {label} {hint} {error} {required} {dir}>
71
+ <div class="sv-phone sv-phone--{size}" class:is-disabled={disabled} class:is-invalid={invalid}>
50
72
  <div class="sv-phone__country">
51
73
  <span class="sv-phone__flag" aria-hidden="true">{ph.flag}</span>
52
74
  <span class="sv-phone__dial">{ph.dial}</span>
@@ -60,6 +82,7 @@
60
82
  <input class="sv-phone__number" {...ph.inputProps()} />
61
83
  {#if name}<input type="hidden" {name} value={ph.value} />{/if}
62
84
  </div>
85
+ </SvField>
63
86
 
64
87
  <style>
65
88
  .sv-phone {
@@ -70,16 +93,25 @@
70
93
  overflow: hidden;
71
94
  }
72
95
  .sv-phone:focus-within { border-color: var(--_accent); box-shadow: 0 0 0 2px color-mix(in srgb, var(--_accent) 22%, transparent); }
96
+ .sv-phone.is-invalid { border-color: var(--sg-danger, #dc2626); }
97
+ .sv-phone.is-invalid:focus-within { box-shadow: 0 0 0 2px color-mix(in srgb, var(--sg-danger, #dc2626) 22%, transparent); }
73
98
  .sv-phone.is-disabled { opacity: 0.6; }
74
99
  .sv-phone__country {
75
100
  position: relative; display: inline-flex; align-items: center; gap: 4px;
76
- padding: 0 6px 0 10px; border-right: 1px solid var(--sg-border, #e2e8f0);
101
+ padding-block: 0; padding-inline: 10px 6px; border-inline-end: 1px solid var(--sg-border, #e2e8f0);
77
102
  background: var(--sg-header-bg, #f8fafc); cursor: pointer;
78
103
  }
79
104
  .sv-phone__flag { font-size: 15px; }
80
105
  .sv-phone__dial { font-size: 13px; font-weight: 600; }
81
106
  .sv-phone__chev { color: var(--sg-muted, #64748b); }
82
- .sv-phone__select { position: absolute; inset: 0; opacity: 0; cursor: pointer; font-size: 13px; }
107
+ /* The native <select> is an invisible overlay, but its option popup is drawn by
108
+ the OS using the control's own color/background - so theme them explicitly or
109
+ dark themes get light text on the default white popup. */
110
+ .sv-phone__select {
111
+ position: absolute; inset: 0; opacity: 0; cursor: pointer; font-size: 13px;
112
+ color: var(--sg-fg, #0f172a); background: var(--sg-bg, #fff);
113
+ }
114
+ .sv-phone__select option { color: var(--sg-fg, #0f172a); background: var(--sg-bg, #fff); }
83
115
  .sv-phone__number { flex: 1; min-width: 0; border: 0; background: none; outline: none; color: inherit; font: inherit; padding: 0 10px; }
84
116
  .sv-phone--sm { height: 28px; font-size: 12px; }
85
117
  .sv-phone--md { height: 34px; font-size: 13px; }
@@ -0,0 +1,127 @@
1
+ <script lang="ts">
2
+ /**
3
+ * SvPopover - a floating panel anchored to a trigger, portalled to <body> so it
4
+ * escapes any `overflow:hidden` ancestor. Open on click (default), hover, or
5
+ * manually via `open`. Flips above the trigger when there's no room below,
6
+ * closes on outside-click / Escape, and animates in. Parity: Smart popover.
7
+ *
8
+ * ```svelte
9
+ * <SvPopover>
10
+ * {#snippet anchor()}<button>Open</button>{/snippet}
11
+ * <p>Panel content</p>
12
+ * </SvPopover>
13
+ * ```
14
+ */
15
+ import type { Snippet } from 'svelte'
16
+ import { anchoredRect, portalToBody, popIn, type AnchoredRect } from './popover'
17
+ import { createDismissableLayer } from './a11y/dismissable'
18
+
19
+ type Props = {
20
+ /** Controlled open state (bindable). */
21
+ open?: boolean
22
+ onOpenChange?: (open: boolean) => void
23
+ /** How the anchor opens the panel. `manual` = only `open` drives it. */
24
+ trigger?: 'click' | 'hover' | 'manual'
25
+ /** Estimated panel height for flip decisions. */
26
+ estimatedHeight?: number
27
+ /** Force a minimum panel width (else it hugs its content). */
28
+ minWidth?: number
29
+ /** Close when clicking outside. Default true. */
30
+ closeOnOutsideClick?: boolean
31
+ ariaLabel?: string
32
+ /** The anchor element(s) that open the panel. */
33
+ anchor?: Snippet
34
+ /** Panel content. */
35
+ children?: Snippet
36
+ }
37
+
38
+ let {
39
+ open = $bindable(false),
40
+ onOpenChange,
41
+ trigger = 'click',
42
+ estimatedHeight = 220,
43
+ minWidth,
44
+ closeOnOutsideClick = true,
45
+ ariaLabel,
46
+ anchor,
47
+ children,
48
+ }: Props = $props()
49
+
50
+ let anchorEl = $state<HTMLSpanElement | null>(null)
51
+ let panelEl = $state<HTMLDivElement | null>(null)
52
+ let rect = $state<AnchoredRect>({ top: 0, left: 0, width: 0, openUpward: false })
53
+
54
+ function setOpen(v: boolean) { if (v !== open) { open = v; onOpenChange?.(v) } }
55
+ function toggle() { setOpen(!open) }
56
+
57
+ function updatePos() {
58
+ if (!anchorEl) return
59
+ rect = anchoredRect(anchorEl.getBoundingClientRect(), { estimatedHeight, minWidth })
60
+ }
61
+
62
+ $effect(() => {
63
+ if (!open) return
64
+ updatePos()
65
+ const rp = () => updatePos()
66
+ window.addEventListener('scroll', rp, true)
67
+ window.addEventListener('resize', rp)
68
+ // Escape + outside-click dismissal via the shared layer stack (so a popover
69
+ // nested in a dialog closes top-first). The trigger is passed alongside the
70
+ // panel so clicking it toggles rather than dismiss-then-reopen.
71
+ const layer = createDismissableLayer({
72
+ element: () => [anchorEl, panelEl],
73
+ onDismiss: () => setOpen(false),
74
+ closeOnOutside: closeOnOutsideClick,
75
+ })
76
+ layer.activate()
77
+ return () => {
78
+ window.removeEventListener('scroll', rp, true)
79
+ window.removeEventListener('resize', rp)
80
+ layer.release()
81
+ }
82
+ })
83
+
84
+ let hoverTimer: ReturnType<typeof setTimeout> | undefined
85
+ function onEnter() { if (trigger === 'hover') { clearTimeout(hoverTimer); setOpen(true) } }
86
+ function onLeave() { if (trigger === 'hover') { hoverTimer = setTimeout(() => setOpen(false), 120) } }
87
+ </script>
88
+
89
+ <!-- svelte-ignore a11y_no_static_element_interactions -->
90
+ <span
91
+ bind:this={anchorEl}
92
+ class="sv-pop__anchor"
93
+ onclick={() => trigger === 'click' && toggle()}
94
+ onpointerenter={onEnter}
95
+ onpointerleave={onLeave}
96
+ >
97
+ {@render anchor?.()}
98
+ </span>
99
+
100
+ {#if open}
101
+ <div
102
+ bind:this={panelEl}
103
+ class="sv-pop__panel"
104
+ use:portalToBody
105
+ use:popIn={{ up: rect.openUpward }}
106
+ style:position="fixed"
107
+ style:top={`${rect.top}px`}
108
+ style:left={`${rect.left}px`}
109
+ style:min-width={minWidth ? `${rect.width}px` : undefined}
110
+ role="dialog"
111
+ aria-label={ariaLabel}
112
+ onpointerenter={onEnter}
113
+ onpointerleave={onLeave}
114
+ >
115
+ {@render children?.()}
116
+ </div>
117
+ {/if}
118
+
119
+ <style>
120
+ .sv-pop__anchor { display: inline-flex; }
121
+ :global(.sv-pop__panel) {
122
+ z-index: 2147483646; max-width: min(92vw, 360px); padding: 12px 14px;
123
+ background: var(--sg-bg, #fff); color: var(--sg-fg, #0f172a);
124
+ border: 1px solid var(--sg-border, #e2e8f0); border-radius: 10px;
125
+ box-shadow: 0 16px 48px -12px rgba(15, 23, 42, 0.35); font-size: 13px; line-height: 1.55;
126
+ }
127
+ </style>
@@ -0,0 +1,116 @@
1
+ <script lang="ts">
2
+ /**
3
+ * SvProgress - a linear progress bar (WAI-ARIA `progressbar`). Determinate
4
+ * (value/max) or `indeterminate` (animated), with color intents, sizes, an
5
+ * optional label and an optional secondary `buffer` track. Theme-driven via
6
+ * `--sg-*`; respects prefers-reduced-motion. Parity: Smart progress bar.
7
+ *
8
+ * ```svelte
9
+ * <SvProgress value={64} showLabel />
10
+ * <SvProgress indeterminate color="success" />
11
+ * ```
12
+ */
13
+ type Props = {
14
+ /** Current value (0..max). Ignored when `indeterminate`. */
15
+ value?: number
16
+ max?: number
17
+ /** Unknown-duration animated bar. */
18
+ indeterminate?: boolean
19
+ /** Buffered/secondary value (e.g. streamed-ahead), 0..max. */
20
+ buffer?: number
21
+ color?: 'accent' | 'success' | 'warning' | 'danger'
22
+ size?: 'sm' | 'md' | 'lg'
23
+ /** Show a percentage label at the end of the bar. */
24
+ showLabel?: boolean
25
+ /** Format the label (default: rounded percent). */
26
+ formatLabel?: (value: number, max: number) => string
27
+ /** Diagonal candy-stripe overlay on the fill. */
28
+ striped?: boolean
29
+ ariaLabel?: string
30
+ }
31
+
32
+ let {
33
+ value = 0,
34
+ max = 100,
35
+ indeterminate = false,
36
+ buffer,
37
+ color = 'accent',
38
+ size = 'md',
39
+ showLabel = false,
40
+ formatLabel,
41
+ striped = false,
42
+ ariaLabel,
43
+ }: Props = $props()
44
+
45
+ const pct = $derived(max > 0 ? Math.min(100, Math.max(0, (value / max) * 100)) : 0)
46
+ const bufPct = $derived(buffer != null && max > 0 ? Math.min(100, Math.max(0, (buffer / max) * 100)) : null)
47
+ const label = $derived(formatLabel ? formatLabel(value, max) : `${Math.round(pct)}%`)
48
+ </script>
49
+
50
+ <div class="sv-prog sv-prog--{size} sv-prog--{color}" class:has-label={showLabel && !indeterminate}>
51
+ <div
52
+ class="sv-prog__track"
53
+ role="progressbar"
54
+ aria-label={ariaLabel}
55
+ aria-valuemin={indeterminate ? undefined : 0}
56
+ aria-valuemax={indeterminate ? undefined : max}
57
+ aria-valuenow={indeterminate ? undefined : value}
58
+ aria-valuetext={indeterminate ? undefined : label}
59
+ >
60
+ {#if bufPct != null && !indeterminate}<div class="sv-prog__buffer" style:width={`${bufPct}%`}></div>{/if}
61
+ <div
62
+ class="sv-prog__fill"
63
+ class:is-indeterminate={indeterminate}
64
+ class:is-striped={striped}
65
+ style:width={indeterminate ? undefined : `${pct}%`}
66
+ ></div>
67
+ </div>
68
+ {#if showLabel && !indeterminate}<span class="sv-prog__label">{label}</span>{/if}
69
+ </div>
70
+
71
+ <style>
72
+ .sv-prog {
73
+ --_accent: var(--sg-accent, #2563eb);
74
+ --_c: var(--_accent);
75
+ display: flex; align-items: center; gap: 10px; width: 100%;
76
+ }
77
+ .sv-prog--success { --_c: var(--sg-success, #16a34a); }
78
+ .sv-prog--warning { --_c: var(--sg-warning, #f59e0b); }
79
+ .sv-prog--danger { --_c: var(--sg-danger, #dc2626); }
80
+ .sv-prog__track {
81
+ position: relative; flex: 1; overflow: hidden;
82
+ background: var(--sg-border, #e2e8f0); border-radius: 999px;
83
+ }
84
+ .sv-prog--sm .sv-prog__track { height: 5px; }
85
+ .sv-prog--md .sv-prog__track { height: 8px; }
86
+ .sv-prog--lg .sv-prog__track { height: 12px; }
87
+ .sv-prog__buffer {
88
+ position: absolute; inset-block: 0; inset-inline-start: 0;
89
+ background: color-mix(in srgb, var(--_c) 28%, transparent); border-radius: 999px;
90
+ }
91
+ .sv-prog__fill {
92
+ position: absolute; inset-block: 0; inset-inline-start: 0; min-width: 0;
93
+ background: var(--_c); border-radius: 999px; transition: width 0.3s cubic-bezier(0.16, 1, 0.3, 1);
94
+ }
95
+ .sv-prog__fill.is-striped {
96
+ background-image: linear-gradient(45deg, rgba(255,255,255,0.22) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.22) 50%, rgba(255,255,255,0.22) 75%, transparent 75%);
97
+ background-size: 16px 16px; animation: sv-prog-stripe 0.8s linear infinite;
98
+ }
99
+ .sv-prog__fill.is-indeterminate {
100
+ width: 40%; border-radius: 999px;
101
+ animation: sv-prog-indet 1.3s cubic-bezier(0.65, 0.05, 0.36, 1) infinite;
102
+ }
103
+ @keyframes sv-prog-indet {
104
+ 0% { inset-inline-start: -45%; } 100% { inset-inline-start: 100%; }
105
+ }
106
+ @keyframes sv-prog-stripe { to { background-position: 16px 0; } }
107
+ @media (prefers-reduced-motion: reduce) {
108
+ .sv-prog__fill.is-indeterminate { animation-duration: 2.4s; }
109
+ .sv-prog__fill.is-striped { animation: none; }
110
+ .sv-prog__fill { transition: none; }
111
+ }
112
+ .sv-prog__label {
113
+ flex: none; min-width: 38px; text-align: end; font-size: 12px; font-weight: 600;
114
+ font-variant-numeric: tabular-nums; color: var(--sg-muted, #64748b);
115
+ }
116
+ </style>
@@ -8,17 +8,15 @@
8
8
  * roving tabindex + arrow-key navigation. Parity: Smart `smart-radio-button`
9
9
  * (as a managed group). Controlled via `value` + `onChange`.
10
10
  */
11
+ import SvField from './SvField.svelte'
12
+ import { nextEditorId, type SvEditorProps } from './editor-contract'
11
13
  import { createRadioGroup, type RadioOption } from './createRadioGroup.svelte'
12
14
 
13
- type Props = {
15
+ type Props = SvEditorProps & {
14
16
  options: ReadonlyArray<RadioOption>
15
17
  value?: string | number | null
16
18
  onChange?: (value: string | number) => void
17
- name?: string
18
- disabled?: boolean
19
19
  orientation?: 'vertical' | 'horizontal'
20
- size?: 'sm' | 'md' | 'lg'
21
- ariaLabel?: string
22
20
  }
23
21
 
24
22
  let {
@@ -30,34 +28,53 @@
30
28
  orientation = 'vertical',
31
29
  size = 'md',
32
30
  ariaLabel,
31
+ invalid = false,
32
+ required = false,
33
+ error,
34
+ label,
35
+ hint,
36
+ dir,
37
+ id,
33
38
  }: Props = $props()
34
39
 
40
+ const autoId = nextEditorId('sv-radio')
41
+ const uid = $derived(id ?? autoId)
42
+
35
43
  // The styled radio group is just a renderer over the headless core.
36
44
  const rg = createRadioGroup({
37
45
  options: () => options,
38
46
  value: () => value,
39
47
  onChange: (v) => onChange?.(v),
40
48
  disabled: () => disabled,
41
- ariaLabel: () => ariaLabel,
49
+ // A visible field `label` also names the group for assistive tech.
50
+ ariaLabel: () => ariaLabel ?? label,
51
+ id: () => uid,
52
+ invalid: () => invalid,
53
+ required: () => required,
54
+ error: () => error,
55
+ hint: () => hint,
42
56
  })
43
57
  </script>
44
58
 
45
- <div
46
- class="sv-radiogroup sv-radiogroup--{orientation} sv-radiogroup--{size}"
47
- {...rg.groupProps()}
48
- >
49
- {#each options as opt (opt.value)}
50
- <button
51
- class="sv-radio"
52
- class:is-checked={opt.value === value}
53
- {...rg.radioProps(opt)}
54
- >
55
- <span class="sv-radio__dot"></span>
56
- <span class="sv-radio__label">{opt.label}</span>
57
- </button>
58
- {/each}
59
- {#if name}<input type="hidden" {name} value={value ?? ''} />{/if}
60
- </div>
59
+ <SvField id={uid} {label} {hint} {error} {required} {dir}>
60
+ <div
61
+ class="sv-radiogroup sv-radiogroup--{orientation} sv-radiogroup--{size}"
62
+ class:is-invalid={invalid}
63
+ {...rg.groupProps()}
64
+ >
65
+ {#each options as opt (opt.value)}
66
+ <button
67
+ class="sv-radio"
68
+ class:is-checked={opt.value === value}
69
+ {...rg.radioProps(opt)}
70
+ >
71
+ <span class="sv-radio__dot"></span>
72
+ <span class="sv-radio__label">{opt.label}</span>
73
+ </button>
74
+ {/each}
75
+ {#if name}<input type="hidden" {name} value={value ?? ''} />{/if}
76
+ </div>
77
+ </SvField>
61
78
 
62
79
  <style>
63
80
  .sv-radiogroup { --_accent: var(--sg-accent, #2563eb); display: flex; gap: 10px; }
@@ -76,6 +93,7 @@
76
93
  border: 1.5px solid var(--sg-border, #cbd5e1); background: var(--sg-input-bg, #fff);
77
94
  display: grid; place-items: center; transition: border-color 0.12s;
78
95
  }
96
+ .sv-radiogroup.is-invalid .sv-radio__dot { border-color: var(--sg-danger, #dc2626); }
79
97
  .sv-radio.is-checked .sv-radio__dot { border-color: var(--_accent); }
80
98
  .sv-radio.is-checked .sv-radio__dot::after {
81
99
  content: ''; width: 9px; height: 9px; border-radius: 50%; background: var(--_accent);