@skdx/docs-kit 0.35.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 (505) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +22 -0
  3. package/dist/component-aliases.json +12 -0
  4. package/dist/data/THIRD-PARTY-NOTICES.md +21 -0
  5. package/dist/data/angular-inputs.json +1 -0
  6. package/dist/data/api-manifest.json +1 -0
  7. package/dist/data/exports-by-framework.json +1 -0
  8. package/dist/data/honoured-slots.json +1 -0
  9. package/dist/data/styling-hooks-manifest.json +10331 -0
  10. package/dist/frameworks.mjs +64 -0
  11. package/dist/shared/contracts/accordion.d.ts +3 -0
  12. package/dist/shared/contracts/accordion.js +1 -0
  13. package/dist/shared/contracts/alert.d.ts +3 -0
  14. package/dist/shared/contracts/alert.js +1 -0
  15. package/dist/shared/contracts/angle-slider.d.ts +3 -0
  16. package/dist/shared/contracts/angle-slider.js +1 -0
  17. package/dist/shared/contracts/aspect-ratio.d.ts +3 -0
  18. package/dist/shared/contracts/aspect-ratio.js +1 -0
  19. package/dist/shared/contracts/autocomplete.d.ts +3 -0
  20. package/dist/shared/contracts/autocomplete.js +1 -0
  21. package/dist/shared/contracts/avatar.d.ts +3 -0
  22. package/dist/shared/contracts/avatar.js +1 -0
  23. package/dist/shared/contracts/badge.d.ts +3 -0
  24. package/dist/shared/contracts/badge.js +1 -0
  25. package/dist/shared/contracts/box.d.ts +3 -0
  26. package/dist/shared/contracts/box.js +1 -0
  27. package/dist/shared/contracts/breadcrumb.d.ts +3 -0
  28. package/dist/shared/contracts/breadcrumb.js +1 -0
  29. package/dist/shared/contracts/button.d.ts +3 -0
  30. package/dist/shared/contracts/button.js +1 -0
  31. package/dist/shared/contracts/calendar.d.ts +5 -0
  32. package/dist/shared/contracts/calendar.js +1 -0
  33. package/dist/shared/contracts/card.d.ts +3 -0
  34. package/dist/shared/contracts/card.js +1 -0
  35. package/dist/shared/contracts/carousel.d.ts +3 -0
  36. package/dist/shared/contracts/carousel.js +1 -0
  37. package/dist/shared/contracts/change-reason.d.ts +29 -0
  38. package/dist/shared/contracts/change-reason.js +1 -0
  39. package/dist/shared/contracts/chat-composer.d.ts +3 -0
  40. package/dist/shared/contracts/chat-composer.js +1 -0
  41. package/dist/shared/contracts/chat-message.d.ts +3 -0
  42. package/dist/shared/contracts/chat-message.js +1 -0
  43. package/dist/shared/contracts/checkbox-card.d.ts +3 -0
  44. package/dist/shared/contracts/checkbox-card.js +1 -0
  45. package/dist/shared/contracts/checkbox-group.d.ts +3 -0
  46. package/dist/shared/contracts/checkbox-group.js +1 -0
  47. package/dist/shared/contracts/checkbox.d.ts +3 -0
  48. package/dist/shared/contracts/checkbox.js +1 -0
  49. package/dist/shared/contracts/clipboard.d.ts +3 -0
  50. package/dist/shared/contracts/clipboard.js +1 -0
  51. package/dist/shared/contracts/collapsible.d.ts +3 -0
  52. package/dist/shared/contracts/collapsible.js +1 -0
  53. package/dist/shared/contracts/color-picker.d.ts +3 -0
  54. package/dist/shared/contracts/color-picker.js +1 -0
  55. package/dist/shared/contracts/combobox.d.ts +3 -0
  56. package/dist/shared/contracts/combobox.js +1 -0
  57. package/dist/shared/contracts/command.d.ts +3 -0
  58. package/dist/shared/contracts/command.js +1 -0
  59. package/dist/shared/contracts/comment-thread.d.ts +3 -0
  60. package/dist/shared/contracts/comment-thread.js +1 -0
  61. package/dist/shared/contracts/comment.d.ts +3 -0
  62. package/dist/shared/contracts/comment.js +1 -0
  63. package/dist/shared/contracts/confirm-dialog.d.ts +3 -0
  64. package/dist/shared/contracts/confirm-dialog.js +1 -0
  65. package/dist/shared/contracts/conversation-list.d.ts +3 -0
  66. package/dist/shared/contracts/conversation-list.js +1 -0
  67. package/dist/shared/contracts/dashboard-layout.d.ts +3 -0
  68. package/dist/shared/contracts/dashboard-layout.js +1 -0
  69. package/dist/shared/contracts/date-field.d.ts +3 -0
  70. package/dist/shared/contracts/date-field.js +1 -0
  71. package/dist/shared/contracts/date-picker.d.ts +3 -0
  72. package/dist/shared/contracts/date-picker.js +1 -0
  73. package/dist/shared/contracts/date-value.d.ts +11 -0
  74. package/dist/shared/contracts/date-value.js +1 -0
  75. package/dist/shared/contracts/dialog.d.ts +3 -0
  76. package/dist/shared/contracts/dialog.js +1 -0
  77. package/dist/shared/contracts/divider.d.ts +5 -0
  78. package/dist/shared/contracts/divider.js +1 -0
  79. package/dist/shared/contracts/drawer.d.ts +3 -0
  80. package/dist/shared/contracts/drawer.js +1 -0
  81. package/dist/shared/contracts/editable.d.ts +3 -0
  82. package/dist/shared/contracts/editable.js +1 -0
  83. package/dist/shared/contracts/empty-state.d.ts +3 -0
  84. package/dist/shared/contracts/empty-state.js +1 -0
  85. package/dist/shared/contracts/field.d.ts +3 -0
  86. package/dist/shared/contracts/field.js +1 -0
  87. package/dist/shared/contracts/file-upload.d.ts +3 -0
  88. package/dist/shared/contracts/file-upload.js +1 -0
  89. package/dist/shared/contracts/filter-bar.d.ts +3 -0
  90. package/dist/shared/contracts/filter-bar.js +1 -0
  91. package/dist/shared/contracts/floating-panel.d.ts +3 -0
  92. package/dist/shared/contracts/floating-panel.js +1 -0
  93. package/dist/shared/contracts/forgot-password-page.d.ts +3 -0
  94. package/dist/shared/contracts/forgot-password-page.js +1 -0
  95. package/dist/shared/contracts/form-property.d.ts +3 -0
  96. package/dist/shared/contracts/form-property.js +1 -0
  97. package/dist/shared/contracts/form-section.d.ts +3 -0
  98. package/dist/shared/contracts/form-section.js +1 -0
  99. package/dist/shared/contracts/form-validity.d.ts +7 -0
  100. package/dist/shared/contracts/form-validity.js +1 -0
  101. package/dist/shared/contracts/form.d.ts +3 -0
  102. package/dist/shared/contracts/form.js +1 -0
  103. package/dist/shared/contracts/heading.d.ts +3 -0
  104. package/dist/shared/contracts/heading.js +1 -0
  105. package/dist/shared/contracts/image.d.ts +3 -0
  106. package/dist/shared/contracts/image.js +1 -0
  107. package/dist/shared/contracts/index.d.ts +8 -0
  108. package/dist/shared/contracts/index.js +1 -0
  109. package/dist/shared/contracts/kbd.d.ts +3 -0
  110. package/dist/shared/contracts/kbd.js +1 -0
  111. package/dist/shared/contracts/label.d.ts +3 -0
  112. package/dist/shared/contracts/label.js +1 -0
  113. package/dist/shared/contracts/link.d.ts +3 -0
  114. package/dist/shared/contracts/link.js +1 -0
  115. package/dist/shared/contracts/list.d.ts +3 -0
  116. package/dist/shared/contracts/list.js +1 -0
  117. package/dist/shared/contracts/listbox.d.ts +3 -0
  118. package/dist/shared/contracts/listbox.js +1 -0
  119. package/dist/shared/contracts/loading-overlay.d.ts +3 -0
  120. package/dist/shared/contracts/loading-overlay.js +1 -0
  121. package/dist/shared/contracts/member-id.d.ts +18 -0
  122. package/dist/shared/contracts/member-id.js +1 -0
  123. package/dist/shared/contracts/mentions.d.ts +3 -0
  124. package/dist/shared/contracts/mentions.js +1 -0
  125. package/dist/shared/contracts/menu.d.ts +3 -0
  126. package/dist/shared/contracts/menu.js +1 -0
  127. package/dist/shared/contracts/menubar.d.ts +3 -0
  128. package/dist/shared/contracts/menubar.js +1 -0
  129. package/dist/shared/contracts/navigation-menu.d.ts +6 -0
  130. package/dist/shared/contracts/navigation-menu.js +1 -0
  131. package/dist/shared/contracts/notification-center.d.ts +3 -0
  132. package/dist/shared/contracts/notification-center.js +1 -0
  133. package/dist/shared/contracts/number-field.d.ts +5 -0
  134. package/dist/shared/contracts/number-field.js +1 -0
  135. package/dist/shared/contracts/onboarding-checklist.d.ts +3 -0
  136. package/dist/shared/contracts/onboarding-checklist.js +1 -0
  137. package/dist/shared/contracts/overlay-parts.d.ts +73 -0
  138. package/dist/shared/contracts/overlay-parts.js +1 -0
  139. package/dist/shared/contracts/page-container.d.ts +3 -0
  140. package/dist/shared/contracts/page-container.js +1 -0
  141. package/dist/shared/contracts/pagination.d.ts +5 -0
  142. package/dist/shared/contracts/pagination.js +1 -0
  143. package/dist/shared/contracts/password-input.d.ts +6 -0
  144. package/dist/shared/contracts/password-input.js +1 -0
  145. package/dist/shared/contracts/pin-input.d.ts +6 -0
  146. package/dist/shared/contracts/pin-input.js +1 -0
  147. package/dist/shared/contracts/polymorphic.d.ts +6 -0
  148. package/dist/shared/contracts/polymorphic.js +1 -0
  149. package/dist/shared/contracts/popover.d.ts +7 -0
  150. package/dist/shared/contracts/popover.js +1 -0
  151. package/dist/shared/contracts/progress.d.ts +6 -0
  152. package/dist/shared/contracts/progress.js +1 -0
  153. package/dist/shared/contracts/qr-code.d.ts +5 -0
  154. package/dist/shared/contracts/qr-code.js +1 -0
  155. package/dist/shared/contracts/radio-card.d.ts +6 -0
  156. package/dist/shared/contracts/radio-card.js +1 -0
  157. package/dist/shared/contracts/radio-group.d.ts +6 -0
  158. package/dist/shared/contracts/radio-group.js +1 -0
  159. package/dist/shared/contracts/rating.d.ts +6 -0
  160. package/dist/shared/contracts/rating.js +1 -0
  161. package/dist/shared/contracts/reset-password-page.d.ts +3 -0
  162. package/dist/shared/contracts/reset-password-page.js +1 -0
  163. package/dist/shared/contracts/resizable.d.ts +7 -0
  164. package/dist/shared/contracts/resizable.js +1 -0
  165. package/dist/shared/contracts/rules.d.ts +11 -0
  166. package/dist/shared/contracts/rules.js +1 -0
  167. package/dist/shared/contracts/scroll-area.d.ts +6 -0
  168. package/dist/shared/contracts/scroll-area.js +1 -0
  169. package/dist/shared/contracts/select.d.ts +5 -0
  170. package/dist/shared/contracts/select.js +1 -0
  171. package/dist/shared/contracts/selection-value.d.ts +20 -0
  172. package/dist/shared/contracts/selection-value.js +1 -0
  173. package/dist/shared/contracts/sign-in-page.d.ts +3 -0
  174. package/dist/shared/contracts/sign-in-page.js +1 -0
  175. package/dist/shared/contracts/sign-up-page.d.ts +3 -0
  176. package/dist/shared/contracts/sign-up-page.js +1 -0
  177. package/dist/shared/contracts/skeleton.d.ts +5 -0
  178. package/dist/shared/contracts/skeleton.js +1 -0
  179. package/dist/shared/contracts/slider.d.ts +7 -0
  180. package/dist/shared/contracts/slider.js +1 -0
  181. package/dist/shared/contracts/speed-dial.d.ts +6 -0
  182. package/dist/shared/contracts/speed-dial.js +1 -0
  183. package/dist/shared/contracts/spinner.d.ts +6 -0
  184. package/dist/shared/contracts/spinner.js +1 -0
  185. package/dist/shared/contracts/split-button.d.ts +6 -0
  186. package/dist/shared/contracts/split-button.js +1 -0
  187. package/dist/shared/contracts/stat-card.d.ts +3 -0
  188. package/dist/shared/contracts/stat-card.js +1 -0
  189. package/dist/shared/contracts/stepper.d.ts +6 -0
  190. package/dist/shared/contracts/stepper.js +1 -0
  191. package/dist/shared/contracts/styling-hooks.d.ts +8 -0
  192. package/dist/shared/contracts/styling-hooks.js +1 -0
  193. package/dist/shared/contracts/switch.d.ts +6 -0
  194. package/dist/shared/contracts/switch.js +1 -0
  195. package/dist/shared/contracts/table.d.ts +7 -0
  196. package/dist/shared/contracts/table.js +1 -0
  197. package/dist/shared/contracts/tabs.d.ts +5 -0
  198. package/dist/shared/contracts/tabs.js +1 -0
  199. package/dist/shared/contracts/tag-group.d.ts +7 -0
  200. package/dist/shared/contracts/tag-group.js +1 -0
  201. package/dist/shared/contracts/tags-input.d.ts +8 -0
  202. package/dist/shared/contracts/tags-input.js +1 -0
  203. package/dist/shared/contracts/text-field.d.ts +6 -0
  204. package/dist/shared/contracts/text-field.js +1 -0
  205. package/dist/shared/contracts/text.d.ts +6 -0
  206. package/dist/shared/contracts/text.js +1 -0
  207. package/dist/shared/contracts/textarea.d.ts +5 -0
  208. package/dist/shared/contracts/textarea.js +1 -0
  209. package/dist/shared/contracts/time-field.d.ts +5 -0
  210. package/dist/shared/contracts/time-field.js +1 -0
  211. package/dist/shared/contracts/time.d.ts +6 -0
  212. package/dist/shared/contracts/time.js +1 -0
  213. package/dist/shared/contracts/timeline.d.ts +5 -0
  214. package/dist/shared/contracts/timeline.js +1 -0
  215. package/dist/shared/contracts/toast.d.ts +6 -0
  216. package/dist/shared/contracts/toast.js +1 -0
  217. package/dist/shared/contracts/toggle-group.d.ts +6 -0
  218. package/dist/shared/contracts/toggle-group.js +1 -0
  219. package/dist/shared/contracts/toggle.d.ts +5 -0
  220. package/dist/shared/contracts/toggle.js +1 -0
  221. package/dist/shared/contracts/toolbar.d.ts +3 -0
  222. package/dist/shared/contracts/toolbar.js +1 -0
  223. package/dist/shared/contracts/tour.d.ts +5 -0
  224. package/dist/shared/contracts/tour.js +1 -0
  225. package/dist/shared/contracts/transfer.d.ts +6 -0
  226. package/dist/shared/contracts/transfer.js +1 -0
  227. package/dist/shared/contracts/tree-select.d.ts +6 -0
  228. package/dist/shared/contracts/tree-select.js +1 -0
  229. package/dist/shared/contracts/tree.d.ts +6 -0
  230. package/dist/shared/contracts/tree.js +1 -0
  231. package/dist/shared/contracts/types.d.ts +230 -0
  232. package/dist/shared/contracts/types.js +1 -0
  233. package/dist/shared/contracts/usage-card.d.ts +3 -0
  234. package/dist/shared/contracts/usage-card.js +1 -0
  235. package/dist/shared/contracts/user-menu.d.ts +3 -0
  236. package/dist/shared/contracts/user-menu.js +1 -0
  237. package/dist/shared/contracts/verification-page.d.ts +3 -0
  238. package/dist/shared/contracts/verification-page.js +1 -0
  239. package/dist/shared/contracts/workspace-switcher.d.ts +3 -0
  240. package/dist/shared/contracts/workspace-switcher.js +1 -0
  241. package/dist/shared/core/announcer.d.ts +17 -0
  242. package/dist/shared/core/announcer.js +1 -0
  243. package/dist/shared/core/appearance.d.ts +14 -0
  244. package/dist/shared/core/appearance.js +1 -0
  245. package/dist/shared/core/arrow-keys.d.ts +7 -0
  246. package/dist/shared/core/arrow-keys.js +1 -0
  247. package/dist/shared/core/calendar-locale.d.ts +35 -0
  248. package/dist/shared/core/calendar-locale.js +1 -0
  249. package/dist/shared/core/color.d.ts +80 -0
  250. package/dist/shared/core/color.js +1 -0
  251. package/dist/shared/core/controllable.d.ts +42 -0
  252. package/dist/shared/core/controllable.js +1 -0
  253. package/dist/shared/core/csv.d.ts +43 -0
  254. package/dist/shared/core/csv.js +2 -0
  255. package/dist/shared/core/date-segments.d.ts +223 -0
  256. package/dist/shared/core/date-segments.js +1 -0
  257. package/dist/shared/core/date-value.d.ts +57 -0
  258. package/dist/shared/core/date-value.js +1 -0
  259. package/dist/shared/core/dev-mode.d.ts +12 -0
  260. package/dist/shared/core/dev-mode.js +1 -0
  261. package/dist/shared/core/dialogs.d.ts +96 -0
  262. package/dist/shared/core/dialogs.js +1 -0
  263. package/dist/shared/core/dismissal.d.ts +56 -0
  264. package/dist/shared/core/dismissal.js +1 -0
  265. package/dist/shared/core/field-core.d.ts +250 -0
  266. package/dist/shared/core/field-core.js +1 -0
  267. package/dist/shared/core/focus-targets.d.ts +77 -0
  268. package/dist/shared/core/focus-targets.js +1 -0
  269. package/dist/shared/core/format-file-size.d.ts +9 -0
  270. package/dist/shared/core/format-file-size.js +1 -0
  271. package/dist/shared/core/glyph-data.d.ts +13 -0
  272. package/dist/shared/core/glyph-data.js +1 -0
  273. package/dist/shared/core/measure-auto-resize.d.ts +5 -0
  274. package/dist/shared/core/measure-auto-resize.js +1 -0
  275. package/dist/shared/core/media-query.d.ts +7 -0
  276. package/dist/shared/core/media-query.js +1 -0
  277. package/dist/shared/core/mentions.d.ts +116 -0
  278. package/dist/shared/core/mentions.js +2 -0
  279. package/dist/shared/core/pin-chars.d.ts +13 -0
  280. package/dist/shared/core/pin-chars.js +1 -0
  281. package/dist/shared/core/placement.d.ts +102 -0
  282. package/dist/shared/core/placement.js +1 -0
  283. package/dist/shared/core/qr-encoder.d.ts +33 -0
  284. package/dist/shared/core/qr-encoder.js +1 -0
  285. package/dist/shared/core/roving-tab-stop.d.ts +37 -0
  286. package/dist/shared/core/roving-tab-stop.js +1 -0
  287. package/dist/shared/core/select-keyboard.d.ts +80 -0
  288. package/dist/shared/core/select-keyboard.js +1 -0
  289. package/dist/shared/core/selection.d.ts +58 -0
  290. package/dist/shared/core/selection.js +1 -0
  291. package/dist/shared/core/tabbable.d.ts +8 -0
  292. package/dist/shared/core/tabbable.js +1 -0
  293. package/dist/shared/core/timer.d.ts +82 -0
  294. package/dist/shared/core/timer.js +1 -0
  295. package/dist/shared/core/tree-columns.d.ts +48 -0
  296. package/dist/shared/core/tree-columns.js +1 -0
  297. package/dist/shared/core/typeahead.d.ts +27 -0
  298. package/dist/shared/core/typeahead.js +1 -0
  299. package/dist/shared/index.d.ts +113 -0
  300. package/dist/shared/index.js +1 -0
  301. package/dist/skins-src/_foundation-fallback.css +124 -0
  302. package/dist/skins-src/base.css +328 -0
  303. package/dist/skins-src/components/_actuator.css +203 -0
  304. package/dist/skins-src/components/_arrow.css +20 -0
  305. package/dist/skins-src/components/_card-control.css +27 -0
  306. package/dist/skins-src/components/_collection.css +281 -0
  307. package/dist/skins-src/components/_hit-target.css +28 -0
  308. package/dist/skins-src/components/_overlay.css +214 -0
  309. package/dist/skins-src/components/_status.css +38 -0
  310. package/dist/skins-src/components/_trigger.css +85 -0
  311. package/dist/skins-src/components/accordion.css +85 -0
  312. package/dist/skins-src/components/alert.css +118 -0
  313. package/dist/skins-src/components/angle-slider.css +110 -0
  314. package/dist/skins-src/components/aspect-ratio.css +26 -0
  315. package/dist/skins-src/components/autocomplete.css +112 -0
  316. package/dist/skins-src/components/avatar.css +87 -0
  317. package/dist/skins-src/components/badge.css +164 -0
  318. package/dist/skins-src/components/box.css +9 -0
  319. package/dist/skins-src/components/breadcrumb.css +78 -0
  320. package/dist/skins-src/components/button.css +304 -0
  321. package/dist/skins-src/components/calendar.css +269 -0
  322. package/dist/skins-src/components/card.css +116 -0
  323. package/dist/skins-src/components/carousel.css +192 -0
  324. package/dist/skins-src/components/chat-composer.css +89 -0
  325. package/dist/skins-src/components/chat-message.css +98 -0
  326. package/dist/skins-src/components/checkbox-card.css +153 -0
  327. package/dist/skins-src/components/checkbox-group.css +72 -0
  328. package/dist/skins-src/components/checkbox.css +141 -0
  329. package/dist/skins-src/components/clipboard.css +126 -0
  330. package/dist/skins-src/components/collapsible.css +64 -0
  331. package/dist/skins-src/components/color-picker.css +304 -0
  332. package/dist/skins-src/components/combobox.css +111 -0
  333. package/dist/skins-src/components/command.css +73 -0
  334. package/dist/skins-src/components/comment-thread.css +56 -0
  335. package/dist/skins-src/components/comment.css +59 -0
  336. package/dist/skins-src/components/confirm-dialog.css +43 -0
  337. package/dist/skins-src/components/conversation-list.css +142 -0
  338. package/dist/skins-src/components/dashboard-layout.css +106 -0
  339. package/dist/skins-src/components/date-field.css +95 -0
  340. package/dist/skins-src/components/date-picker.css +79 -0
  341. package/dist/skins-src/components/dialog.css +161 -0
  342. package/dist/skins-src/components/divider.css +64 -0
  343. package/dist/skins-src/components/drawer.css +166 -0
  344. package/dist/skins-src/components/editable.css +121 -0
  345. package/dist/skins-src/components/empty-state.css +85 -0
  346. package/dist/skins-src/components/field.css +104 -0
  347. package/dist/skins-src/components/file-upload.css +164 -0
  348. package/dist/skins-src/components/filter-bar.css +48 -0
  349. package/dist/skins-src/components/floating-panel.css +168 -0
  350. package/dist/skins-src/components/forgot-password-page.css +45 -0
  351. package/dist/skins-src/components/form-section.css +75 -0
  352. package/dist/skins-src/components/form.css +115 -0
  353. package/dist/skins-src/components/heading.css +38 -0
  354. package/dist/skins-src/components/image.css +43 -0
  355. package/dist/skins-src/components/kbd.css +76 -0
  356. package/dist/skins-src/components/label.css +45 -0
  357. package/dist/skins-src/components/link.css +72 -0
  358. package/dist/skins-src/components/list.css +104 -0
  359. package/dist/skins-src/components/listbox.css +90 -0
  360. package/dist/skins-src/components/loading-overlay.css +89 -0
  361. package/dist/skins-src/components/mentions.css +79 -0
  362. package/dist/skins-src/components/menu.css +102 -0
  363. package/dist/skins-src/components/menubar.css +130 -0
  364. package/dist/skins-src/components/navigation-menu.css +145 -0
  365. package/dist/skins-src/components/notification-center.css +139 -0
  366. package/dist/skins-src/components/number-field.css +95 -0
  367. package/dist/skins-src/components/onboarding-checklist.css +156 -0
  368. package/dist/skins-src/components/page-container.css +29 -0
  369. package/dist/skins-src/components/pagination.css +147 -0
  370. package/dist/skins-src/components/password-input.css +116 -0
  371. package/dist/skins-src/components/pin-input.css +115 -0
  372. package/dist/skins-src/components/popover.css +108 -0
  373. package/dist/skins-src/components/progress.css +207 -0
  374. package/dist/skins-src/components/qr-code.css +62 -0
  375. package/dist/skins-src/components/radio-card.css +158 -0
  376. package/dist/skins-src/components/radio-group.css +148 -0
  377. package/dist/skins-src/components/rating.css +150 -0
  378. package/dist/skins-src/components/reset-password-page.css +51 -0
  379. package/dist/skins-src/components/resizable.css +131 -0
  380. package/dist/skins-src/components/scroll-area.css +101 -0
  381. package/dist/skins-src/components/select.css +239 -0
  382. package/dist/skins-src/components/sign-in-page.css +47 -0
  383. package/dist/skins-src/components/sign-up-page.css +55 -0
  384. package/dist/skins-src/components/skeleton.css +55 -0
  385. package/dist/skins-src/components/skip-link.css +51 -0
  386. package/dist/skins-src/components/slider.css +164 -0
  387. package/dist/skins-src/components/speed-dial.css +162 -0
  388. package/dist/skins-src/components/spinner.css +59 -0
  389. package/dist/skins-src/components/split-button.css +167 -0
  390. package/dist/skins-src/components/stat-card.css +117 -0
  391. package/dist/skins-src/components/stepper.css +153 -0
  392. package/dist/skins-src/components/switch.css +155 -0
  393. package/dist/skins-src/components/table.css +336 -0
  394. package/dist/skins-src/components/tabs.css +116 -0
  395. package/dist/skins-src/components/tag-group.css +72 -0
  396. package/dist/skins-src/components/tags-input.css +176 -0
  397. package/dist/skins-src/components/text-field.css +182 -0
  398. package/dist/skins-src/components/text.css +83 -0
  399. package/dist/skins-src/components/textarea.css +118 -0
  400. package/dist/skins-src/components/time-field.css +43 -0
  401. package/dist/skins-src/components/time.css +13 -0
  402. package/dist/skins-src/components/timeline.css +206 -0
  403. package/dist/skins-src/components/toast.css +133 -0
  404. package/dist/skins-src/components/toggle-group.css +185 -0
  405. package/dist/skins-src/components/toggle.css +89 -0
  406. package/dist/skins-src/components/toolbar.css +84 -0
  407. package/dist/skins-src/components/tour.css +67 -0
  408. package/dist/skins-src/components/transfer.css +112 -0
  409. package/dist/skins-src/components/tree-select.css +124 -0
  410. package/dist/skins-src/components/tree.css +110 -0
  411. package/dist/skins-src/components/usage-card.css +129 -0
  412. package/dist/skins-src/components/user-menu.css +83 -0
  413. package/dist/skins-src/components/verification-page.css +64 -0
  414. package/dist/skins-src/components/workspace-switcher.css +133 -0
  415. package/dist/skins-src/utilities.css +130 -0
  416. package/dist/skins-src/web-components.css +64 -0
  417. package/dist/strip-paint.d.mts +7 -0
  418. package/dist/strip-paint.mjs +131 -0
  419. package/dist/themes/AntDark.md +14 -0
  420. package/dist/themes/AntDark.ts +47 -0
  421. package/dist/themes/AntLight.md +21 -0
  422. package/dist/themes/AntLight.ts +95 -0
  423. package/dist/themes/CatppuccinLatte.md +20 -0
  424. package/dist/themes/CatppuccinLatte.ts +93 -0
  425. package/dist/themes/CatppuccinMocha.md +15 -0
  426. package/dist/themes/CatppuccinMocha.ts +93 -0
  427. package/dist/themes/ChakraDark.md +8 -0
  428. package/dist/themes/ChakraDark.ts +47 -0
  429. package/dist/themes/ChakraLight.md +14 -0
  430. package/dist/themes/ChakraLight.ts +93 -0
  431. package/dist/themes/Contrast.test.ts +80 -0
  432. package/dist/themes/CupcakeDark.md +8 -0
  433. package/dist/themes/CupcakeDark.ts +39 -0
  434. package/dist/themes/CupcakeLight.md +31 -0
  435. package/dist/themes/CupcakeLight.ts +93 -0
  436. package/dist/themes/DefaultTheme.md +8 -0
  437. package/dist/themes/DefaultTheme.test.ts +96 -0
  438. package/dist/themes/DefaultTheme.ts +137 -0
  439. package/dist/themes/DraculaDark.md +14 -0
  440. package/dist/themes/DraculaDark.ts +93 -0
  441. package/dist/themes/DraculaLight.md +8 -0
  442. package/dist/themes/DraculaLight.ts +55 -0
  443. package/dist/themes/EmeraldDark.md +8 -0
  444. package/dist/themes/EmeraldDark.ts +35 -0
  445. package/dist/themes/EmeraldLight.md +8 -0
  446. package/dist/themes/EmeraldLight.ts +93 -0
  447. package/dist/themes/EverforestDark.md +26 -0
  448. package/dist/themes/EverforestDark.ts +99 -0
  449. package/dist/themes/EverforestLight.md +31 -0
  450. package/dist/themes/EverforestLight.ts +51 -0
  451. package/dist/themes/FluentDark.md +8 -0
  452. package/dist/themes/FluentDark.ts +47 -0
  453. package/dist/themes/FluentLight.md +8 -0
  454. package/dist/themes/FluentLight.ts +100 -0
  455. package/dist/themes/GraphiteDark.md +8 -0
  456. package/dist/themes/GraphiteDark.ts +35 -0
  457. package/dist/themes/GraphiteLight.md +14 -0
  458. package/dist/themes/GraphiteLight.ts +93 -0
  459. package/dist/themes/GruvboxDark.md +14 -0
  460. package/dist/themes/GruvboxDark.ts +93 -0
  461. package/dist/themes/GruvboxLight.md +27 -0
  462. package/dist/themes/GruvboxLight.ts +49 -0
  463. package/dist/themes/MaterialDark.md +8 -0
  464. package/dist/themes/MaterialDark.ts +47 -0
  465. package/dist/themes/MaterialLight.md +8 -0
  466. package/dist/themes/MaterialLight.ts +104 -0
  467. package/dist/themes/MidnightDark.md +8 -0
  468. package/dist/themes/MidnightDark.ts +19 -0
  469. package/dist/themes/MidnightLight.md +8 -0
  470. package/dist/themes/MidnightLight.ts +23 -0
  471. package/dist/themes/NordDark.md +28 -0
  472. package/dist/themes/NordDark.ts +93 -0
  473. package/dist/themes/NordLight.md +20 -0
  474. package/dist/themes/NordLight.ts +50 -0
  475. package/dist/themes/OneDark.md +26 -0
  476. package/dist/themes/OneDark.ts +93 -0
  477. package/dist/themes/OneLight.md +20 -0
  478. package/dist/themes/OneLight.ts +51 -0
  479. package/dist/themes/PrimerDark.md +26 -0
  480. package/dist/themes/PrimerDark.ts +99 -0
  481. package/dist/themes/PrimerLight.md +14 -0
  482. package/dist/themes/PrimerLight.ts +93 -0
  483. package/dist/themes/RosePine.md +23 -0
  484. package/dist/themes/RosePine.ts +93 -0
  485. package/dist/themes/RosePineDawn.md +20 -0
  486. package/dist/themes/RosePineDawn.ts +51 -0
  487. package/dist/themes/SkandaDark.md +8 -0
  488. package/dist/themes/SkandaDark.ts +57 -0
  489. package/dist/themes/SkandaLight.md +8 -0
  490. package/dist/themes/SkandaLight.ts +96 -0
  491. package/dist/themes/SolarizedDark.md +8 -0
  492. package/dist/themes/SolarizedDark.ts +93 -0
  493. package/dist/themes/SolarizedLight.md +32 -0
  494. package/dist/themes/SolarizedLight.ts +93 -0
  495. package/dist/themes/SynthwaveDark.md +8 -0
  496. package/dist/themes/SynthwaveDark.ts +93 -0
  497. package/dist/themes/SynthwaveLight.md +20 -0
  498. package/dist/themes/SynthwaveLight.ts +48 -0
  499. package/dist/themes/Themes.test.ts +110 -0
  500. package/dist/themes/brands.test.ts +63 -0
  501. package/dist/themes/brands.ts +121 -0
  502. package/dist/themes/createBrandTheme.test.ts +223 -0
  503. package/dist/themes/createBrandTheme.ts +298 -0
  504. package/dist/themes/index.ts +54 -0
  505. package/package.json +73 -0
@@ -0,0 +1 @@
1
+ import{changeDetail as e}from"./change-reason.js";import{constraintValidationMethods as t,setCustomValidityMethod as a}from"./form-validity.js";import{ROOT_DATA_ATTRIBUTES as i}from"./styling-hooks.js";var o={name:"PasswordInput",purpose:"A password field: a TextField whose type flips between password and text, with a toggle button reporting state via aria-pressed. Forwards all TextField props plus Field and Toggle parts.",props:[{name:"visible",type:"boolean",required:!1,description:"Controlled visibility \u2014 whether the characters are revealed. Pair with the visible-change event."},{name:"defaultVisible",type:"boolean",defaultValue:"false",required:!1,description:"Initial visibility, for uncontrolled usage; starts masked, the only safe default for an onscreen credential."},{name:"value",type:"string",required:!1,description:"Controlled value, forwarded to the underlying TextField. Pair with the value-change event."},{name:"defaultValue",type:"string",required:!1,description:"Initial value, for uncontrolled usage, forwarded to the underlying TextField."},{name:"disabled",type:"boolean",defaultValue:"false",required:!1,description:"Disables the field and the toggle together \u2014 there is nothing to reveal in a field nobody can use."},{name:"required",type:"boolean",defaultValue:"false",required:!1,description:"Marks the field required for native form validation, forwarded to the underlying TextField."},{name:"invalid",type:"boolean",defaultValue:"false",required:!1,description:"Marks the field invalid, exposed as aria-invalid on the input."},{name:"name",type:"string",required:!1,description:"Form field name, forwarded to the underlying TextField and set on the wrapped native <input>."},{name:"revealLabel",type:"string",defaultValue:"'Show password'",required:!1,description:"Accessible name for the reveal button, an icon-only control with no text content to take a name from; the name stays stable since aria-pressed carries the state. All five packages let an aria-label written directly on the Toggle take precedence over it \u2014 React, Vue and Svelte through attribute passthrough, Angular through its aliased ariaLabel input, and Web Components through the Toggle's own label property."},{name:"showToggle",type:"boolean",defaultValue:"true",required:!1,description:"Renders the button that reveals and hides the value."},{name:"readOnly",type:"boolean",defaultValue:"false",required:!1,description:"Makes the field read-only, forwarded to the input: value stays focusable, selectable and submitted, only editing is blocked. The Toggle stays operable, since revealing matters most when a credential can't be edited."},{name:"placeholder",type:"string",required:!1,description:"Placeholder text for the derived Field, forwarded from TextField. Never a substitute for a label \u2014 the naming requirement below still applies."},{name:"clearable",type:"boolean",defaultValue:"false",required:!1,description:"Renders a button that clears the value, placed before the Toggle rather than in the trailing position the Toggle occupies."},{name:"clearLabel",type:"string",defaultValue:"'Clear'",required:!1,description:"Accessible name for the derived clear button."},{name:"getVisibilityAnnouncement",type:"(visible: boolean) => string",required:!1,description:'Words the polite live-region message announced when visibility changes \u2014 the only screen-reader confirmation the characters are now readable, since the toggle\'s own name doesn\'t change. Return an empty string to announce nothing. Defaults to "Password shown" / "Password hidden". **Property-only**: a function has no attribute form, so `<skdx-password-input>` declares it `@property({ attribute: false })`.'},{name:"size",type:"'md' | 'sm' | 'lg' | (string & {})",required:!1,description:"Visual size rung, written to data-size on the root; the data-size attribute may be set directly instead."},{name:"variant",type:"'filled' | 'ghost' | (string & {})",required:!1,description:"Fill style rung inherited from the underlying text field, written to data-variant on the root; the data-variant attribute may be set directly instead."},{name:"type",type:"string",required:!1,frameworks:["angular","webComponents"],exception:"framework-host",frameworksReason:'Angular and Web Components extend the TextField class, so its type input is present but ignored: the field is always type="password" or "text" by visibility. React, Vue and Svelte compose TextField and omit the prop.',description:'Inherited from TextField and ignored: the native input is type="password" when masked and "text" when revealed.'}],events:[{name:"visible-change",detail:"boolean",description:"Fired with the new visibility whenever the characters are revealed or re-masked, controlled or not."},{name:"value-change",description:"Fired with the new value as the user types, forwarded from the underlying TextField.",detail:e("string")}],parts:[{name:"Field",lightDom:!0,description:"The native input; its type is owned by the root and flips with visibility, so it isn't settable from outside.",props:[{name:"size",type:"'md' | 'sm' | 'lg' | (string & {})",required:!1,description:"Visual size rung, written to data-size on the input; the data-size attribute may be set directly instead."},{name:"variant",type:"'filled' | 'ghost' | (string & {})",required:!1,description:"Fill style rung inherited from the underlying text field, written to data-variant on the input; the data-variant attribute may be set directly instead."}]},{name:"Toggle",description:'The reveal button, carrying aria-pressed for the state and data-state for CSS; a `<button type="button">` and its own tab stop, never `tabindex="-1"`.'}],slots:[{name:"default",description:"The field's body \u2014 a Field and a Toggle."}],appearance:[{attribute:"data-size",values:["md","sm","lg"],stylesheet:"password-input.css"},{attribute:"data-variant",values:["filled","ghost"],stylesheet:"password-input.css"}],states:["hidden","visible","disabled","invalid"],controlledUncontrolled:"Two independent axes: value (inherited from TextField) and visible, each starting from its default* prop and switching to controlled when the matching prop is passed.",formBehavior:"Whatever TextField does, unchanged: a real <input> that submits under its name and participates in form reset. The type flip does not affect submission. A form reset restores `defaultValue` **and re-masks the field back to `defaultVisible`**, firing visible-change, so a credential isn't left on screen after reset. **The plaintext value is never reflected to an attribute, in any package** \u2014 not `value`, not `data-*`, not `aria-*` \u2014 since that would put a credential into the serialised DOM, reachable via `outerHTML`, a DOM snapshot or a session replay. The one exception is React, which maintains the `value` attribute on every `<input>` it controls regardless of type, since that's what a native input's form reset restores from.",validationBehavior:"Native constraint validation forwarded from TextField (required, minLength, pattern, and the rest). No password-strength rules of its own: strength is a product policy, and a library guessing at it would be wrong more often than right.",accessibility:{role:"none \u2014 the Field is a native input and the Toggle a native button",keyboard:[{key:"Enter / Space (on the Toggle)",behavior:"Reveals or re-masks the characters."},{key:"Tab",behavior:'Moves from the field to the toggle. The toggle MUST be a tab stop of its own and MUST NOT carry tabindex="-1": revealing the characters is the only way a keyboard-only user can check what they typed, making removal a WCAG 2.1.1 failure.'}],ariaAttributes:["aria-pressed on the Toggle reflecting whether the characters are currently revealed \u2014 a swapped eye icon says nothing to a screen reader","aria-invalid on the input while invalid","The input keeps its type toggled between password and text, so browser and password-manager behaviour follows the real state rather than a CSS approximation","aria-readonly is not set: the field carries the native readonly attribute, which the platform already maps to the same state"],focusManagement:"Toggling does not move focus: the caret stays where it was, so revealing mid-entry does not cost the user their place \u2014 the reason every package flips the input's type in place rather than swapping in a second element. The toggle is a separate tab stop after the field, and every package must leave it in the tab order.",namingRequirement:'The Toggle must be named ("Show password"), and the name should stay stable while aria-pressed carries the state \u2014 a label that flips between "Show" and "Hide" duplicates what aria-pressed already announces. The field itself is named by the surrounding Field/Label like any TextField.'},styling:{cssParts:["root","toggle","field","input"],dataAttributes:[...i,"data-state","data-disabled","data-invalid","data-size","data-variant",{name:"data-skdx-password-input-generated",frameworks:["webComponents"],exception:"wc-marker",frameworksReason:'Marks a node the element generated for itself rather than one the consumer authored. React, Vue, Svelte and Angular re-render their derived anatomy declaratively, so "mine or theirs" is answered by the framework and no marker is needed.'}],cssCustomProperties:[]},publicMethods:[...t,a,{name:"setVisible",signature:"(visible: boolean): void",description:"Shows or masks the characters from code, firing the visible-change event exactly as pressing the Toggle does; a no-op while the field is disabled."}]};export{o as passwordInputContract};
@@ -0,0 +1,6 @@
1
+ import type { ComponentContract } from './types.js';
2
+ /**
3
+ * A one-time-passcode input built from N single-character boxes behaving as
4
+ * one logical string value.
5
+ */
6
+ export declare const pinInputContract: ComponentContract;
@@ -0,0 +1 @@
1
+ import{changeDetail as e}from"./change-reason.js";import{constraintValidationMethods as t,setCustomValidityMethod as a}from"./form-validity.js";import{ROOT_DATA_ATTRIBUTES as o}from"./styling-hooks.js";var s={name:"PinInput",purpose:"A one-time-passcode input: N single-character boxes behaving as one logical string value. Typing or pasting auto-advances focus; Backspace on an empty box clears and moves back; Arrow Left/Right move focus between boxes; pasting a multi-character string fills consecutive boxes.",props:[{name:"value",type:"string",required:!1,description:"Current value, for controlled usage."},{name:"defaultValue",type:"string",defaultValue:"''",required:!1,description:"Initial value, for uncontrolled usage."},{name:"length",type:"number",defaultValue:"6",required:!1,description:"Number of character boxes."},{name:"type",type:"'text' | 'numeric' | 'alphanumeric' | 'alphabetic'",defaultValue:"'text'",required:!1,description:"Which characters a box accepts: 'text' anything, 'numeric' digits 0-9, 'alphanumeric' ASCII letters and digits, 'alphabetic' ASCII letters. It was digits-or-anything, which cannot express the alphanumeric backup codes and letter-only codes both are used for. pattern overrides it entirely. Also drives inputMode, where only 'numeric' has a keyboard of its own to ask for."},{name:"pattern",type:"string",required:!1,description:"A regular-expression source tested against one character at a time, replacing type's built-in set \u2014 '[A-F0-9]' for a hex code. Per character rather than per code, because that is the decision each keystroke and each pasted character has to make; anchor it yourself if you need to."},{name:"placeholder",type:"string",required:!1,description:"A single character drawn in every empty box \u2014 a dot or a circle, so the boxes read as slots waiting for a code. No default glyph on purpose: which character it is belongs to the product, not to a package."},{name:"otp",type:"boolean",defaultValue:"true",required:!1,description:'Advertises autocomplete="one-time-code" on the first box so the platform can offer a code it received. Defaults on because that is what a pin input usually is; turn it off for a PIN pad or a door code, where the suggestion will never arrive. First box only either way \u2014 a second one-time-code field on a page suppresses the suggestion for both.'},{name:"autoFocus",type:"boolean",defaultValue:"false",required:!1,description:"Focuses the first box on mount, which is what a screen whose only job is the code wants. Off by default: a pin input further down a page that steals focus on mount moves the user away from what they were reading."},{name:"blurOnComplete",type:"boolean",defaultValue:"false",required:!1,description:"Blurs the last box the moment the code completes, so a soft keyboard closes and the confirmation the completion triggers is on screen. Pairs with autoSubmit, and fires after value-complete."},{name:"selectOnFocus",type:"boolean",defaultValue:"false",required:!1,description:"Selects a box's existing character when it takes focus, so correcting one digit is a single keystroke instead of a delete and a retype. Applies to click, Tab and the auto-advance alike."},{name:"mask",type:"boolean",defaultValue:"false",required:!1,description:"Renders filled boxes as a password field instead of plain text."},{name:"disabled",type:"boolean",defaultValue:"false",required:!1,description:"Disables every box."},{name:"invalid",type:"boolean",defaultValue:"false",required:!1,description:'Marks the field invalid. aria-invalid lands once on the role="group" root, never on the boxes.'},{name:"readOnly",type:"boolean",defaultValue:"false",required:!1,description:"Makes every box read-only."},{name:"name",type:"string",required:!1,description:"Form field name. The joined code is submitted as one entry under it; without it the field submits nothing."},{name:"form",type:"string",required:!1,description:"Id of the <form> that owns this pin, for a pin rendered outside it \u2014 inside a Dialog's portal, which is exactly where a one-time-passcode prompt lives. React, Vue, Svelte and Angular forward it to the hidden input's form attribute and resolve the reset listener through it rather than through closest('form'); <skdx-pin-input> takes the form content attribute, which is what ElementInternals associates on."},{name:"required",type:"boolean",defaultValue:"false",required:!1,description:"Marks the field required. valueMissing until every box is filled \u2014 a half-typed code counts as missing."},{name:"autoSubmit",type:"boolean",defaultValue:"false",required:!1,description:"Submits the surrounding form the moment the value completes, through requestSubmit() so constraint validation and the form's own submit handling still run."},{name:"sanitize",type:"(pasted: string) => string",required:!1,description:"Cleans pasted text before the type/pattern character filter, so both apply."},{name:"digitLabel",type:"(index: number, length: number) => string",defaultValue:"pinInputDigitLabel",required:!1,description:`Words each box's accessible name \u2014 the default reads "Digit 3 of 6". A consumer's own aria-label on a box still wins over it.`},{name:"density",type:"'default' | 'compact' | 'loose' | (string & {})",required:!1,description:"Vertical rhythm rung, written to data-density on the root; the data-density attribute may be set directly instead."},{name:"shape",type:"'rounded' | 'square' | 'pill' | (string & {})",required:!1,description:"Corner rounding rung, written to data-shape on the root; the data-shape attribute may be set directly instead."},{name:"size",type:"'md' | 'sm' | 'lg' | (string & {})",required:!1,description:"Visual size rung, written to data-size on the root; the data-size attribute may be set directly instead."}],events:[{name:"value-change",detail:e("string"),description:"Fires with the new joined value whenever any box changes."},{name:"value-complete",description:"Fires with the full value on the transition into a complete value only \u2014 retyping a box while the code is already complete does not fire it again.",detail:"string"},{name:"value-invalid",description:"Fires with a character the type or pattern filter refused, and the index of the box it was aimed at. A keystroke that does nothing and says nothing is indistinguishable from a broken keyboard, and this is the hook for saying so \u2014 a shake, a hint, an announcement. Fires once per rejected character, including once per rejected character of a paste.",detail:"{ value: string; index: number }"}],parts:[{name:"Field",lightDom:!0,description:"One box. Every package requires an `index` on it, and until now no contract said so \u2014 which left the component's whole identity model undeclared: a box is identified by its **position**, not by its value or its order in the DOM, so the root reads and writes the character at `index` in a fixed-length slot array. That is what lets box 3 of an empty code hold a character while boxes 0-2 stay empty; indexing into the joined string instead would shift every later keystroke left.",props:[{name:"index",type:"number",required:!0,description:"This box's 0-based position. Required to be unique and contiguous: the root reads and writes `value[index]`, so two boxes sharing an index write over each other and a gap leaves a character the user can never type."}]}],slots:[{name:"default",description:"PinInputField children, one per box."}],appearance:[{attribute:"data-density",values:["default","compact","loose"],stylesheet:"pin-input.css"},{attribute:"data-shape",values:["rounded","square","pill"],stylesheet:"pin-input.css"},{attribute:"data-size",values:["md","sm","lg"],stylesheet:"pin-input.css"}],states:["default","filled","empty","disabled","invalid","readonly"],controlledUncontrolled:"Supports both: value + onValueChange (controlled) or defaultValue (uncontrolled).",formBehavior:"Form-associated: with a name, submits the joined code as one entry. form associates the pin with a <form> it is not nested inside \u2014 a passcode prompt inside a portalled dialog is the ordinary case \u2014 and is also what the reset listener resolves through, so that form's reset reaches it. A required PinInput blocks submission until every box is filled \u2014 a half-typed code is no more submittable than an empty one \u2014 but the two form-participation architectures reach that through different ValidityState flags, and both spellings are contracted. React, Vue, Svelte and Angular render a real hidden input carrying `required` plus a completeness `pattern`: a half-typed code has a non-empty value, so it fails as patternMismatch and is valueMissing only when nothing is typed. Web Components has no hidden input \u2014 the host is form-associated through ElementInternals and sets its own validity \u2014 so it reports valueMissing for any incomplete code. Read the boolean (`checkValidity()`, `validity.valid`) rather than the individual flag when the code must work in all five. A form reset restores the declared default code \u2014 silently in Web Components, and by firing value-change in React/Vue/Svelte/Angular, where a controlled value belongs to the parent and would otherwise be restored straight back.",validationBehavior:"invalid is a purely presentational flag the consumer sets from its own result; required participates in native constraint validation, reported through checkValidity()/reportValidity().",accessibility:{role:"group (root); each box is a native <input>",keyboard:[{key:"Printable character",behavior:"Fills the focused box and auto-advances to the next one. A character the `type`/`pattern` filter rejects is not committed, focus does not move, and `value-invalid` fires with the character and this box's index \u2014 so a refusal is observable rather than silent."},{key:"ArrowLeft/ArrowRight",behavior:'Moves focus to the previous/next box. Mirrored under dir="rtl", so the arrows always follow the visual order rather than the index order.'},{key:"Backspace",behavior:"Clears the current box, or \u2014 only when it is already empty \u2014 clears the previous box and moves back. **This is a deliberate divergence** from Ark, PrimeVue and Zag, which all delete the current character *and* retreat in one press. A user who mistypes one digit expects to fix that digit, not the one before it, and the one-press form makes correcting the last character of a full code impossible without re-entering the one before it. Two presses to retreat, one to correct: recorded here as a decision rather than left to read as an incomplete implementation of the common pattern."},{key:"Delete",behavior:"Clears the current box and leaves focus where it is \u2014 the counterpart to Backspace above. Handled explicitly rather than left to the native default, whose behaviour inside a `maxlength=1` box depends entirely on caret position."},{key:"Paste",behavior:"Fills consecutive boxes from the pasted-into box onward, truncated at the last box, and moves focus to the box after the last one filled. The root's `sanitize` hook runs **first** \u2014 it is what strips the spaces and dashes an authenticator app copies \u2014 and the `type`/`pattern` filter runs on its result; reversing the order would filter the separators into the code rather than out of it. Every character the filter drops fires `value-invalid`."}],ariaAttributes:['aria-invalid on the role="group" root while invalid \u2014 once for the whole code, and never replicated onto the boxes, which would announce one wrong code as N separate errors',"aria-readonly on each box while readOnly \u2014 read-only is a property of the control the user is typing in, unlike invalidity",`aria-label on each box, "Digit N of M" by default and worded by the root's digitLabel, so an auto-advance says which of the N boxes focus has landed in`,'aria-describedby on the group when an enclosing Field renders a message: FIELD_CONTROL_SELECTOR matches [role="group"], and the root precedes the boxes in document order, so the Field discovers the root instead of box 0 and attaches its message (and its own aria-invalid) there'],focusManagement:"Typing or a successful paste auto-advances focus to the next incomplete box. `autoFocus` puts focus in box 0 on mount, `selectOnFocus` selects whatever character a box already holds when focus lands in it, and `blurOnComplete` takes focus back out once the code completes \u2014 three opt-ins, all off by default, because each of them moves focus somewhere the user did not ask for and only an OTP screen can say that is right.",namingRequirement:'The role="group" root is name-from-author (text inside names nothing), so it needs aria-label/aria-labelledby or an enclosing Field. Each box is named by digitLabel and is never nameless: unnamed boxes leave the user unable to tell where they are.'},styling:{cssParts:["root","field"],dataAttributes:[...o,"data-disabled","data-invalid","data-readonly","data-density","data-shape","data-size",{name:"data-skdx-pin-input-generated",frameworks:["webComponents"],exception:"wc-marker",frameworksReason:'Marks a node the element generated for itself rather than one the consumer authored. React, Vue, Svelte and Angular re-render their derived anatomy declaratively, so "mine or theirs" is answered by the framework and no marker is needed.'}],cssCustomProperties:[]},publicMethods:[...t,a,{name:"clear",signature:"(): void",description:"Empties every box and publishes the empty value, the way a rejected code needs. Deliberately the only imperative writer: value is already controllable, and a setValue beside it would be a second write path competing with the first."},{name:"focus",signature:"(): void",description:"Moves DOM focus into the first box. The counterpart of clear() \u2014 a rejected code is cleared and then handed back to the user, and doing that from a consumer meant reaching for a box element the component owns."}]};export{s as pinInputContract};
@@ -0,0 +1,6 @@
1
+ /** Element names a part's `as` prop accepts. */
2
+ export declare const POLYMORPHIC_TAGS: readonly ["a", "article", "aside", "footer", "header", "main", "nav", "section", "blockquote", "button", "caption", "code", "div", "dd", "dl", "dt", "em", "fieldset", "figcaption", "figure", "form", "h1", "h2", "h3", "h4", "h5", "h6", "kbd", "label", "legend", "li", "mark", "ol", "p", "pre", "small", "span", "strong", "table", "tbody", "td", "tfoot", "th", "thead", "time", "tr", "ul"];
3
+ /** One of {@link POLYMORPHIC_TAGS} — the type of every part's `as` prop. */
4
+ export type PolymorphicTag = (typeof POLYMORPHIC_TAGS)[number];
5
+ /** The `as` prop's contract entry for all parts. */
6
+ export declare const AS_PROP_DESCRIPTION = "Element name to render instead of this part's default tag. Accepts tag names only, not components; see `POLYMORPHIC_TAGS`. React's `asChild` takes a component and takes precedence when both are set.";
@@ -0,0 +1 @@
1
+ var e=["a","article","aside","footer","header","main","nav","section","blockquote","button","caption","code","div","dd","dl","dt","em","fieldset","figcaption","figure","form","h1","h2","h3","h4","h5","h6","kbd","label","legend","li","mark","ol","p","pre","small","span","strong","table","tbody","td","tfoot","th","thead","time","tr","ul"],t="Element name to render instead of this part's default tag. Accepts tag names only, not components; see `POLYMORPHIC_TAGS`. React's `asChild` takes a component and takes precedence when both are set.";export{t as AS_PROP_DESCRIPTION,e as POLYMORPHIC_TAGS};
@@ -0,0 +1,7 @@
1
+ import type { ComponentContract } from './types.js';
2
+ /**
3
+ * A non-modal-by-default floating panel anchored to a trigger, positioned via
4
+ * floating-ui with collision avoidance, opened by click or by hover and
5
+ * rendered as a dialog or as a plain tooltip.
6
+ */
7
+ export declare const popoverContract: ComponentContract;
@@ -0,0 +1 @@
1
+ import{arrowPart as t,autoFocusEvents as o,dismissalEvents as n,forceMountProp as a,openChangeCompleteEvent as r,popperContentProps as i,popperMeasurementProperties as s,portalPart as e}from"./overlay-parts.js";import{PART_DATA_ATTRIBUTES as l}from"./styling-hooks.js";var c={name:"Popover",purpose:'A floating panel positioned via floating-ui, anchored to a trigger, and dismissed on Escape or outside pointer-down. Derives trigger, portal, and panel anatomy from trigger, title, description, side, align, and showArrow props; manual composition via primitives/popover. Two axes widen it past the click-opened dialog: openOn="hover" reveals the panel on pointer enter after openDelay and hides it after closeDelay, and role="tooltip" makes the panel an inert, non-focusable bubble the Trigger points aria-describedby at.',props:[{name:"trigger",type:"ReactElement | Snippet | TemplateRef<unknown>",required:!1,frameworks:["react","svelte","angular"],exception:"render-prop",frameworksReason:`React, Svelte, and Angular take this as a prop. Vue and Web Components use named #trigger slot and slot="trigger" instead. Only React merges onto the consumer's element via asChild; others render their own button.`,description:"The trigger for the derived anatomy. Content model varies by framework: React passes a whole element (merged via asChild); Svelte and Angular pass only button inner content."},{name:"title",type:"string",required:!1,description:"The derived panel's accessible name, rendered as the Title part."},{name:"description",type:"string",required:!1,description:"The derived panel's accessible description, rendered as the Description part."},{name:"openOn",type:"'click' | 'hover'",defaultValue:"'click'",required:!1,description:'Which gesture reveals the panel. "click" toggles it from the Trigger button and keeps it open until dismissed. "hover" opens it on pointer enter after openDelay and closes it after closeDelay once the pointer has left both Trigger and Content, so the pointer can travel onto the panel \u2014 the Hoverable requirement of WCAG 2.2 SC 1.4.13. Keyboard focus of the Trigger also opens a hover panel under role="tooltip"; under role="dialog" hover is the only activation there is, so the Trigger must carry an href (or its own tabindex) for keyboard and touch users to reach the same information.'},{name:"role",type:"'dialog' | 'tooltip'",defaultValue:"'dialog'",required:!1,description:'What the panel is. "dialog" is an operable panel: it can be named by Title, hold buttons and links, take focus, and honour modal. "tooltip" is an inert bubble \u2014 Content renders role="tooltip", takes no focus and traps none, Tab passes straight through it, the Trigger points aria-describedby at it while open, Escape and pointer-leave and blur all close it, modal is forced to "none" whatever is passed, and data-state reports delayed-open or instant-open rather than open.'},{name:"side",type:"'top' | 'right' | 'bottom' | 'left' | 'start' | 'end'",defaultValue:"'bottom'",required:!1,description:`Which side of the trigger the derived panel opens on \u2014 forwarded to the underlying Content part. Set Content's own side directly under full manual composition. A tooltip bubble conventionally sits above its trigger, so pass side="top" under role="tooltip".`},{name:"align",type:"'start' | 'center' | 'end'",defaultValue:"'center'",required:!1,description:"Alignment of the derived panel along side \u2014 forwarded to the underlying Content part."},{name:"showArrow",type:"boolean",defaultValue:"false",required:!1,description:"Whether the derived panel renders an Arrow part. Gates element creation only; size and position are CSS once created."},{name:"open",type:"boolean",required:!1,description:"Controlled open state. Pair with the open-change event."},{name:"defaultOpen",type:"boolean",defaultValue:"false",required:!1,description:"Initial open state, for uncontrolled usage."},{name:"openDelay",type:"number",defaultValue:"700",required:!1,description:`Delay in milliseconds before a hover popover opens on pointer enter. Read only under openOn="hover"; under role="tooltip" an ancestor Provider's delayDuration applies instead unless this is set, and the Provider's skipDelayDuration can waive the delay entirely for a panel opened just after a sibling closed.`},{name:"closeDelay",type:"number",defaultValue:"300",required:!1,description:`Delay in milliseconds before a hover popover closes once the pointer has left both Trigger and Content. Read only under openOn="hover". Under role="tooltip" an ancestor Provider's closeDelay applies instead unless this is set (0 with no Provider), and while the bubble is hoverable the effective delay is max(closeDelay, 150), protecting the crossing time WCAG 2.2 SC 1.4.13 requires; a bubble with disableHoverableContent uses the value exactly.`},{name:"disableHoverableContent",type:"boolean",defaultValue:"false",required:!1,description:'Whether the pointer moving from Trigger onto Content closes the panel instead of keeping it open. Overrides an ancestor Provider. Defaults to false so the pointer can travel onto the panel, which is the Hoverable requirement of WCAG 2.2 SC 1.4.13; set true only for a bubble that must stay pointer-transparent. Read only under openOn="hover".'},{name:"href",type:"string",required:!1,frameworks:["vue","svelte","angular","webComponents"],exception:"as-directive",frameworksReason:"React's trigger is a whole element supplied through asChild, including its own href, so React declares no member for it; the other four render the anchor themselves and need the destination as a declared property.",description:`Destination for the derived Trigger's anchor. A hover popover under role="dialog" opens on pointer enter and on nothing else, so this link is the only route keyboard and touch users have to the same information; omitting it renders an <a> that is neither in tab order nor a link.`},{name:"disabled",type:"boolean",defaultValue:"false",required:!1,description:"Whether the panel is suppressed. While true it never opens: the pointer entering Trigger does nothing, aria-describedby is never set, data-state stays closed and open-change never fires. A panel already open when this turns true closes without an event."},{name:"modal",type:"'none' | 'modal' | 'trap-focus'",defaultValue:"'none'",required:!1,description:`How the open popover constrains the page across three independent axes: focus containment, outside-interaction blocking, and page-scroll lock. 'none' (default) applies none of them \u2014 focus stays in the page, the page scrolls, the background stays interactive. 'trap-focus' cycles Tab inside Content and makes the rest of the document inert, leaving page scroll alone. 'modal' applies all three, like Dialog and Drawer, and traps the user. Anything other than 'none' requires a Close part inside Content. Forced to 'none' under role="tooltip", whatever is passed: a bubble that cannot take focus has nothing to contain.`}],events:[{name:"open-change",detail:"boolean",description:"Fired with the new open state whenever it changes, controlled or not."},r("popover"),...n("popover",{outsideNote:'Under role="tooltip" the bubble closes on pointer-leave and on blur rather than on where an outside interaction landed, so the three outside events are notification-only there: the payload stays cancelable, and preventing default changes nothing. escape-key-down is the exception and is listened for on the document while open, so a hover-revealed bubble is dismissable with focus elsewhere (WCAG 2.2 SC 1.4.13).'}),...o("popover")],parts:[{name:"Provider",description:'Optional ancestor coordinating hover-delay timing across every descendant popover with role="tooltip". Renders no element of its own, and a descendant with its own openDelay, closeDelay or disableHoverableContent overrides it. Without one each tooltip falls back to its own values.',props:[{name:"delayDuration",type:"number",defaultValue:"700",required:!1,description:"Delay in milliseconds before a descendant tooltip opens on hover. Each descendant can override it with its own openDelay."},{name:"skipDelayDuration",type:"number",defaultValue:"300",required:!1,description:'Window in milliseconds after a tooltip closes during which sibling tooltips open instantly, so sweeping the pointer along a row of triggers does not re-pay the open delay each time. An instantly-opened bubble reports data-state="instant-open".'},{name:"disableHoverableContent",type:"boolean",defaultValue:"false",required:!1,description:"Whether descendant bubbles ignore the pointer entirely, so moving off Trigger closes them. Defaults to false: the pointer can travel from Trigger into Content, which is what WCAG 2.2 SC 1.4.13 Hoverable requires. Each descendant can override it."},{name:"closeDelay",type:"number",defaultValue:"0",required:!1,description:"Delay in milliseconds before a descendant tooltip closes after the pointer leaves its Trigger. Each descendant can override it, and a hoverable bubble applies the 150 ms floor, so this value can only lengthen the window."}]},{name:"Trigger",description:'The button that opens the popover. Also the default positioning anchor, unless an Anchor part overrides it. Under openOn="hover" it reveals the panel on pointer enter and keeps focus throughout \u2014 the panel never steals it \u2014 and the recipe renders it as an anchor when href is set, which is what makes a hover panel reachable without a pointer. Under role="tooltip" it carries aria-describedby at the open bubble and must hold its own accessible name.'},{name:"Anchor",description:"Optional alternative positioning anchor \u2014 Content floats against this element instead of Trigger, for cases where the thing you click and the thing you point at differ."},{...e,description:`${e.description} Framework-conditional: React, Vue, Svelte ship a Portal component. Web Components ships <skdx-popover-portal> as a bare subclass (positioning uses strategy: 'fixed', nothing to escape). Angular uses [skdxPortal] directive. container is reachable everywhere, but in Web Components only as a property \u2014 DOM nodes cannot cross HTML attributes.`},{name:"Content",description:'The floating panel (role="dialog"). Owns positioning, dismissal interceptors (escape-key-down, pointer-down-outside, etc.), focus overrides, and modality (focus trap, inert barrier, scroll lock as modal requests). Under role="tooltip" it renders role="tooltip" instead and is inert: it moves no focus, traps none, holds nothing tabbable, and Tab passes through it as though it were closed \u2014 put buttons and links in a role="dialog" panel. Under openOn="hover" it accepts the pointer by default and reflects data-hoverable while it does, so the pointer can rest on the panel without closing it; disableHoverableContent drops the attribute and ignores the pointer entirely.',props:[...i(),a,{name:"arrowPadding",type:"number",defaultValue:"8",required:!1,description:"Clearance in pixels between the Arrow and panel edges, fed to the floating layer's arrow middleware. Prevents the arrow from sitting over rounded corners when shifted by collision avoidance. Arrow size stays in CSS; only clearance is computed. Default 8 matches the shipped skin's corner radius."},{name:"hideWhenDetached",type:"boolean",defaultValue:"false",required:!1,description:"Hide the panel while its anchor has scrolled out of view inside a clipping ancestor. The panel is hidden (visibility: hidden, pointer-events: none), never unmounted or closed \u2014 unmounting on scroll would tear down the focus trap and move focus unexpectedly. Scrolling the anchor back into view shows it again. Off by default because the extra overflow measurement on every reposition answers a question an anchor outside a scroll container never poses."},{name:"initialFocus",type:"string",required:!1,description:"CSS selector for the element that should receive focus when the popover opens, resolved with querySelector inside Content. Selector form matches Dialog/Drawer. Live only when modal contains focus ('trap-focus' or 'modal'); a 'none' popover never moves focus in. Applies only when open-auto-focus was not prevented. Falls back to the first tabbable element in Content, then Content itself."},{name:"finalFocus",type:"string",required:!1,description:"CSS selector for the element focus should be sent to when the popover closes, resolved at document level. Unlike initialFocus, this is live in every modality: Escape returns focus in all modes. Applies only when close-auto-focus was not prevented. Falls back to the trigger (or whatever was focused before opening) when the selector matches nothing."}]},{name:"Title",description:"The popover's accessible name. Generates an id and wires it onto Content's aria-labelledby while mounted. Optional in the sense that aria-label can replace it, never in the sense the panel may go unnamed."},{name:"Description",description:"Supporting text for the panel, wired onto Content's aria-describedby the same way and only while mounted."},t,{name:"Close",description:"A button inside Content that closes the popover."}],slots:[{name:"trigger",description:"Trigger's content \u2014 the button (or, with href, the anchor) that reveals the popover and anchors its position."},{name:"default",description:"The panel's body content, including a tooltip bubble's label text. In manual composition, Content's body from Title, Description, Arrow, and Close."},{name:"title",description:"Title's content \u2014 the popover's accessible name."},{name:"description",description:"Description's content \u2014 the popover's accessible description."}],states:["closed","open","delayed-open","instant-open"],controlledUncontrolled:"Stateless by default (uncontrolled): starts at defaultOpen and manages its own state internally. Passing open switches to controlled.",formBehavior:'Not applicable \u2014 Popover participates in no form; Trigger and Close are type="button".',validationBehavior:"Not applicable.",accessibility:{role:'dialog, or tooltip under role="tooltip"',keyboard:[{key:"Escape",behavior:'Requests close (cancelable via escape-key-down), refocuses Trigger. Under role="tooltip" the listener is on the document, so a hover-revealed bubble is dismissable even when focus is elsewhere (WCAG 2.2 SC 1.4.13).'},{key:"Tab / Shift+Tab",behavior:`Cycles focus within Content only while modal contains focus ('trap-focus' or 'modal'); leaves the panel into the page when modal is 'none'. Under role="tooltip" it is never intercepted \u2014 the bubble holds nothing tabbable and Tab moves through the page as if it were closed.`}],ariaAttributes:['aria-haspopup="dialog", aria-expanded, aria-controls on Trigger',"Trigger's aria-controls points at Content's id","aria-labelledby on Content points at Title's id, aria-describedby at Description's \u2014 each only while mounted","While focus-containing ('trap-focus' or true), everything outside is inert; focus is trapped","Focus-containing popovers must render a Close part \u2014 Escape is unavailable to touch screen-reader users",`Under role="tooltip" the Trigger instead points aria-describedby at Content's id, only while open, and neither aria-haspopup nor aria-expanded is emitted. Content must then hold text only: aria-describedby flattens every role and boundary inside it, so rich or interactive content belongs in a role="dialog" panel.`,"A hover popover accepts the pointer by default: it may leave Trigger and rest on the panel without it closing, which is the Hoverable requirement of WCAG 2.2 SC 1.4.13.","A hover popover is unreachable on touch-only input \u2014 there is no long-press path, and platform gestures take precedence. Anything it conveys must also be available from a control touch can reach, which is what the Trigger's href is for.","A tooltip bubble must contain no Trigger of its own. Nesting is unsupported: Escape is claimed by the top dismiss layer only, so an inner panel would swallow the outer one's dismissal."],focusManagement:`Traps focus in Content only when modal contains it ('trap-focus' or 'modal'); always returns focus to Trigger on Escape. Announces both moves as cancelable open-auto-focus / close-auto-focus events. Content's initialFocus and finalFocus selectors redirect these moves (applied only when events not prevented). initialFocus is inert while modal is 'none'; finalFocus is live in every mode. Under role="tooltip" the panel moves no focus at all in either direction \u2014 Trigger keeps it and the bubble only appears and disappears around it \u2014 so initialFocus goes unread and modal is forced to 'none'. A hover panel under role="dialog" likewise never pulls the caret off the trigger; if its content has to be operated, open it on click instead.`,namingRequirement:'Content is a role="dialog" and must be named: render a Title or set aria-label on Content. Unnamed panels announce as bare "dialog". Under role="tooltip" the obligation moves to the Trigger, which must carry its own accessible name \u2014 visible text, or an aria-label when icon-only. The bubble is wired as a description, and a description is not a name: an icon button whose only text lives in its tooltip is an unnamed button, and Content is never a naming source. A hover panel needs a focusable Trigger for the same reason \u2014 an <a> with no href is neither in tab order nor a link.'},styling:{cssParts:["trigger","anchor","content","title","description","arrow","close"],dataAttributes:[...l,"data-state","data-side","data-align","data-hoverable",{name:"data-skdx-popover-generated",frameworks:["webComponents"],exception:"wc-marker",frameworksReason:"Marks a node the Web Components port generated for itself rather than one the consumer authored; the other four frameworks re-render their derived anatomy declaratively, so they never need this disambiguation."}],cssCustomProperties:s("popover")},publicMethods:[{name:"reposition",frameworks:["vue","svelte","angular","webComponents"],exception:"imperative",frameworksReason:"React's root forwards no imperative handle and renders no element, so there is no instance to hang a method off \u2014 usePopoverContext is React's binding of this member and it is declared under contextApi.",signature:"() => void",description:"Recomputes the open panel's position immediately. Needed when the anchor moves for a reason the DOM never reports (CSS transform finishing, virtual list reflow, etc.). No-op while closed or unmounted."}],contextApi:[{name:"reposition",signature:"() => void",description:"Recomputes the open panel's position immediately for an anchor that moved without observers noticing.",accessors:{react:"usePopoverContext('MyComponent').reposition",vue:"popoverRef.value.reposition() \u2014 defineExpose'd on SkdxPopover",svelte:"popover.reposition() \u2014 the instance export on Popover",angular:"skdxPopoverRef.reposition()",webComponents:"document.querySelector('skdx-popover').reposition()"}}]};export{c as popoverContract};
@@ -0,0 +1,6 @@
1
+ import type { ComponentContract } from './types.js';
2
+ /**
3
+ * A progress bar with a linear root and a Circle/CircleIndicator
4
+ * pair that restates the same value as ring geometry.
5
+ */
6
+ export declare const progressContract: ComponentContract;
@@ -0,0 +1 @@
1
+ import{ROOT_DATA_ATTRIBUTES as e}from"./styling-hooks.js";var t={name:"Progress",purpose:'A bar for a number inside a known range. The root clamps value between min and max, renders role="progressbar" with the matching aria-value* attributes, and shares value/min/max with an Indicator part via context so the fill can be styled purely from CSS. With role="meter" the same bar becomes a gauge for a measurement that is not going anywhere \u2014 disk usage, a score, a battery \u2014 where low/high/optimum sort the range into bands published as data-range.',props:[{name:"role",type:"'progressbar' | 'meter'",defaultValue:"'progressbar'",required:!1,description:'What the bar is reporting, and therefore the ARIA role the root renders. "progressbar" is a task advancing towards completion and may be indeterminate or buffered. "meter" is a static measurement inside a range: aria-valuenow is always present, low/high/optimum sort the range into bands, and indeterminate and buffer have no meaning there.'},{name:"value",type:"number | null",defaultValue:"null",required:!1,description:'Current value. null renders an indeterminate progress bar; under role="meter" it reads as min instead, because a meter always reports a number and role="meter" requires aria-valuenow.'},{name:"min",type:"number",defaultValue:"0",required:!1,description:"Lower bound of the range, reflected as aria-valuemin. Defaults to 0, the value the range started at before the prop existed, so an existing bar is unaffected."},{name:"max",type:"number",defaultValue:"100",required:!1,description:"Upper bound of the range that value is measured against. Raised to min if passed below it. Defaults to 100 rather than the HTML <meter> element's 1, so the default percentage label reads as the literal value."},{name:"low",type:"number",required:!1,description:'Upper edge of the low band. Together with high and optimum it sorts the range into optimum/suboptimal/poor regions, published as data-range. Region rules follow the HTML <meter> element. Applies only under role="meter".'},{name:"high",type:"number",required:!1,description:'Lower edge of the high band, the counterpart of low and read under the same rules. Applies only under role="meter".'},{name:"optimum",type:"number",required:!1,description:'The ideal value, whose position relative to low and high decides which end of the range is good: below low makes low values good (disk usage), above high makes high values good (battery), between them makes the middle band good and leaves no poor band. Defaults to the range midpoint when low or high is given without it. Applies only under role="meter".'},{name:"buffer",type:"number | null",defaultValue:"null",required:!1,description:'A second value clamped into [min, max] and published as --skdx-progress-buffer. aria-valuenow keeps reporting value, since a buffer is not progress the user made. Applies only under role="progressbar": a measurement has nothing loading behind it.'},{name:"formatOptions",type:"Intl.NumberFormatOptions",required:!1,description:'Intl.NumberFormat options the value is formatted with for aria-valuetext and the Value part (currency, percent, unit, grouping) \u2014 the canonical formatting route. Formats the raw value, exactly as NumberField does, so with style: percent the value is the fraction and 0.5 reads "50%". Serializable, so it crosses the Web Components attribute boundary as JSON where a function cannot; getValueLabel remains the escape hatch for a string Intl cannot produce, and wins when both are supplied.'},{name:"locale",type:"string",required:!1,description:"BCP-47 locale the formatting uses, resolved once in the root through Intl.NumberFormat(locale).resolvedOptions().locale so a server render and a browser render agree. Defaults to the runtime locale. Resolution only happens while formatting is on (locale or formatOptions given); without either, the label falls through to the default percentage untouched by Intl."},{name:"getValueLabel",type:"(value: number, min: number, max: number) => string",required:!1,description:'Formats aria-valuetext. Defaults to a rounded percentage of the position within [min, max], e.g. "66%". Takes min as well as max because the range does not have to start at zero. Supplying it is the escape hatch: formatOptions is the canonical route and covers currency, percent, unit and grouping, so reach for this only when the string is one Intl cannot produce. It wins over formatOptions when both are given.'},{name:"circular",type:"boolean",defaultValue:"false",required:!1,description:"Renders the circular anatomy \u2014 a ring and its indicator \u2014 instead of the linear bar."},{name:"label",type:"string",required:!1,description:"Text naming what is progressing or being measured; when absent no label element is rendered. Renders in both the linear and the circular shape, under either role."},{name:"showValue",type:"boolean",defaultValue:"false",required:!1,description:"Renders the formatted value alongside the indicator."},{name:"indeterminate",type:"boolean",defaultValue:"false",required:!1,description:'Marks progress as unmeasurable, overriding `value`. Equivalent to `value: null`, which stays supported; when both are given `indeterminate` wins. Applies only under role="progressbar" \u2014 a meter always reports a number, so it is ignored there.'},{name:"diameter",type:"number",defaultValue:"48",required:!1,description:"Outer diameter of the circular track, in the unitless SVG user units the Circle part documents \u2014 the same number the consumer puts in their own viewBox, not a CSS length. Applies only when `circular`."},{name:"strokeWidth",type:"number",defaultValue:"4",required:!1,description:"Stroke width of the circular track, in the same unitless units as `diameter`. Insets the radius by half its value so the stroke stays inside the diameter box. Applies only when `circular`."}],events:[],parts:[{name:"Label",description:`The bar's visible name. Generates an id the root points aria-labelledby at while this part is mounted, so a bar with a visible caption needs no second copy of that caption in an aria-label. Neither role="progressbar" nor role="meter" takes a name from its contents, which is exactly why the id has to be wired rather than left to the accessible-name computation.`},{name:"Value",description:"The visible readout \u2014 the same string the root announces through aria-valuetext. Rendered aria-hidden for that reason: without it a screen reader hears the value twice, once as the root's valuetext and once as descendant text. Renders getValueLabel(value, min, max) when given no children of its own, and nothing at all while indeterminate, because there is no value to read out."},{name:"Indicator",description:`The visual fill inside the linear root. Mirrors the root's data-state / data-value / data-min / data-max \u2014 and data-range under role="meter", so a skin can paint the band without reading the thresholds itself \u2014 and sets --skdx-progress to the position of value inside [min, max], so width or transform can be driven purely from CSS. Publishes --skdx-progress-buffer the same way when a buffer is set. Both properties are absent while indeterminate (and the buffer one when no buffer was given), so an unset value falls through to the consumer's own animation instead of pinning the fill at a value the component does not have.`},{name:"Circle",description:`Geometry host for a ring. Renders no SVG of its own \u2014 it publishes the ring's arithmetic as CSS custom properties (--skdx-progress-circle-size, --skdx-progress-circle-thickness, --skdx-progress-circle-radius, --skdx-progress-circle-circumference, --skdx-progress-dasharray, --skdx-progress-circle-offset) so the consumer brings their own <svg> and drives stroke-dasharray / stroke-dashoffset from CSS alone. The first two keep their published names after the diameter/strokeWidth prop rename: a renamed prop breaks at compile time, a renamed custom property breaks silently in a stylesheet no compiler reads. Mirrors the root's data-state / data-value / data-min / data-max, and adds no second role="progressbar": the ARIA lives on the root this must be used inside.`,props:[{name:"diameter",type:"number",defaultValue:"48",required:!1,description:"Outer diameter of the ring in unitless SVG user units \u2014 the number that also goes in the consumer's own viewBox. Unitless rather than a CSS length because it feeds stroke-dasharray/stroke-dashoffset, which are path lengths CSS cannot convert. Named diameter rather than size: the system reserves size for the appearance rung no component ships, and a geometry number that reads as a design token is a number some tool will eventually mis-read."},{name:"strokeWidth",type:"number",defaultValue:"4",required:!1,description:"Stroke width of the ring in the same unitless units as diameter. Insets the radius by half its value ((diameter - strokeWidth) / 2) so the stroke stays inside the diameter box rather than clipping at the viewBox edge. Named after the SVG presentation attribute it feeds, following the diameter rename."}]},{name:"CircleIndicator",description:"The swept arc of a Circle \u2014 the circular counterpart of Indicator, usually rendered onto the consumer's own <circle> or <path> because the default element has no stroke. Mirrors the root's data-state / data-value / data-max, repeats the value-dependent ring properties (--skdx-progress-circle-circumference, --skdx-progress-dasharray, --skdx-progress-circle-offset) on itself so the arc element can be styled directly, and adds --skdx-progress as a percentage for anything measured in percent rather than path length. Must be used inside a Circle."}],slots:[{name:"default",description:"The bar's body \u2014 typically an Indicator part, or a Circle wrapping the consumer's own <svg> with a CircleIndicator on the arc, optionally preceded by a Label and a Value."}],states:["indeterminate","loading","complete","optimum","suboptimal","poor"],controlledUncontrolled:"Stateless \u2014 the root only clamps and mirrors the value prop, it holds no state.",formBehavior:"Not applicable \u2014 the bar participates in no form.",validationBehavior:"Not applicable \u2014 the bar carries a value but participates in no validation.",accessibility:{role:'progressbar (default), or meter when role="meter"',keyboard:[],ariaAttributes:["aria-valuemin reflects the min prop (0 by default)","aria-valuemax reflects the max prop",'aria-valuenow reflects the clamped value \u2014 omitted when indeterminate, and always present under role="meter", which has no indeterminate state','aria-valuetext reflects getValueLabel(value, min, max), or Intl.NumberFormat(locale, formatOptions).format(value) when formatOptions or locale is supplied instead (omitted when indeterminate). Under role="meter" it is emitted only when one of those is supplied or the range is 0..100, because a rounded percentage is not the value on any other range and it overrides the aria-valuenow that is',"aria-labelledby points at the Label part while one is mounted, unless the consumer supplied their own"],focusManagement:"Not focusable; not part of the tab order.",namingRequirement:"The root must carry an accessible name via aria-label, a resolving aria-labelledby, or a mounted Label part (which wires aria-labelledby for the consumer). Neither role takes a name from its contents, so the percentage rendered inside the bar is announced as a bare number with nothing saying what is at that number."},styling:{cssParts:["root","label","value","indicator","circle","circle-indicator"],dataAttributes:[...e,"data-state","data-value","data-min","data-max",{name:"data-range",description:'On the root and the Indicator under role="meter": which band the value falls into \u2014 optimum, suboptimal or poor \u2014 derived from low/high/optimum, and absent when no threshold was given.'},{name:"data-skdx-progress-generated",frameworks:["webComponents"],exception:"wc-marker",frameworksReason:'Marks a node the element generated for itself rather than one the consumer authored. React, Vue, Svelte and Angular re-render their derived anatomy declaratively, so "mine or theirs" is answered by the framework and no marker is needed.'}],cssCustomProperties:["--skdx-progress","--skdx-progress-buffer","--skdx-progress-dasharray","--skdx-progress-circle-size","--skdx-progress-circle-thickness","--skdx-progress-circle-radius","--skdx-progress-circle-circumference","--skdx-progress-circle-offset"]},publicMethods:[]};export{t as progressContract};
@@ -0,0 +1,5 @@
1
+ import type { ComponentContract } from './types.js';
2
+ /**
3
+ * An encoder that turns a string into a module matrix, and an SVG surface that draws it.
4
+ */
5
+ export declare const qrCodeContract: ComponentContract;
@@ -0,0 +1 @@
1
+ import{ROOT_DATA_ATTRIBUTES as e}from"./styling-hooks.js";var r={name:"QrCode",purpose:"A QR code encoder. The root encodes a string into a module matrix, shares it with an SVG Frame and Pattern path, and optional Overlay for a logo. Payload rendered as visually hidden text \u2014 not a dead end without a camera.",props:[{name:"value",type:"string",required:!0,description:"The payload to encode. Encoded as UTF-8 bytes; only length can exceed capacity."},{name:"errorCorrection",type:"'L' | 'M' | 'Q' | 'H'",defaultValue:"'M'",required:!1,description:"Error-correction level: L ~7%, M 15%, Q 25%, H 30% redundancy. Overlay requires H \u2014 nothing raises it automatically."},{name:"version",type:"number",required:!1,description:"Force a symbol version (1\u201340), fixing the module count at 4 \xD7 version + 17. Too small for the value is an encode failure, not a silent upgrade."},{name:"hiddenLabel",type:"boolean | string",defaultValue:"true",required:!1,description:"Visually hidden text inside the root, so a screen-reader user reaches the destination without a camera. true renders value; string renders that instead; false renders none. Pass string for payloads not meant to be read aloud (credentials, tokens)."},{name:"overlay",type:"unknown",required:!1,frameworks:["react","svelte","angular"],exception:"render-prop",frameworksReason:"Vue and Web Components use a named slot \u2014 Vue idiom, Web Components because attributes carry strings, not nodes. Both slot spellings declared under `slots`.",description:"Content laid over the centre of the code, typically a logo. The code's error correction level must be high enough to survive the occlusion."}],events:[{name:"encode-error",description:"Fired when value cannot be encoded \u2014 exceeds capacity or version is outside 1\u201340. The root renders nothing in that case rather than a broken symbol.",detail:"Error"}],parts:[{name:"Frame",description:'The <svg> host with viewBox extent as module count. ARIA follows what it is named \u2014 role="img" if labelled, aria-hidden if not. Use aria-label or aria-labelledby; <title> children do not count.'},{name:"Pattern",description:"The single <path> carrying every dark module. One path rather than one rect per module \u2014 for page weight."},{name:"Overlay",description:"The centred slot for a logo, drawn in module units so it scales with the symbol. Warns in development when errorCorrection is not 'H' \u2014 overlay destroys modules that only 'H' can reconstruct.",props:[{name:"extent",type:"number",defaultValue:"7",required:!1,description:"Edge length of the overlay box in module units (same coordinate space as viewBox). Defaults to finder pattern width. Keep it under roughly a fifth of the symbol's edge \u2014 larger patches damage more modules than H error correction can reconstruct."}]}],slots:[{name:"default",description:"The code's body \u2014 a Frame wrapping a Pattern, and optionally an Overlay."},{name:"overlay",description:"Overlay's content \u2014 typically a logo drawn over the centre of the code."}],states:[],controlledUncontrolled:"Stateless \u2014 the matrix is derived from value, errorCorrection and version on every change, and nothing is held between renders.",formBehavior:"Not applicable \u2014 QrCode renders a value, it collects none.",validationBehavior:"Encoding capacity is the only constraint, and exceeding it is reported through the encode-error event rather than rendered as an invalid state.",accessibility:{role:"img (Frame, only when named \u2014 aria-hidden otherwise)",keyboard:[],ariaAttributes:['role="img" on the Frame when named; aria-hidden on the Frame when no name is given',"Visually hidden payload text (rendered on root by default) gives non-sighted users the destination"],focusManagement:"None \u2014 nothing here is focusable. A QR code is content, not a control; if it should be actionable, the consumer wraps it in a link or a button.",namingRequirement:"Name the Frame when the symbol is the only copy of the destination. Leave unnamed when the destination is written out beside it."},styling:{cssParts:["root","frame","svg","pattern","overlay","hidden-label"],dataAttributes:[...e,{name:"data-skdx-qr-code-generated",frameworks:["webComponents"],exception:"wc-marker",frameworksReason:'Marks a node the element generated for itself rather than one the consumer authored. React, Vue, Svelte and Angular re-render their derived anatomy declaratively, so "mine or theirs" is answered by the framework and no marker is needed.'}],cssCustomProperties:["--skdx-qr-code-size"]},publicMethods:[]};export{r as qrCodeContract};
@@ -0,0 +1,6 @@
1
+ import type { ComponentContract } from './types.js';
2
+ /**
3
+ * A radio whose hit target is a whole card, built on a real
4
+ * `<input type="radio">` inside a RadioGroup.
5
+ */
6
+ export declare const radioCardContract: ComponentContract;
@@ -0,0 +1 @@
1
+ import{ROOT_DATA_ATTRIBUTES as e}from"./styling-hooks.js";var a={name:"RadioCard",purpose:'A radio with card-sized hit target for RadioGroup, built as a <label> wrapping a hidden <input type="radio">, with Indicator, Label, and Description parts.',props:[{name:"value",type:"string",required:!0,description:"Unique identifier compared against the RadioGroup's selected value."},{name:"disabled",type:"boolean",defaultValue:"false",required:!1,description:"Disables this card only; a group-level disabled takes precedence and cannot be re-enabled per card."},{name:"hasLabel",type:"boolean",defaultValue:"false",required:!1,description:"Svelte-only: declares that a Label is present, so server-rendered markup carries aria-labelledby before hydration. Other frameworks detect it during render.",frameworks:["svelte"],exception:"snippet-opaque",frameworksReason:"React and Vue scan children for the part during render; Angular detects it in its first change-detection pass; Web Components queries real DOM children. Svelte receives children as an opaque Snippet, so it takes an explicit prop instead. The real registration on mount is authoritative."},{name:"hasDescription",type:"boolean",defaultValue:"false",required:!1,description:"Svelte-only: declares a Description is present for aria-describedby.",frameworks:["svelte"],exception:"snippet-opaque",frameworksReason:"Same reason as hasLabel: Svelte cannot inspect a Snippet, so it needs an explicit prop."},{name:"label",type:"string",required:!1,description:"Title text, rendered into the Label that `aria-labelledby` points at. When supplied, the card derives Control, Indicator, and Label automatically; omit it and an `aria-label` on the control is required. This all-or-nothing behaviour preserves the anatomy as the card itself, not optional additions."},{name:"description",type:"string",required:!1,description:"Supporting copy under the title, which derives a Description part and `aria-describedby`. The only optional part of the derived anatomy; a card without supporting copy is still a card."},{name:"checked",type:"boolean",required:!1,frameworks:["webComponents"],exception:"wc-internals",frameworksReason:"Only the custom element publishes it. The other four hand this derived state down to their parts through context, so a consumer never reads it off a part; here every part is its own element with no such channel, and reading it back is the only way to reflect the state in surrounding markup.",description:"Whether this card currently holds the group's selected value. Read-only: pick it through the group's value. It has no defaultChecked twin, because the seed for an uncontrolled group is RadioGroup's own defaultValue and a second seed on the card would let the two disagree."},{name:"effectiveDisabled",type:"boolean",required:!1,frameworks:["webComponents"],exception:"wc-internals",frameworksReason:"Only the custom element publishes it. The other four hand this derived state down to their parts through context, so a consumer never reads it off a part; here every part is its own element with no such channel, and reading it back is the only way to reflect the state in surrounding markup.",description:"Whether this card is disabled, by its own disabled or by the group's. Read-only: it is the OR of the two."},{name:"size",type:"'sm' | 'md' | 'lg' | (string & {})",required:!1,description:"Visual size rung, written to data-size on the root; the data-size attribute may be set directly instead."}],events:[],parts:[{name:"Control",description:"The hidden radio input, still focusable so the browser owns activation and focus. Points aria-labelledby at the Label and aria-describedby at the Description when mounted."},{name:"Indicator",description:"The drawn dot or ring, aria-hidden because the control already reports its own checked state."},{name:"Label",description:"The card's title, and the accessible name."},{name:"Description",description:"Supporting copy announced after the name, referenced by aria-describedby so it is pronounced rather than folded into it."}],slots:[{name:"default",description:"The card's body: Control, Indicator, Label, and usually Description."}],appearance:[{attribute:"data-size",values:["sm","md","lg"],stylesheet:"radio-card.css"}],states:["checked","unchecked","focus-visible","disabled"],controlledUncontrolled:"Neither \u2014 RadioCard holds no state of its own. Selection belongs to the enclosing RadioGroup.",formBehavior:`A real <input type="radio"> carrying the group's name in React, Vue, Svelte and Angular, so exclusivity and form submission are native rather than reimplemented. The Web Components Control is an ARIA radio instead \u2014 a visually-hidden element with role="radio", aria-checked and the roving tab stop \u2014 and the value reaches the form through its group's ElementInternals, because a shadow-root input is never associated with the ancestor form.`,validationBehavior:'None of its own; a group-level invalid flag applies. Requiredness belongs to the group \u2014 "pick one of these" is a statement about the set, not a single card \u2014 and the paint comes via a descendant rule: an invalid group\'s aria-invalid/data-invalid reaches its cards through `.skdx-radio-group[data-invalid] .skdx-radio-card`.',accessibility:{role:"radio \u2014 from the native input, not an ARIA role",keyboard:[{key:"Arrow keys",behavior:'Move between cards and select as they go, handled by RadioGroup. Mirrored under dir="rtl".'},{key:"Tab",behavior:"A single stop for the whole group: only the checked card \u2014 or the first enabled one when nothing is checked \u2014 is tabbable, so a ten-option group costs one tab press rather than ten."},{key:"Space",behavior:"Selects the focused card."}],ariaAttributes:["aria-labelledby on the control pointing at the Label, and only when one is mounted","aria-describedby on the control pointing at the Description, on the same condition","The association must hold in server-rendered markup as well as after hydration, which the registration alone does not give: effects never run on the server, so a control shipped naming nothing has its accessible name silently widened to the card's whole text content \u2014 and for an un-hydrated island that markup is the whole product. It is resolved from what the children declare or from real DOM children one render earlier, with the registration staying the authority once it has run; where no render-time signal exists, explicit hasLabel/hasDescription props (default false) seed the server-rendered guess.","aria-hidden on the Indicator, which draws a state the control already reports",'aria-disabled="true" on the control while disabled, in Web Components only. There the control is an ARIA role="radio" widget rather than a native <input type="radio">, so there is no native disabled attribute to carry the semantics; React, Vue, Angular and Svelte set the native attribute and must not add aria-disabled on top of it.',"data-value on the root, so the selected card is addressable from CSS without reading the input"],focusManagement:"Focus lives on the hidden input, never on the card. Roving tabindex is owned by the group: exactly one card is a tab stop at a time. data-focus-visible is set only for keyboard focus, so a ring appears when it should and not on every click.",namingRequirement:"A Label part, or an explicit aria-label on the control when the card has no visible title. The Description is deliberately excluded from the name, so the announcement stays the title rather than the whole card."},styling:{cssParts:["radio-card","control","indicator","label","description"],dataAttributes:[...e,"data-state","data-disabled","data-focus-visible","data-value","data-size",{name:"data-skdx-radio-card-generated",frameworks:["webComponents"],exception:"wc-marker",frameworksReason:'Marks a node the element generated for itself rather than one the consumer authored. React, Vue, Svelte and Angular re-render their derived anatomy declaratively, so "mine or theirs" is answered by the framework and no marker is needed.'}],cssCustomProperties:[]},publicMethods:[]};export{a as radioCardContract};
@@ -0,0 +1,6 @@
1
+ import type { ComponentContract } from './types.js';
2
+ /**
3
+ * Single-selection radio group with roving-tabindex arrow-key navigation
4
+ * and optional form participation via per-item hidden inputs.
5
+ */
6
+ export declare const radioGroupContract: ComponentContract;
@@ -0,0 +1 @@
1
+ import{changeDescription as a,changeDetail as e}from"./change-reason.js";import{constraintValidationMethods as t,setCustomValidityMethod as r}from"./form-validity.js";import{ROOT_DATA_ATTRIBUTES as i}from"./styling-hooks.js";var d={name:"RadioGroup",purpose:"A single-selection group of radio buttons. Manages roving tabindex and arrow-key/Home/End navigation between items \u2014 the checked item (or the first enabled one, when none is checked) is the sole tab stop.",props:[{name:"value",type:"string | null",required:!1,description:'Selected value for controlled usage. null means controlled with nothing chosen; undefined is reserved for "uncontrolled".'},{name:"defaultValue",type:"string | null",required:!1,description:"Initial value for uncontrolled usage; accepts null or undefined."},{name:"name",type:"string",required:!1,description:"Name for form submission via hidden input on each item."},{name:"form",type:"string",required:!1,description:"Form id when group is rendered outside the form."},{name:"required",type:"boolean",defaultValue:"false",required:!1,description:"Require a selection for form validation."},{name:"disabled",type:"boolean",defaultValue:"false",required:!1,description:"Disable all items."},{name:"readOnly",type:"boolean",defaultValue:"false",required:!1,description:"Freeze selection without freezing group. The roving tab stop is unchanged, arrow keys work, nothing gains aria-disabled, and items keep submitting."},{name:"invalid",type:"boolean",defaultValue:"false",required:!1,description:"Mark group invalid; exposed as aria-invalid/data-invalid."},{name:"orientation",type:"'horizontal' | 'vertical' | 'both'",defaultValue:"'both'",required:!1,description:'Arrow-key navigation axis; "both" responds to all four arrows.'},{name:"loop",type:"boolean",defaultValue:"true",required:!1,description:"Arrow-key navigation wraps from last item to first; defaults to true per APG. A segmented ToggleGroup turns looping off instead, because pressing follows focus there and a wrap would silently re-press the item at the other end."},{name:"options",type:"ReadonlyArray<{ value: string; label: string; disabled?: boolean }>",required:!1,description:"Radios the group derives \u2014 one Item per entry with its label. Flat only; no option-group shape."}],events:[{name:"value-change",description:a("the selected item"),detail:e("string")},{name:"value-change-detail",frameworks:["angular"],exception:"event-shape",frameworksReason:"Angular's `valueChange` emits the scalar so `[(value)]` round-trips the value itself; this second output carries the detail object the other four hand to `value-change`.",description:"Fires with valueChange, carrying the previous value and the reason for the change.",detail:e("string")}],parts:[{name:"Item",description:'One radio with role="radio", aria-checked, aria-disabled, data-state, data-disabled, and data-value. Plus hidden input when group has a name.',props:[{name:"checked",type:"boolean",required:!1,frameworks:["webComponents"],exception:"wc-internals",frameworksReason:"Only the custom element publishes it. The other four hand this derived state down to their parts through context, so a consumer never reads it off a part; here every part is its own element with no such channel, and reading it back is the only way to reflect the state in surrounding markup.",description:"Whether this item currently holds one of the group's selected values. Read-only: pick or clear it through the root's value."},{name:"value",type:"string",required:!0,description:"Unique identifier compared to group's value; required."},{name:"disabled",type:"boolean",defaultValue:"false",required:!1,description:"Disable this item; skipped by arrow keys and does not claim tab stop."}]},{name:"Indicator",description:"Selection mark inside the checked item; shown only when checked.",props:[{name:"forceMount",type:"boolean",defaultValue:"false",required:!1,description:"Keep mark present when unselected; lets animation libraries animate exits."}]}],slots:[{name:"default",description:"RadioGroupItem children."}],states:["default","readonly"],controlledUncontrolled:'Controlled via value + a change event, or uncontrolled via defaultValue. The controlled/uncontrolled decision is "is value undefined", so null \u2014 not undefined \u2014 is the value that means "controlled, nothing selected". In Angular the pair is split: `valueChange` emits the scalar for `[(value)]`, `valueChangeDetail` carries the detail.',formBehavior:'Each item renders a hidden native <input type="radio"> when the group has a name, in React, Vue, Svelte and Angular. Web Components publishes the selected value through ElementInternals instead, because an input inside the shadow root is never associated with the ancestor form. readOnly keeps items submitting either way.',validationBehavior:"required marks inputs required. checkValidity()/reportValidity() delegate to one hidden input, which answers for the whole group because they all share the group's name. setCustomValidity() writes to the same input. Without a name, both readable methods report valid and the write is dropped. invalid exposes aria-invalid/data-invalid on the root.",accessibility:{role:"radiogroup",keyboard:[{key:"ArrowRight/ArrowDown",behavior:'Move focus to (and select) next item. Mirrored under dir="rtl": ArrowLeft is what moves to the *next* item there.'},{key:"ArrowLeft/ArrowUp",behavior:"Move focus to (and select) previous item."},{key:"Home",behavior:"Move focus to (and select) first item."},{key:"End",behavior:"Move focus to (and select) last item."}],ariaAttributes:["aria-required reflects required","aria-invalid reflects invalid","aria-readonly on root (not aria-disabled)","each item exposes aria-checked, and aria-disabled while it is disabled"],focusManagement:"Roving tabindex \u2014 checked item (or first enabled) is sole tab stop. Arrow keys select; external focus does not. First-enabled fallback is resolved during render.",namingRequirement:'Root must be named via Fieldset legend or aria-label/aria-labelledby. role="radiogroup" does not inherit item labels.'},styling:{cssParts:["radio-group","item","indicator"],dataAttributes:[...i,"data-orientation","data-disabled","data-readonly","data-invalid","data-state","data-value",{name:"data-skdx-radio-group-generated",frameworks:["webComponents"],exception:"wc-marker",frameworksReason:'Marks a node the element generated for itself rather than one the consumer authored. React, Vue, Svelte and Angular re-render their derived anatomy declaratively, so "mine or theirs" is answered by the framework and no marker is needed.'}],cssCustomProperties:[]},publicMethods:[...t,r,{name:"setValue",signature:"(value: string, reason?: RadioGroupChangeReason) => void",frameworks:["webComponents"],exception:"imperative",frameworksReason:"Only the custom element publishes it. The other four re-render with a new value prop and never expose a setter; a Web Components consumer holds the element itself, so the same change is made by calling this method on it.",description:"Selects the item named by value and emits value-change carrying reason."}],frameworkExtensions:[{framework:"webComponents",name:"requiredMessage",type:"string",description:"Custom message shown when the required constraint fails; Web Components only, set from markup with the required-message attribute."}]};export{d as radioGroupContract};
@@ -0,0 +1,6 @@
1
+ import type { ComponentContract } from './types.js';
2
+ /**
3
+ * The Rating contract: a `role="radiogroup"` of `role="radio"` items with roving-tabindex
4
+ * navigation and hover-preview highlighting.
5
+ */
6
+ export declare const ratingContract: ComponentContract;
@@ -0,0 +1 @@
1
+ import{changeDescription as t,changeDetail as e}from"./change-reason.js";import{constraintValidationMethods as a,setCustomValidityMethod as i}from"./form-validity.js";import{ROOT_DATA_ATTRIBUTES as r}from"./styling-hooks.js";var l={name:"Rating",purpose:"Single-selection rating widget (e.g. stars). Highlights hovered/selected item and all before it. Roving-tabindex navigation (horizontal, no wrap); arrows clamp at both ends. The selected item (or 1 when nothing is selected) is the sole tab stop.",props:[{name:"value",type:"number",required:!1,description:"Selected value, for controlled usage."},{name:"defaultValue",type:"number",defaultValue:"0",required:!1,description:"Initial value, for uncontrolled usage.",frameworks:["react","vue","svelte","angular"],exception:"wc-default",frameworksReason:"Web Components has no default-value member and will not grow one: the authored value attribute is the seed, exactly as <input value> seeds a native input and as switch already documents."},{name:"max",type:"number",defaultValue:"5",required:!1,description:"The number of items on the scale and the highest value the rating can hold. In whole-item mode it is a count of radios; with allowHalf it is aria-valuemax on the root slider."},{name:"itemLabel",type:"(value: number, max: number) => string",defaultValue:"(value, max) => `${value} of ${max} stars`",required:!1,description:"Names every item (applied as aria-label). Each item is a role=radio with only an icon, so without this a screen-reader user cannot tell which star they are on. Takes max and value to name the score out of the total. An aria-label on the item itself wins over this."},{name:"allowClear",type:"boolean",defaultValue:"false",required:!1,description:"Lets the committed value clear to 0 by picking it again (clicking the checked item, or pressing Space). Off by default, where re-picking the current value is swallowed and emits nothing. With allowHalf, the leading half clears and the trailing half sets the next value. Clearing fires value-change with 0."},{name:"allowHalf",type:"boolean",defaultValue:"false",required:!1,description:"Allow half-item values (0.5, 1, 1.5, \u2026). Pointer picks from the leading half (trailing under RTL); arrow keys step by 0.5. Changes the ARIA: the root becomes role=slider with aria-valuenow/aria-valuetext, and items become role=presentation."},{name:"disabled",type:"boolean",defaultValue:"false",required:!1,description:"Disables every item."},{name:"readOnly",type:"boolean",defaultValue:"false",required:!1,description:"Displays the current value but blocks interaction (still focusable, unlike disabled)."},{name:"name",type:"string",required:!1,description:"Form field name. The selected value is submitted under it; without it the rating submits nothing."},{name:"required",type:"boolean",defaultValue:"false",required:!1,description:"Marks the rating required. valueMissing while the value is 0, as for a radio group."},{name:"form",type:"string",required:!1,description:"Id of the `<form>` that owns this rating, for a rating rendered outside it. Decides which form's reset restores the initial rating."},{name:"icon",type:"unknown",required:!1,frameworks:["react","svelte","angular"],exception:"render-prop",frameworksReason:"Vue and Web Components take this as a named slot rather than a prop \u2014 Vue because a renderable region is a slot in Vue's own idiom, Web Components because a custom element attribute carries a string and cannot carry a node. The content hole is the same one in all five; only the way a node reaches it differs, and on a custom element markup is the only route in. Both slot spellings are declared under `slots`.",description:"Glyph rendered for each item. Defaults to a built-in star."},{name:"size",type:"'md' | 'sm' | 'lg' | (string & {})",required:!1,description:"Visual size rung, written to data-size on the root; the data-size attribute may be set directly instead."}],events:[{name:"value-change",detail:e("number"),description:`${t("the rating")} Re-picking the current value is swallowed unless allowClear is set. An unset rating and a rating of 0 are the same state: 0 is the resting value, what aria-valuenow reports, and what counts as valueMissing when required.`},{name:"value-change-detail",frameworks:["angular"],exception:"event-shape",frameworksReason:"Angular's `valueChange` emits the scalar so `[(value)]` round-trips the value itself; this second output carries the detail object the other four hand to `value-change`.",description:"Fires with valueChange, carrying the previous rating and the reason for the change.",detail:e("number")},{name:"hover-value-change",description:"Fires with the value the pointer is previewing, or null when it leaves. Display-only \u2014 the preview never writes the committed value.",detail:"number | null"}],parts:[{name:"Item",description:'One position on the scale (e.g. a star). A role="radio" in whole-item mode, or role="presentation" when allowHalf turns the root into role="slider". Publishes data-state, data-highlighted (on itself and all items before it), and data-half. Clicking, focusing or hovering commits or previews its value; with allowHalf, the leading half commits value - 0.5.',props:[{name:"value",type:"number",required:!0,description:"This item's 1-indexed position on the scale. Determines what the item commits when picked and what itemLabel is called with."},{name:"disabled",type:"boolean",defaultValue:"false",required:!1,description:"Excludes this item from selection, hover preview and roving focus. OR-ed with the root's disabled, not overriding it."}]}],slots:[{name:"default",description:"RatingItem children, one per position."},{name:"item",description:"A single RatingItem's content, e.g. a star icon."},{name:"icon",description:"The glyph rendered for each item in the rating."}],appearance:[{attribute:"data-size",values:["md","sm","lg"],stylesheet:"rating.css"}],states:["default","checked","unchecked","highlighted","half","disabled"],controlledUncontrolled:"Supports both: value + onValueChange (controlled) or defaultValue (uncontrolled). In Angular the pair is split: `valueChange` emits the scalar for `[(value)]`, `valueChangeDetail` carries the detail.",formBehavior:'Form-associated: with a name, the selected value is submitted. Like a radio group, a rating of 0 carries no value and is valueMissing when required \u2014 Web Components submit no entry at all there, while React/Vue/Svelte/Angular submit one empty entry, because a mirrored input that is not rendered cannot report valueMissing (the same trade-off the Select contract makes for an empty selection). With allowHalf the tab stop is the root div role="slider" rather than the item buttons, so a <fieldset disabled> ancestor stops submission (the mirrored input is disabled) but does not disable the root itself \u2014 pass disabled explicitly there. Web Components has no default-value member and will not grow one: the authored value attribute is the seed, exactly as <input value> seeds a native input and as switch already documents. A form reset restores the initial rating \u2014 silently in Web Components, and by firing value-change in React/Vue/Svelte/Angular, where a controlled value belongs to the parent and would otherwise be restored straight back.',validationBehavior:"required participates in native constraint validation, reported through checkValidity()/reportValidity(). setCustomValidity() writes the third half: an error the browser cannot derive \u2014 a server response, a cross-field rule \u2014 lands on the same control that carries the constraint, so checkValidity() sees it and reportValidity() shows it, and '' clears it. Dropped without a name, matching the reads, since there is then no control and nothing is submitted. One Web-Components-only attribute sits alongside this and is deliberately NOT contracted: required-message, which replaces the English wording the browser shows for a failed required constraint. It is not a Rating capability \u2014 it comes from the FormAssociated mixin and every form-associated skdx element carries it \u2014 and it exists there because that string is sealed inside a shadow root, a problem the other four packages do not have since their control is a native input in the consumer's own tree. See the ruling in form-validity.ts, decided once for Rating, Switch, ToggleGroup and Checkbox.",accessibility:{role:'radiogroup (root), radio (each item) \u2014 or slider (root), role="presentation" (each item) when allowHalf is set',keyboard:[{key:"ArrowRight/ArrowDown",behavior:"Moves focus (and selection) to the next item; with allowHalf, increases the value by 0.5."},{key:"ArrowLeft/ArrowUp",behavior:"Moves focus (and selection) to the previous item; with allowHalf, decreases the value by 0.5."},{key:"Home",behavior:"Sets the value to 0, in every mode, as the slider pattern requires."},{key:"End",behavior:"Sets the value to max, in every mode, as the slider pattern requires."},{key:"Space",behavior:"Whole-item mode: commits the focused item's value, or clears to 0 if already committed and allowClear is set. In allowHalf mode, items are not focusable and Space does nothing."},{key:"Enter",behavior:"Suppressed. Enter on a focused item would activate the native button and submit the form; Space is the activation key here."}],ariaAttributes:["aria-checked on each item (whole-item mode)","aria-label on each item (whole-item mode), from itemLabel(value, max) \u2014 unless the item carries its own aria-label","aria-valuemin/aria-valuemax/aria-valuenow/aria-valuetext/aria-orientation on the root (allowHalf)",'role="presentation" on each item (allowHalf) \u2014 non-focusable span carrying pointer handlers',"aria-disabled/aria-readonly on the root"],focusManagement:"Whole-item mode: roving tabindex on the checked item (or 1 when none is checked). With allowHalf: the root is the sole tab stop and items leave the tab order.",namingRequirement:"The root needs an accessible name in both modes (aria-label or aria-labelledby) \u2014 neither radiogroup nor slider takes its name from content."},styling:{cssParts:["rating","item"],dataAttributes:[...r,"data-disabled","data-readonly","data-state","data-highlighted","data-half","data-size","data-skdx-rating-item",{name:"data-skdx-rating-generated",frameworks:["webComponents"],exception:"wc-marker",frameworksReason:'Marks a node the element generated for itself rather than one the consumer authored. React, Vue, Svelte and Angular re-render their derived anatomy declaratively, so "mine or theirs" is answered by the framework and no marker is needed.'}],cssCustomProperties:[]},publicMethods:[...a,i],frameworkExtensions:[{framework:"webComponents",name:"requiredMessage",type:"string",description:"Replaces the browser's message when a required rating is submitted empty. Web-Components-only, from the FormAssociated mixin, and set from markup with the required-message attribute. The other four expose `setCustomValidity()` on the hidden input in the consumer's tree."}]};export{l as ratingContract};
@@ -0,0 +1,3 @@
1
+ import type { ComponentContract } from './types.js';
2
+ /** Contract for the ResetPasswordPage block: a new password with its rules and an optional matched confirmation. */
3
+ export declare const resetPasswordPageContract: ComponentContract;
@@ -0,0 +1 @@
1
+ import{ROOT_DATA_ATTRIBUTES as e}from"./styling-hooks.js";var r={name:"ResetPasswordPage",purpose:"A password-change block composing Heading, Alert, Form, Field, PasswordInput and Button. It takes a new password, optionally matches it against a confirmation, reports it through a reset-password event, and swaps the whole form for a success alert once the change is accepted. Ships in the blocks package of each framework, not the core package.",props:[{name:"title",type:"string",defaultValue:"'Choose a new password'",required:!1,description:"Heading text, rendered into a derived <h1> that names the section."},{name:"error",type:"string",required:!1,description:"Message rendered into a derived error Alert above the form. The block never clears it: set it from the reset handler and reset it when the next attempt starts."},{name:"success",type:"string",required:!1,description:"Confirmation rendered into a derived success Alert that replaces the form entirely, since the password can only be changed once per link."},{name:"pending",type:"boolean",defaultValue:"false",required:!1,description:"Marks the request in flight, making the submit button busy and unusable while both fields stay editable, so the user can still correct a typo."},{name:"passwordLabel",type:"string",defaultValue:"'New password'",required:!1,description:"Label of the field where the new password is typed."},{name:"confirmPasswordLabel",type:"string",required:!1,description:"Label of the confirmation field; supplying it is what makes that field render and what turns on password matching."},{name:"requirements",type:"unknown",required:!1,frameworks:["react","svelte","angular"],exception:"render-prop",frameworksReason:"Vue and Web Components take this as a named slot rather than a prop \u2014 Vue because a renderable region is a slot in Vue's own idiom, Web Components because a custom element attribute carries a string and cannot carry a node. Both slot spellings are declared under `slots`.",description:"Password rules rendered as the new-password field's description, so they are announced with the field. No requirements region renders when omitted. A prop in React, Svelte, and Angular; Vue and Web Components use the `requirements` slot."},{name:"passwordMismatchMessage",type:"string",defaultValue:"'Passwords do not match'",required:!1,description:"Validation message pushed onto the confirmation field as a custom validity when the two passwords differ."},{name:"submitLabel",type:"string",defaultValue:"'Update password'",required:!1,description:"Text of the form submit button."},{name:"footer",type:"unknown",required:!1,frameworks:["react","svelte","angular"],exception:"render-prop",frameworksReason:"Vue and Web Components take this as a named slot rather than a prop \u2014 Vue because a renderable region is a slot in Vue's own idiom, Web Components because a custom element attribute carries a string and cannot carry a node. Both slot spellings are declared under `slots`.",description:"Navigation rendered below the form, such as a link back to the sign-in page. No footer region renders when omitted. A prop in React, Svelte, and Angular; Vue and Web Components use the `footer` slot."}],events:[{name:"reset-password",detail:"{ password: string }",description:"Fires when the form is submitted with a valid password that matches the confirmation, carrying the new password. The native submit is prevented, so the consumer performs the change and then sets success or error."}],slots:[{name:"default",description:"Extra fields rendered inside the form, above the submit button."},{name:"requirements",description:"Password rules used as the new-password field's description; nothing renders without them."},{name:"footer",description:"Navigation below the form, such as a link back to the sign-in page."}],states:["default"],controlledUncontrolled:"Stateless apart from the values the native inputs hold; error, success and pending are always controlled by the consumer.",formBehavior:"The form is a core Form root with required, natively validated password fields; an invalid form reports through constraint validation and emits nothing. No form renders at all while success is set.",validationBehavior:"Both fields are required and validated natively. When a confirmation field renders, a mismatch is pushed onto it as a custom validity, reported through the form, and cleared on the next edit of that field.",accessibility:{role:"region (native <section> named by its heading through aria-labelledby)",keyboard:[{key:"Enter",behavior:"Submits the form whose field has focus (native form submission)."},{key:"Enter/Space",behavior:"Activates a focused reveal button, unmasking that field's characters."}],ariaAttributes:["aria-labelledby on the <section> points at the derived heading","the derived error and success Alerts are live regions, so each is announced without moving focus","the requirements are joined to the password field's aria-describedby by the core Field"],focusManagement:"Focus stays where the user put it, except that a reported password mismatch moves focus to the confirmation field the way constraint validation does."},styling:{cssParts:["reset-password-page","panel","title","error","success","form","field","requirements","submit","footer"],dataAttributes:[...e,{name:"data-skdx-reset-password-page-generated",frameworks:["webComponents"],exception:"wc-marker",frameworksReason:'Marks a node the element generated for itself rather than one the consumer authored. React, Vue, Svelte and Angular re-render their derived anatomy declaratively, so "mine or theirs" is answered by the framework and no marker is needed.'},{name:"data-skdx-reset-password-page-content",frameworks:["webComponents"],exception:"wc-marker",frameworksReason:'Marks a node the element generated for itself rather than one the consumer authored. React, Vue, Svelte and Angular re-render their derived anatomy declaratively, so "mine or theirs" is answered by the framework and no marker is needed.'}],cssCustomProperties:[]},publicMethods:[]};export{r as resetPasswordPageContract};
@@ -0,0 +1,7 @@
1
+ import type { ComponentContract } from './types.js';
2
+ /**
3
+ * The Resizable contract. Every framework package's Resizable implements
4
+ * exactly this: a flexbox-based split-pane group where dragging a handle
5
+ * redistributes size only between the two panels immediately adjacent to it.
6
+ */
7
+ export declare const resizableContract: ComponentContract;
@@ -0,0 +1 @@
1
+ import{ROOT_DATA_ATTRIBUTES as e}from"./styling-hooks.js";var t={name:"Resizable",purpose:"A split-panel layout with draggable, keyboard-operable handles. Panels and handles form an alternating set that may change after mount: every Handle resolves its own index from its position in the DOM at the moment of interaction. A drag redistributes size ONLY between the two panels immediately adjacent to the handle \u2014 the predictable default. Composed of root, Panel, and Handle parts.",props:[{name:"step",type:"number",defaultValue:"2",required:!1,description:"Percentage points per Arrow key press. Group-level so a multi-panel group does not repeat the value silently. Overridable per Handle. The unit is percentage points, not pixels."},{name:"orientation",type:"'horizontal' | 'vertical'",defaultValue:"'horizontal'",required:!1,description:"Layout axis: flex direction, arrow-key pair, cursor, aria-orientation. Exposed as data-orientation. Optional."},{name:"sizes",type:"number[]",required:!1,description:"Controlled panel sizes (percentages, Panel order). Supplied: group renders and reports through `layout`/`layout-commit`. Omitted: uses each Panel's defaultSize."},{name:"panels",type:"ReadonlyArray<{ defaultSize?: number; minSize?: number; maxSize?: number; collapsible?: boolean; collapsedSize?: number; id?: string; content?: unknown }>",required:!1,description:"The panes the group derives \u2014 one Panel per entry. Composition is optional."},{name:"panelTemplate",frameworks:["angular"],exception:"render-prop",frameworksReason:"Angular's `panels[].content` can only be a string, because a component input cannot carry template markup. The other four put markup straight into that entry \u2014 a ReactNode, a VNode, a snippet, or a Node \u2014 so they need no second input; Angular reaches the same capability with an *ngTemplateOutlet fed by this TemplateRef.",type:"TemplateRef<{ $implicit: PanelItem; panel: PanelItem; index: number }>",required:!1,description:"Template rendered as each derived panel's body, replacing that entry's content string."},{name:"size",type:"'sm' | 'lg' | (string & {})",required:!1,description:"Handle target-size rung, written to data-size on the root; the data-size attribute may be set directly instead."}],events:[{name:"layout",description:"Fires with sizes array (percentages) on every pointermove that moves the split.",detail:"number[]"},{name:"layout-commit",description:"Fires with sizes array (percentages) when the user finishes: on pointerup/pointercancel or after keyboard nudge. The event to persist on.",detail:"number[]"},{name:"collapse",description:"Fires when a collapsible Panel reaches collapsedSize, carrying the panel id.",detail:"{ panelId: string }"},{name:"expand",description:"Fires when a collapsed Panel reopens, carrying the panel id. Reachable by pointer and arrow key.",detail:"{ panelId: string }"}],parts:[{name:"Panel",description:"One resizable pane. Registers size constraints on mount and is sized thereafter. No per-Panel `size` prop. Lays out through flexbox before the group computes a size.",props:[{name:"defaultSize",type:"number | undefined",required:!1,description:"Initial size as a percentage of the group's main axis (0-100). Omit to split remaining space evenly. Percentages are the only unit accepted."},{name:"minSize",type:"number",defaultValue:"10",required:!1,description:"Minimum size as a percentage (0-100). Default 10 prevents accidental loss."},{name:"maxSize",type:"number",defaultValue:"90",required:!1,description:"Maximum size as a percentage (0-100). Default 90 pairs with minSize 10."},{name:"collapsible",type:"boolean",defaultValue:"false",required:!1,description:"Lets this panel close: below minSize snaps to collapsedSize. Off by default. Reopens on any movement."},{name:"collapsedSize",type:"number",defaultValue:"0",required:!1,description:"Size (percentage) while closed. Panel carries data-collapsed; group fires collapse/expand."}]},{name:"Handle",description:'The draggable divider (role="separator"), its own tab stop. Carries data-dragging during pointer gestures.',props:[{name:"disabled",type:"boolean",defaultValue:"false",required:!1,description:'Refuses every drag and every key. Focusable-and-inert: the handle keeps its tab stop and announces aria-disabled="true".'},{name:"step",type:"number | undefined",defaultValue:"undefined \u2014 inherits the group's step (2)",required:!1,description:"Nudge per Arrow key press, overriding the group's step. Percentage points, not pixels."}]}],slots:[{name:"default",description:"Root content \u2014 alternating Panel, Handle, Panel, ... entries."}],appearance:[{attribute:"data-size",values:["sm","lg"],stylesheet:"resizable.css"}],states:["disabled","dragging","collapsed"],controlledUncontrolled:"Standard. Uncontrolled: sizes seeded from each Panel's defaultSize. Controlled: supply `sizes` for a pure renderer. No `defaultSizes` on root.",formBehavior:"Not applicable \u2014 Resizable does not participate in forms.",validationBehavior:"Not applicable \u2014 Resizable carries no value and participates in no validation.",accessibility:{role:"(none, root); separator (Handle)",keyboard:[{key:"ArrowLeft/ArrowRight (horizontal groups) or ArrowUp/ArrowDown (vertical groups)",behavior:"Nudges the focused Handle by step (default 2 percentage points)."},{key:"Home",behavior:"Shrinks the Handle's left/top panel to its minSize."},{key:"End",behavior:"Grows the Handle's left/top panel to its maxSize."}],ariaAttributes:["Handle's aria-orientation is perpendicular to the group's direction","Handle's aria-valuenow/aria-valuemin/aria-valuemax describe the adjacent panel size; a collapsible panel reports collapsedSize as its aria-valuemin, since that is the smallest size it can legally reach","Handle's aria-valuetext expresses size as a percentage","Handle's aria-controls is the DOM id of the start-side panel","data-dragging on Handle during pointer gesture",'data-disabled on disabled Handle with aria-disabled="true"',"aria-label or aria-labelledby on Handle, forwarded to separator element"],namingRequirement:"Groups with multiple Handles MUST name each distinctly with aria-label/aria-labelledby. Single Handles need no name.",focusManagement:"Each Handle is its own tab stop (tabIndex 0), including while disabled. Disabled Handles are focusable-and-inert."},styling:{cssParts:["panel","handle","root"],dataAttributes:[...e,"data-orientation","data-disabled","data-dragging","data-collapsed","data-size","data-skdx-resizable-handle","data-skdx-resizable-panel",{name:"data-skdx-resizable-generated",frameworks:["webComponents"],exception:"wc-marker",frameworksReason:'Marks a node the element generated for itself rather than one the consumer authored. React, Vue, Svelte and Angular re-render their derived anatomy declaratively, so "mine or theirs" is answered by the framework and no marker is needed.'}],cssCustomProperties:["--skdx-resizable-handle-size"]},publicMethods:[{name:"getSizes",frameworks:["vue","svelte","angular","webComponents"],exception:"imperative",frameworksReason:"React uses `useResizableContext`; see contextApi below.",signature:"() => number[]",description:"Current sizes as percentages, in Panel order."},{name:"setSizes",frameworks:["vue","svelte","angular","webComponents"],exception:"imperative",frameworksReason:"React uses `useResizableContext`; see contextApi below.",signature:"(sizes: number[]) => void",description:"Drive layout to sizes (percentages, Panel order). Clamped and renormalized to 100."},{name:"resetSizes",frameworks:["vue","svelte","angular","webComponents"],exception:"imperative",frameworksReason:"React uses `useResizableContext`; see contextApi below.",signature:"() => void",description:"Return every panel to its defaultSize or even split: fresh mount layout."}],contextApi:[{name:"getSizes",signature:"() => number[]",description:"Current sizes as percentages, in Panel order.",accessors:{react:"useResizableContext('MyComponent').getSizes",vue:"inject(RESIZABLE_CONTEXT).getSizes",svelte:"requireContext(RESIZABLE_CONTEXT).getSizes",angular:"inject(SkdxResizableState).getSizes",webComponents:"document.querySelector('skdx-resizable-panel-group').getSizes"}},{name:"setSizes",signature:"(sizes: number[]) => void",description:"Drive layout to sizes, clamped and renormalized to 100.",accessors:{react:"useResizableContext('MyComponent').setSizes",vue:"inject(RESIZABLE_CONTEXT).setSizes",svelte:"requireContext(RESIZABLE_CONTEXT).setSizes",angular:"inject(SkdxResizableState).setSizes",webComponents:"document.querySelector('skdx-resizable-panel-group').setSizes"}},{name:"resetSizes",signature:"() => void",description:"Reset every panel to defaultSize or even split.",accessors:{react:"useResizableContext('MyComponent').resetSizes",vue:"inject(RESIZABLE_CONTEXT).resetSizes",svelte:"requireContext(RESIZABLE_CONTEXT).resetSizes",angular:"inject(SkdxResizableState).resetSizes",webComponents:"document.querySelector('skdx-resizable-panel-group').resetSizes"}}]};export{t as resizableContract};
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Cross-contract rule sentences: one decision that several components state,
3
+ * written once and spread into each contract's prose. A contract test asserts
4
+ * the constant is present rather than matching a regex over the sentence, so
5
+ * rewording the rule updates every contract and every test at once.
6
+ */
7
+ /**
8
+ * How a popup-owning control places focus while its list is open. Spread into
9
+ * the `focusManagement` of every control whose list is navigated virtually.
10
+ */
11
+ export declare const VIRTUAL_FOCUS_RULE = "DOM focus stays on the element the popup is anchored to and never moves into the list: the highlighted option is virtual, named by aria-activedescendant on that element and mirrored as data-highlighted on the option, and no implementation may re-focus the anchor on its own.";
@@ -0,0 +1 @@
1
+ var e="DOM focus stays on the element the popup is anchored to and never moves into the list: the highlighted option is virtual, named by aria-activedescendant on that element and mirrored as data-highlighted on the option, and no implementation may re-focus the anchor on its own.";export{e as VIRTUAL_FOCUS_RULE};
@@ -0,0 +1,6 @@
1
+ import type { ComponentContract } from './types.js';
2
+ /**
3
+ * Natively-scrollable viewport paired with a synced custom
4
+ * scrollbar thumb for consistent cross-platform styling.
5
+ */
6
+ export declare const scrollAreaContract: ComponentContract;
@@ -0,0 +1 @@
1
+ import{ROOT_DATA_ATTRIBUTES as e}from"./styling-hooks.js";var a={name:"ScrollArea",purpose:"Wraps a natively-scrollable viewport and exposes a custom scrollbar thumb kept in sync with it, so brands can style scrollbars consistently across platforms. Composed of a root plus Viewport, Scrollbar, Thumb, and Corner parts.",props:[{name:"type",type:"'auto' | 'always' | 'hover' | 'scroll'",defaultValue:"'hover'",required:!1,description:'When scrollbar is visible: "hover" on pointer over, "scroll" on scroll, "always"/"auto" always. "auto" mounts track only while axis overflows; "always" always mounts it.'},{name:"scrollHideDelay",type:"number",defaultValue:"600",required:!1,description:'Milliseconds scrollbar stays visible after scroll stops (type="scroll" only).'},{name:"scrollbars",type:"'vertical' | 'horizontal' | 'both'",defaultValue:"'both'",required:!1,description:"Which scrollbars to derive."},{name:"size",type:"'sm' | 'lg' | (string & {})",required:!1,description:"Track/thumb size rung, written to data-size on the root; the data-size attribute may be set directly instead."}],events:[{name:"scroll-position-change",description:"Fires with viewport scroll offsets on every scroll tick.",detail:"{ x: number, y: number }"}],parts:[{name:"Scrollbar",description:'Track for one axis with aria-hidden="true"; rendered only while that axis overflows. Its data-state is gated on overflow before anything else: an axis with nothing to scroll stays data-state="hidden" whatever hover, scrolling or type would otherwise say, so a skin never paints a track over content that already fits.',props:[{name:"orientation",type:"'horizontal' | 'vertical'",defaultValue:"'vertical'",required:!1,description:"Track axis; selects which overflow state drives render."},{name:"forceMount",type:"boolean",defaultValue:"false",required:!1,description:"Keep track in flow even when axis does not overflow."}]},{name:"Corner",description:"Square filling the gap where vertical and horizontal scrollbars meet.",props:[{name:"forceMount",type:"boolean",defaultValue:"false",required:!1,description:"Keep corner mounted even when both axes do not overflow."}]}],slots:[{name:"default",description:"Root content \u2014 Viewport, Scrollbar(s), and Corner."}],appearance:[{attribute:"data-size",values:["sm","lg"],stylesheet:"scroll-area.css"}],states:["visible","hidden"],controlledUncontrolled:"Not applicable \u2014 ScrollArea has no value; scroll position is native browser state.",formBehavior:"Not applicable \u2014 ScrollArea does not participate in forms.",validationBehavior:"Not applicable \u2014 ScrollArea carries no value and participates in no validation.",accessibility:{role:"region on Viewport when named; none otherwise",namingRequirement:'Name Viewport with aria-label or aria-labelledby to emit role="region".',keyboard:[{key:"(native)",behavior:"Native scroll keys (Arrow, Page Up/Down, Home/End, Space) on Viewport."}],ariaAttributes:['Viewport carries role="region" plus aria-label or aria-labelledby when named','aria-hidden="true" on Scrollbar, Thumb and Corner'],focusManagement:"Focus stays on Viewport; Scrollbar/Thumb are pointer-only visual affordances."},styling:{cssParts:["viewport","scrollbar","thumb","corner","root"],dataAttributes:[...e,"data-state","data-orientation","data-overflow-x","data-overflow-y","data-size","data-skdx-scroll-area","data-skdx-scroll-area-content","data-skdx-scroll-area-corner","data-skdx-scroll-area-scrollbar","data-skdx-scroll-area-thumb","data-skdx-scroll-area-viewport",{name:"data-skdx-scroll-area-generated",frameworks:["webComponents"],exception:"wc-marker",frameworksReason:'Marks a node the element generated for itself rather than one the consumer authored. React, Vue, Svelte and Angular re-render their derived anatomy declaratively, so "mine or theirs" is answered by the framework and no marker is needed.'}],cssCustomProperties:["--skdx-scroll-area-track-size","--skdx-scroll-area-thumb-min-length"]},publicMethods:[{name:"scrollTo",frameworks:["vue","svelte","angular","webComponents"],exception:"imperative",frameworksReason:"React's root forwards a DOM ref rather than an imperative handle, so there is no component instance to hang a method off \u2014 `useScrollAreaContext` is React's binding of this member and it is declared under `contextApi` below. Listing it here unscoped would read as React missing a method the family has.",signature:"(options: { top?: number, left?: number, behavior?: 'auto' | 'smooth' }) => void",description:"Scroll Viewport; omitted axes stay where they are."}],contextApi:[{name:"scrollTo",signature:"(options: { top?: number, left?: number, behavior?: 'auto' | 'smooth' }) => void",description:"Scrolls the Viewport to the given position.",accessors:{react:"useScrollAreaContext('MyComponent').scrollTo",vue:"inject(SCROLL_AREA_CONTEXT).scrollTo",svelte:"getContext(SCROLL_AREA_CONTEXT).scrollTo",angular:"inject(SkdxScrollAreaState).scrollTo",webComponents:"document.querySelector('skdx-scroll-area').scrollTo"}}]};export{a as scrollAreaContract};
@@ -0,0 +1,5 @@
1
+ import { type ComponentContract } from './types.js';
2
+ /**
3
+ * A button trigger that displays the current value and opens a positioned popup listbox of options.
4
+ */
5
+ export declare const selectContract: ComponentContract;
@@ -0,0 +1 @@
1
+ import{changeDetail as t}from"./change-reason.js";import{constraintValidationMethods as r,setCustomValidityMethod as s}from"./form-validity.js";import{closeAutoFocusEvent as l,dismissalEvents as d,forceMountProp as e,openChangeCompleteEvent as h,popperContentProps as p,popperMeasurementProperties as c,portalPart as a,portalPropsSansForceMount as u}from"./overlay-parts.js";import{VIRTUAL_FOCUS_RULE as m}from"./rules.js";import{SELECTION_ATTRIBUTE_RULE as n,SELECTION_INPUT_RULE as i,SELECTION_OUTPUT_RULE as o}from"./selection-value.js";import{PART_DATA_ATTRIBUTES as g}from"./styling-hooks.js";import{withoutScope as b}from"./types.js";var C={name:"Select",purpose:"A button trigger that displays the current value and opens a positioned popup listbox of options. Derives trigger and listbox from option data when provided. With `multiple` it accumulates values and renders a TagList of removable Tags; with `filterable` it swaps the trigger for a filter Input that narrows the options as the user types.",props:[{name:"options",type:"Array<{ value: string; label?: string; disabled?: boolean } | { label: string; options: Array<{ value: string; label?: string; disabled?: boolean }> }>",required:!1,description:"Flat or grouped option data to render automatically \u2014 trigger, tag list, filter input, Clear button, portal, listbox, and Items \u2014 instead of hand composing them. Seeds items for typeahead and labels on first paint. Property-only on <skdx-select>: HTML attributes cannot carry arrays."},{name:"renderOption",type:"(option: { value: string; label?: string; disabled?: boolean }, state: { selected: boolean }) => React.ReactNode",required:!1,frameworks:["react","svelte","angular"],exception:"render-prop",frameworksReason:'Web Components uses a named slot (`slot="option"`, keyed by `data-value`), Vue uses a scoped slot (`#option`), and Angular uses a TemplateRef input. HTML attributes cannot carry functions.',description:"Customises how a derived option renders inside its Item. Receives the option and whether it is currently selected. Only read while options is deriving the anatomy."},{name:"renderValue",type:"(selected: { value: string; label?: string; disabled?: boolean } | Array<{ value: string; label?: string; disabled?: boolean }> | null) => React.ReactNode",required:!1,frameworks:["react","svelte","angular"],exception:"render-prop",frameworksReason:'Web Components uses a named slot (`slot="value"`), Vue uses a scoped slot (`#value`), and Angular uses a TemplateRef input always receiving an array. HTML attributes cannot carry functions.',description:"Customizes the trigger's displayed content in place of the default label (or chips in multiple mode). Receives selected option(s) or null."},{name:"renderTag",type:"(option: { value: string; label?: string; disabled?: boolean }) => React.ReactNode",required:!1,frameworks:["react","svelte","angular"],exception:"render-prop",frameworksReason:'Web Components uses a named slot (`slot="tag"`, keyed by `data-value`), Vue uses a scoped slot (`#tag`), and Angular uses a TemplateRef input. HTML attributes cannot carry functions.',description:"Customises a selected value's content inside its derived Tag. Only read while `multiple` and options is deriving the anatomy."},{name:"placeholder",type:"string",required:!1,description:"Placeholder shown by the derived trigger while nothing is selected, or by the derived filter Input while `filterable`. Only read while options is deriving the anatomy \u2014 pass it to SelectValue directly under manual composition."},{name:"aria-label",type:"string",required:!1,frameworks:["react","vue","svelte","angular"],exception:"attribute-passthrough",frameworksReason:"Web Components claims the host `aria-label` attribute and relocates it to the derived control; the other four declare it as a prop.",description:"Accessible name for the derived Trigger or filter Input, and for the tag list beside it. Only read while options is deriving the anatomy."},{name:"value",type:"string | string[]",required:!1,description:`Selected option value(s), for controlled usage. Pair with a value-change event/emit/callback. ${i} ${o} ${n}`},{name:"defaultValue",type:"string | string[]",required:!1,description:`Initially selected value(s), for uncontrolled usage. Same shape as \`value\`. ${i} ${n}`},{name:"multiple",type:"boolean",defaultValue:"false",required:!1,description:'Allows more than one option selected. Sets `aria-multiselectable="true"` on Content, toggles options instead of replacing, keeps the listbox open to pick several at once, and lets the derived anatomy render a TagList of removable Tags beside the field.'},{name:"deselectable",type:"boolean",defaultValue:"false",required:!1,description:'Whether picking the already-selected option in single-select mode clears it. Ignored in multiple mode (always toggles). Cleared selection is `[]` with `selectedValue: null` \u2014 the same empty shape an untouched Select reports \u2014 so no third state is needed for "emptied single-select".'},{name:"maxSelected",type:"number",required:!1,description:"Largest number of values selectable while `multiple`. Once reached, unselected options go aria-disabled rather than silently swallowing clicks; already-selected ones stay removable. Inert in single-select mode, where one value is the cap."},{name:"allowSelectAll",type:"boolean",defaultValue:"true",required:!1,description:"Whether Control+A (Command+A) selects every enabled option while `multiple` and the listbox is open, and whether the derived anatomy offers a SelectAll row. With the listbox closed, Control+A keeps its native meaning of selecting draft text and is never intercepted. Stops where `maxSelected` runs out, and clears the selection if every option is already selected."},{name:"items",type:"Array<{ value: string; label?: string; disabled?: boolean }>",required:!1,description:"Option collection declared up front. Enables closed-trigger typeahead and labels on first paint before Content mounts. Purely a data declaration; rendered Items remain the source of truth."},{name:"filterable",type:"boolean",defaultValue:"false",required:!1,description:"Whether the derived anatomy renders a filter Input that narrows the options as the user types. The Input holds DOM focus in place of the Trigger, so `inputValue`, `defaultInputValue`, `filter` and the input-value-change event only mean anything while this is set."},{name:"inputValue",type:"string",required:!1,description:"Controlled draft text in the filter Input. Pair with the input-value-change event. The string the option list is narrowed by; filtering is the consumer's job unless a `filter` predicate is supplied. Read only while `filterable`."},{name:"defaultInputValue",type:"string",defaultValue:"''",required:!1,description:"Initial draft text in the filter Input, for uncontrolled usage."},{name:"filter",type:"(itemText: string, inputValue: string) => boolean | number",required:!1,description:"Predicate deciding which options survive the current draft text. Returns a boolean to filter, or a number to filter and rank (0 excludes, positive keeps). Surviving options are ordered by score descending. Read only while `filterable`."},{name:"loading",type:"boolean",defaultValue:"false",required:!1,description:'Whether the option list is in flight. Publishes aria-busy="true" and data-loading on Content and on the filter Input, and suppresses the selection-count announcement until options arrive. Does not block interaction.'},{name:"clearable",type:"boolean",defaultValue:"false",required:!1,description:"Whether the derived anatomy renders a Clear button that empties the selection and any draft text in one action. Only read while options is deriving the anatomy."},{name:"closeOnSelect",type:"boolean | undefined",defaultValue:"!multiple",required:!1,description:"Whether picking an option closes the listbox. Defaults to `!multiple` \u2014 single-select closes, and a multiple selection stays open, because picking five things should cost five clicks rather than five clicks and five reopenings. Can be set explicitly to override the default."},{name:"open",type:"boolean",required:!1,description:"Whether the listbox is open, for controlled usage."},{name:"defaultOpen",type:"boolean",defaultValue:"false",required:!1,description:"Initial open state, for uncontrolled usage."},{name:"disabled",type:"boolean",defaultValue:"false",required:!1,description:"Disables the trigger and prevents opening the listbox; tags cannot be removed and the filter Input is disabled. Distinct from `readOnly`, which keeps the trigger focusable and keeps the value in the form."},{name:"readOnly",type:"boolean",defaultValue:"false",required:!1,description:'Displays an unchangeable value. Trigger keeps its tab stop and focus, carries aria-readonly="true" and data-readonly, and submits the value; tags stay visible but cannot be removed. Listbox does not open; typeahead commits nothing. Unlike `disabled`, does not drop out of tab order or stop announcing.'},{name:"required",type:"boolean",defaultValue:"false",required:!1,description:"Marks the hidden native form-participation input as required. Only meaningful with `name`."},{name:"invalid",type:"boolean",defaultValue:"false",required:!1,description:"Marks the select as invalid, exposed as aria-invalid/data-invalid on the trigger."},{name:"name",type:"string",required:!1,description:"When set, a visually-hidden native form control is kept in sync with `value` so the select participates in native form submission/validation. A `multiple` selection produces one control per value, and so repeated name=value entries."},{name:"form",type:"string | undefined",required:!1,description:"Id of the `<form>` the select submits into, forwarded to every mirrored hidden control, so a select can live outside the form it belongs to \u2014 a filter bar above a table, a control in a portal, a field in a sticky footer. Exactly the native `form` content attribute, and it needs `name` to mean anything, since with no `name` there is no control to associate. The Web Components port gets it for free: `<skdx-select>` is a form-associated custom element, so the platform honours the `form` attribute on the host without the component doing anything \u2014 the property is still declared there so the manifest lists one prop rather than four. It is spelled `formId` in Web Components, never `form`: a form-associated custom element already publishes `form` as a readonly `HTMLFormElement`, and shadowing that reserved property with a writable string would break `select.form`. The markup attribute stays `form` in all five packages."},{name:"autoComplete",type:"string | undefined",required:!1,description:"Browser autofill hint, forwarded to the first mirrored hidden control \u2014 the same one that answers for the whole set's validity. One control rather than all of them, because an autofill token names a single field of an address or a payment method and repeating it across the entries of a `multiple` selection would offer the browser several places to write one value. Any value the HTML autocomplete attribute takes, including `off`."},{name:"getSelectionLabel",type:"(count: number) => string",required:!1,description:'Formats the message announced after each selection change while `multiple`. Without this, screen-reader users get no confirmation that anything happened, since the option that changed is neither focused nor always visible. Return empty string to announce nothing. Defaults to "2 selected". Counts selected options, not rendered ones.'},{name:"shape",type:"'rounded' | 'square' | 'pill' | (string & {})",required:!1,description:"Corner rounding rung forwarded to the Trigger's data-shape, and to every derived Tag's; the attribute may be written on either directly instead."},{name:"size",type:"'sm' | 'lg' | (string & {})",required:!1,description:"Size rung forwarded to the Trigger's data-size, and to every derived Tag's; the attribute may be written on either directly instead."},{name:"status",type:"'info' | 'success' | 'warning' | 'danger' | (string & {})",required:!1,description:"Severity rung forwarded to every derived Tag's data-status; the attribute may be written on a Tag directly instead."},{name:"density",type:"'comfortable' | 'compact' | (string & {})",required:!1,description:"Vertical rhythm rung forwarded to the TagList's data-density; the attribute may be written on TagList directly instead."},{name:"matchWidth",type:"boolean",required:!1,description:"Match-width switch forwarded to the Content panel's data-match-width; the attribute may be written on Content directly instead."}],events:[{name:"value-change",description:`Fires whenever the selected option changes, controlled or not \u2014 carrying the whole selection, not the single option that was toggled, so the array can be written straight back to state. ${o}`,detail:t("string[]","selectedValue: string | null")},{name:"value-change-detail",frameworks:["angular"],exception:"event-shape",frameworksReason:"Angular's `valueChange` emits the whole `string[]` selection so `[(value)]` round-trips it; this second output carries the detail object the other four hand to `value-change`.",description:"Fires with valueChange, carrying the whole selection plus the option that changed.",detail:t("string[]","selectedValue: string | null")},{name:"input-value-change",description:"Fires with the new draft text on every keystroke in the filter Input, and with the empty string when a selection or the Clear button empties it.",detail:"string"},{name:"open-change",detail:"boolean",description:"Fires with the new open state whenever the listbox opens or closes, controlled or not."},h("listbox"),...d("listbox"),l("listbox")],parts:[{name:"Trigger",lightDom:!0,description:"The button that opens the listbox and displays the current value. Replaced by the Input part while `filterable`.",props:[{name:"disabled",type:"boolean",defaultValue:"false",required:!1,frameworks:["react","webComponents"],exception:"root-prop",frameworksReason:"Vue, Svelte and Angular read the root's `disabled` off context and expose no per-trigger override; disabling the Select root disables its trigger there, which is the same switch one level up.",description:"Disables this trigger on its own; a disabled root disables every trigger regardless of this value."},{name:"shape",type:"'rounded' | 'square' | 'pill' | (string & {})",required:!1,description:"Corner rounding rung, written to data-shape on the trigger; the data-shape attribute may be set directly instead."},{name:"size",type:"'sm' | 'lg' | (string & {})",required:!1,description:"Visual size rung, written to data-size on the trigger; the data-size attribute may be set directly instead."}]},{name:"Value",description:"Renders the selected option's label, or placeholder when nothing is selected. In multiple mode, renders one chip per selection (not interactive, as Trigger is a button). Deselecting happens in the listbox, or on the removable Tags of a TagList.",props:[{name:"placeholder",type:"string",required:!1,description:"Content shown while no option is selected."}]},{name:"Icon",description:"Decorative open/close indicator inside Trigger."},{name:"TagList",description:"The tag strip rendering one Tag per selected value while `multiple`, in selection order. Built on TagGroup, which is where removal gets its focus behaviour; `disabled` comes from the root.",props:[{name:"orientation",type:"'horizontal' | 'vertical'",defaultValue:"'horizontal'",required:!1,description:"Layout axis of the tag strip, published as data-orientation and deciding arrow-key direction: Left/Right when horizontal, Up/Down when vertical."},{name:"loop",type:"boolean",defaultValue:"true",required:!1,description:"Whether arrow-key navigation wraps between the first and last tag."},{name:"density",type:"'comfortable' | 'compact' | (string & {})",required:!1,description:"Vertical rhythm rung, written to data-density on the tag list; the data-density attribute may be set directly instead."},{name:"tags",type:"ReadonlyArray<{ value: string; label: string; disabled?: boolean }>",required:!1,frameworks:["webComponents"],exception:"wc-internals",frameworksReason:"`<skdx-select-tag-list>` subclasses `<skdx-tag-group>`, so the base element's entry data reaches it too. The other four compose TagGroup and render one Tag per selected value themselves, which is what this strip is for.",description:"Entry data the tag group would derive Badges from, inherited from the base element and left unset here."},{name:"removable",type:"boolean",defaultValue:"false",required:!1,frameworks:["webComponents"],exception:"wc-internals",frameworksReason:"`<skdx-select-tag-list>` subclasses `<skdx-tag-group>`, so the base element's switch reaches it too. The other four compose TagGroup and give every Tag its own TagRemove instead.",description:"Whether a tag derived from the inherited entry data carries its own remove button."}],events:[{name:"remove",frameworks:["webComponents"],exception:"wc-internals",frameworksReason:"`<skdx-select-tag-list>` subclasses `<skdx-tag-group>` and inherits its removal event; React, Vue, Svelte and Angular compose TagGroup instead, so a removed tag reaches the consumer through the root value-change alone.",description:"Fires when a tag is removed without veto, carrying the removed tag's text and position.",detail:"{ label: string; index: number }"}]},{name:"Tag",description:"One selected value inside TagList, showing the option's text or the raw value if none was declared. Carries `data-skdx-select-tag` so a tag can be told from the chips Value renders inside the button trigger.",props:[{name:"value",type:"string",required:!0,description:"The selected value this tag represents. Required: it deselects when remove is clicked and decides the tag's place in roving tab order."},{name:"disabled",type:"boolean",defaultValue:"false",required:!1,description:"Locks this tag: the remove button refuses, it is painted with data-disabled, and roving focus steps over it. Per-tag rather than per-root, for pinned values like mandatory scopes. ORs with the root's locked state."},{name:"shape",type:"'rounded' | 'square' | 'pill' | (string & {})",required:!1,description:"Corner rounding rung, written to data-shape on the tag; the data-shape attribute may be set directly instead."},{name:"size",type:"'sm' | 'md' | 'lg' | (string & {})",required:!1,description:"Visual size rung, written to data-size on the tag; the data-size attribute may be set directly instead."},{name:"status",type:"'info' | 'success' | 'warning' | 'danger' | (string & {})",required:!1,description:"Severity rung, written to data-status on the tag; the data-status attribute may be set directly instead."}]},{name:"TagRemove",description:'The remove button inside a Tag, deselecting that value. Named automatically ("Remove Ruby"). Override with `aria-label` or the `label` prop.',props:[{name:"label",type:"string",required:!1,frameworks:["webComponents"],exception:"attribute-passthrough",frameworksReason:"React, Vue, Svelte and Angular take `aria-label` on the element through attribute passthrough.",description:"Accessible name for the remove button, replacing the generated `Remove <value>`."}]},{name:"Input",lightDom:!0,description:'The filter text field rendered while `filterable`, holding DOM focus in the Trigger\'s place. Carries role="combobox", aria-expanded, aria-controls, aria-autocomplete, and aria-activedescendant naming the highlighted option.'},{name:"Clear",description:'Button emptying the selection and any draft text in one press, then returning focus to the Input, or the Trigger where there is none. Rendered beside the field rather than inside TagList, with its own tab stop, and named automatically ("Clear selection"). Disabled while the root is disabled or readOnly, or the selection is empty and the draft blank.'},{...a,description:`${a.description} React and Web Components only. Vue, Svelte, and Angular position Content with @floating-ui/dom's strategy: 'fixed' and do not teleport. In Web Components, parts hide with hidden rather than unmounting.`,frameworks:["react","webComponents"],exception:"portal",frameworksReason:"Vue, Svelte, and Angular position Content with strategy: 'fixed' and do not need SelectPortal. Scoped to the part so both members inherit it.",props:[...u,{...e,frameworks:["react"],exception:"force-mount",frameworksReason:"The part's own scope already excludes Vue, Svelte and Angular; this narrows the prop one framework further. <skdx-select-portal> declares no force-mount and says so in its own doc comment \u2014 its parts never unmount, they hide via `hidden`, so there is nothing to force and nothing to keep alive for an exit animation. A prop's `frameworks` overrides its part's rather than intersecting, so this list names the one package that ships it."}]},{name:"Content",description:'The floating listbox (role="listbox", plus aria-multiselectable="true" in multiple mode). Opens below and start-aligned. Manages dismissal: Escape and outside interactions trigger cancelable dismissal events before closing.',props:[...p({align:"'start'",sideOffset:"4"}),{...e,frameworks:["react"],exception:"force-mount",frameworksReason:"Only React unmounts. Vue, Svelte, Angular, and Web Components toggle hidden on the element, so it persists for exit animations."},{name:"matchWidth",type:"boolean",required:!1,description:"Matches the listbox width to the trigger, written to data-match-width on Content; the data-match-width attribute may be set directly instead."}]},{name:"Viewport",description:"Scrollable container for Items inside Content."},{name:"SelectAll",description:"A row at the head of the listbox toggling every enabled option at once, offered while `multiple` and `allowSelectAll`. Its aria-selected reports whether the whole enabled set is currently selected, and it stops where `maxSelected` runs out."},{name:"Item",description:'One selectable option (role="option"). Goes aria-disabled while unselected and `maxSelected` is reached, so the cap is announced rather than felt as a dead click.',props:[{name:"value",type:"string",required:!0,description:"Identifier committed to the root's value when this option is chosen."},{name:"disabled",type:"boolean",defaultValue:"false",required:!1,description:'Excludes from selection and keyboard navigation. Carries aria-disabled="true" and data-disabled, so it remains accessible to screen readers.'},{name:"textValue",type:"string",required:!1,description:"Text for Trigger label, typeahead and the root filter, published as `data-text-value`; falls back to rendered text. Needed when the item contains more than text alone."}]},{name:"ItemText",description:"An Item's label content, captured so Value can render it inside Trigger."},{name:"ItemIndicator",description:"Selected-state glyph inside an Item, rendered only while that item is selected.",props:[b(e)]},{name:"Group",description:'Groups related Items under a Label (role="group"). Automatically wires aria-labelledby. Label is required inside Group.'},{name:"Label",description:"Non-interactive heading for Group, providing its accessible name. Outside a Group it renders but does not name anything."},{name:"Separator",description:'Visual divider between Items or Groups inside Content. Renders an aria-hidden element, not role="separator".'},{name:"Empty",description:'Message shown when the filter leaves no option to render. Rendered inside Portal as a sibling of Content with aria-live="polite", never inside the role="listbox" \u2014 an empty-state string announced as an option is worse than one not announced at all.'}],slots:[{name:"default",description:"Root content \u2014 the trigger, portal and content parts."},{name:"trigger",description:"SelectTrigger content: Value part (current selection) and Icon part (open/close indicator)."},{name:"content",description:"SelectContent: SelectOption, SelectGroup, SelectLabel, SelectSeparator."},{name:"option",frameworks:["vue","webComponents"],exception:"render-prop",frameworksReason:"React, Svelte and Angular reach the same customisation through the `renderOption` prop \u2014 a function, a snippet and a TemplateRef \u2014 because their content projection is not addressable by name from option data.",description:"Body of one derived option row, in place of the label its option data carries."},{name:"value",frameworks:["vue","webComponents"],exception:"render-prop",frameworksReason:"React, Svelte and Angular reach the same customisation through the `renderValue` prop, which receives the selected option(s) a slot would have to be handed some other way.",description:"Replacement body for the derived Value part, rendered instead of the resolved label."},{name:"tag",frameworks:["vue","webComponents"],exception:"render-prop",frameworksReason:"React, Svelte and Angular reach the same customisation through the `renderTag` prop, keyed by value rather than by a named slot the markup repeats per tag.",description:"Body of one derived Tag, in place of the resolved option label."},{name:"renderTag",frameworks:["svelte"],exception:"snippet-opaque",frameworksReason:"Svelte spells a render prop as a snippet, so `renderTag` is both the prop and the slot there; Vue and Web Components take the same content through the `tag` slot, and React and Angular through a prop that is not projection at all.",description:"Snippet form of the `tag` slot, passed as the `renderTag` prop."}],appearance:[{attribute:"data-match-width",values:[],stylesheet:"select.css"},{attribute:"data-shape",values:["rounded","square","pill"],stylesheet:"select.css"},{attribute:"data-size",values:["sm","lg"],stylesheet:"select.css"},{attribute:"data-status",values:["info","success","warning","danger"],stylesheet:"select.css"},{attribute:"data-density",values:["comfortable","compact"],stylesheet:"select.css"}],states:["closed","open","loading","disabled","readonly","invalid","required","multiple","highlighted","checked","unchecked"],controlledUncontrolled:"Three independent axes (value, inputValue, open) each start from their default and switch to controlled when the matching prop is passed, paired with a change event. In Angular the value pair is split: `valueChange` emits the whole `string[]` selection for `[(value)]`, `valueChangeDetail` carries the detail.",formBehavior:'With `name` set, a visually-hidden native control mirrors `value` for submission, reset and \u2014 with `required` \u2014 validation. It is never `type="hidden"` and never `readonly`; both bar an input from constraint validation, which would make `required` silently inert. A `multiple` select mirrors one hidden control per selected value under the same `name`, producing the repeated entries a native `<select multiple>` produces rather than one joined string, and an empty `multiple` selection submits nothing at all \u2014 except under `required`, where one empty-valued control still renders so `valueMissing` has somewhere to fire. A single select keeps one control at all times. Draft text in the filter Input never submits. Web Components publish value and validity through `ElementInternals` instead, because their mirrored input lives in the shadow root and is not associated with the ancestor form. A form reset restores `defaultValue` and `defaultInputValue` \u2014 silently in Web Components, and by firing value-change in React/Vue/Svelte/Angular. `form` associates every mirrored control with a form the select does not sit inside, and `autoComplete` hints the first of them. A `readOnly` select submits exactly as an editable one does; only `disabled` withholds the value.',validationBehavior:"`invalid` is a purely presentational flag (aria-invalid/data-invalid on the trigger); `required` participates in native constraint validation only when `name` is set. With `name` and `required` and no selection, `checkValidity()`/`reportValidity()` report `valueMissing` and block submission identically in all five frameworks; a select with a value is valid. `maxSelected` makes further options inert rather than invalid \u2014 reaching a cap is not an error. A minimum count, or any cross-field rule, belongs to the surrounding Field or Form.",accessibility:{role:'combobox (trigger, or the filter Input) with aria-haspopup="listbox"; listbox (content, with aria-multiselectable in multiple mode); option (each SelectOption)',keyboard:[{key:"Enter, Space, Alt+ArrowDown (on a closed trigger)",behavior:"Opens the listbox without moving the active option: the active option is the already-selected one. With nothing selected, the first enabled option becomes active."},{key:"ArrowDown / Home (on a closed trigger)",behavior:"Opens the listbox and makes the first enabled option active."},{key:"ArrowUp / End (on a closed trigger)",behavior:"Opens the listbox and makes the last enabled option active."},{key:"ArrowDown / ArrowUp (in listbox)",behavior:"Moves the active option to the next/previous enabled one (no wrap). Virtual focus handles this on the trigger, or on the filter Input while `filterable`."},{key:"PageDown / PageUp (in listbox)",behavior:"Moves the active option ten enabled options down/up, clamped at the ends. Ten is a fixed count for consistency across frameworks."},{key:"Home / End (in listbox)",behavior:"Makes the first / last enabled option active. Only while the listbox is open: with a `filterable` select closed, both are caret keys of the text field and must not be intercepted."},{key:"Alt+ArrowUp (while the listbox is open)",behavior:"Commits the active option and closes the listbox (counterpart to Alt+ArrowDown). Alt+ArrowDown while open does nothing."},{key:"Printable characters (in listbox)",behavior:"Typeahead: makes the next option whose label starts with the typed text active. Matched against `data-text-value` when present, else the option's text. While `filterable` the same keys type into the Input and narrow the list instead."},{key:"Printable characters (on trigger, closed)",behavior:"Typeahead against labels (like native `<select>`): selects the next matching option without opening. Supply `items` for labels before Content mounts. In multiple mode the same keys open the listbox instead of committing, because toggling an option the user cannot see would change the selection blind."},{key:"Enter or Space (while the listbox is open)",behavior:"Selects the active option. Single-select closes the listbox; `multiple` toggles the option and leaves the listbox open. Either way the trigger already holds DOM focus and never loses it."},{key:"Shift+ArrowDown / Shift+ArrowUp (in listbox, multiple)",behavior:"Moves the active option and toggles what it lands on, extending the selection without an Enter at every step. Nothing toggles if the highlight did not move (clamped at the ends). The cap needs no rule of its own: unselected options are already aria-disabled."},{key:"Shift+Space (in listbox, multiple)",behavior:"Selects every enabled option between the last one toggled \u2014 the range anchor \u2014 and the active one, inclusive. Never deselects. Stops where `maxSelected` runs out. With no anchor, selects the active option alone."},{key:"Control+Shift+Home / Control+Shift+End (in listbox, multiple)",behavior:"Selects every enabled option from the active one to the first or last, inclusive. Additive and never deselecting. The active option does not move, and the range anchor stays where the last toggle put it. Inert while the listbox is closed."},{key:"Control+A (in listbox, multiple)",behavior:"While `allowSelectAll`: selects every enabled option, and clears them all if they are already selected. Only while the listbox is open \u2014 closed, it keeps its native meaning of selecting draft text. Stops where `maxSelected` runs out."},{key:"Backspace (on an empty filter Input)",behavior:"Removes the last selected value. Only on an empty input: it must never eat a character the user is still editing."},{key:"Arrow keys (in TagList)",behavior:"Move between the tags of a multiple selection in one roving tab stop."},{key:"Escape",behavior:"Closes the listbox and returns focus to the trigger."},{key:"Tab / Shift+Tab (while the listbox is open)",behavior:"Commits the active option, closes the listbox, and lets focus continue: the default action is never prevented. In multiple mode, Tab *adds* the active option to selection without removing others."}],ariaAttributes:['aria-expanded, aria-controls, aria-haspopup="listbox", aria-required, aria-invalid on the trigger',"aria-autocomplete on the filter Input, which takes aria-expanded and aria-controls in the trigger's place while `filterable`",'aria-readonly="true" and data-readonly on the trigger while `readOnly` (absent otherwise) \u2014 trigger keeps its tab stop, so the state is announced',"aria-labelledby on the trigger, naming the Value part (see `namingRequirement`)","aria-activedescendant on the trigger, or the filter Input, naming the active option (only when open)",'aria-multiselectable="true" on the listbox in multiple mode (absent otherwise)',"aria-selected on each option; data-highlighted on the active one",'aria-disabled="true" and data-disabled on a disabled option (absent otherwise), and on an unselected option once `maxSelected` is reached','aria-busy="true" and data-loading on Content and the filter Input while `loading`',"aria-labelledby on each Group, naming its Label part",'the Empty part carries aria-live="polite" and sits outside the role="listbox"',"the selection count is announced after every change in multiple mode"],focusManagement:`${m} Here the anchor is the trigger, or the filter Input while \`filterable\`. Opening makes the selected (or first enabled) option active. Arrows, Home/End, typeahead, and pointer hover move the active option. Tab closes the listbox and lets focus continue. TagList separately roves real DOM focus among the tags: removing one moves focus to the next tag, the preceding tag if it was the last, or TagList itself if it was the only one \u2014 never to the field. That focus behaviour is inherited from TagGroup rather than re-implemented here.`,namingRequirement:'role="combobox" does NOT take an accessible name from content. Trigger uses aria-labelledby pointing to Value (which is its current value), so a consumer must supply an associated <label> or aria-label for context; the filter Input needs the same. TagList needs its own name, since the tags are its content and cannot name it. Group is named similarly with aria-labelledby and requires a Label part.'},styling:{cssParts:["trigger","value","chip","icon","tag-list","tag","tag-remove","remove","input","clear","content","select-all","item","group","label","separator","item-text","item-indicator","viewport","empty"],dataAttributes:[...g,"data-state","data-disabled","data-readonly","data-invalid","data-loading","data-placeholder","data-highlighted","data-multiple","data-chip","data-skdx-select-tag","data-value","data-text-value","data-side","data-align","data-match-width","data-shape","data-size","data-status","data-density",{name:"data-skdx-select-generated",frameworks:["webComponents"],exception:"wc-marker",frameworksReason:'Marks a node the element generated for itself rather than one the consumer authored. React, Vue, Svelte and Angular re-render their derived anatomy declaratively, so "mine or theirs" is answered by the framework and no marker is needed.'}],cssCustomProperties:c("select")},publicMethods:[...r,s],frameworkExtensions:[{framework:"webComponents",name:"requiredMessage",type:"string",description:"Custom message shown when the required constraint fails; Web Components only, set from markup with the required-message attribute."}]};export{C as selectContract};
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Canonical single-vs-multiple selection-value rule shared across six
3
+ * components: lenient in, strict out.
4
+ */
5
+ /**
6
+ * How a selection value is accepted. Spread into every `value` /
7
+ * `defaultValue` description on a single-or-many control.
8
+ */
9
+ export declare const SELECTION_INPUT_RULE = "Takes a bare string or a string[], whichever reads better \u2014 lenient in. A single-selection control given multiple values throws in dev, takes the first otherwise. Empty string and empty array entries are dropped (nothing selected).";
10
+ /**
11
+ * What comes back out. Spread into every change-event description on a
12
+ * single-or-many control, and into the description of anything a consumer
13
+ * reads the current selection from.
14
+ */
15
+ export declare const SELECTION_OUTPUT_RULE = "Always a string[] plus selectedValue (first value or null) \u2014 strict out. Identical shape in single/multiple mode and all five frameworks \u2014 no cardinality branching needed. selectedValue keeps the single-value case from paying value[0].";
16
+ /**
17
+ * How the collection form survives an HTML attribute. Spread into the Web
18
+ * Components half of a `value` / `defaultValue` description.
19
+ */
20
+ export declare const SELECTION_ATTRIBUTE_RULE = "Attribute form is a comma-separated list under both cardinalities (value=\"a,b\"), parsed by one rule, whitespace trimmed, empty entries dropped. Property still takes string | string[] directly. Values with commas are not expressible as attributes.";
@@ -0,0 +1 @@
1
+ var e="Takes a bare string or a string[], whichever reads better \u2014 lenient in. A single-selection control given multiple values throws in dev, takes the first otherwise. Empty string and empty array entries are dropped (nothing selected).",t="Always a string[] plus selectedValue (first value or null) \u2014 strict out. Identical shape in single/multiple mode and all five frameworks \u2014 no cardinality branching needed. selectedValue keeps the single-value case from paying value[0].",r='Attribute form is a comma-separated list under both cardinalities (value="a,b"), parsed by one rule, whitespace trimmed, empty entries dropped. Property still takes string | string[] directly. Values with commas are not expressible as attributes.';export{r as SELECTION_ATTRIBUTE_RULE,e as SELECTION_INPUT_RULE,t as SELECTION_OUTPUT_RULE};
@@ -0,0 +1,3 @@
1
+ import type { ComponentContract } from './types.js';
2
+ /** Contract for the SignInPage block: provider buttons, an email/password form and a magic-link form. */
3
+ export declare const signInPageContract: ComponentContract;
@@ -0,0 +1 @@
1
+ import{ROOT_DATA_ATTRIBUTES as e}from"./styling-hooks.js";var t={name:"SignInPage",purpose:"A sign-in block composing Heading, Alert, Button, Divider, Form, Field, TextField and PasswordInput. Each provider renders a button, a credentials form or a magic-link form; the block reports what the user chose through one sign-in event and shows the error the consumer hands back. Ships in the blocks package of each framework, not the core package.",props:[{name:"title",type:"string",defaultValue:"'Sign in'",required:!1,description:"Heading text, rendered into a derived <h1> that names the section."},{name:"providers",type:"SignInProvider[]",required:!0,description:"The ways to sign in, in render order, each { id, name }. The id 'credentials' renders the email and password form, 'magic-link' renders the email-only form, and any other id renders a provider button named by getProviderLabel."},{name:"error",type:"string",required:!1,description:"Message rendered into a derived error Alert above the providers. The block never clears it: set it from the sign-in handler and reset it when the next attempt starts."},{name:"emailLabel",type:"string",defaultValue:"'Email'",required:!1,description:"Label of the email field in both forms."},{name:"passwordLabel",type:"string",defaultValue:"'Password'",required:!1,description:"Label of the password field in the credentials form."},{name:"submitLabel",type:"string",defaultValue:"'Sign in'",required:!1,description:"Text of the credentials form submit button."},{name:"magicLinkLabel",type:"string",defaultValue:"'Send magic link'",required:!1,description:"Text of the magic-link form submit button."},{name:"getProviderLabel",type:"(provider: SignInProvider) => string",defaultValue:"defaultProviderLabel",required:!1,description:`Formats a provider button's text from its entry. The default reads "Sign in with Google".`}],events:[{name:"sign-in",detail:"{ providerId: string; email?: string; password?: string }",description:"Fires when a provider button is activated or a form is submitted with valid fields. A button carries only providerId; the credentials form adds email and password, the magic-link form adds email. The native submit is prevented, so the consumer performs the request and sets error on failure."}],slots:[],states:["default"],controlledUncontrolled:"Stateless apart from the field values the native inputs hold; error is always controlled by the consumer.",formBehavior:"The credentials and magic-link forms are core Form roots with required, natively validated fields; an invalid form reports through constraint validation and emits nothing.",validationBehavior:'Fields are required and the email field is type="email"; the core Field wires the messages. The block adds no validators of its own.',accessibility:{role:"region (native <section> named by its heading through aria-labelledby)",keyboard:[{key:"Enter",behavior:"Submits the form whose field has focus (native form submission)."},{key:"Enter/Space",behavior:"Activates a focused provider button (native button activation)."}],ariaAttributes:["aria-labelledby on the <section> points at the derived heading","the derived error Alert is a live region, so a new error is announced without moving focus","each field is labelled through the core Field, which wires aria-describedby and aria-invalid"],focusManagement:"Focus stays where the user put it; a failed attempt announces the error through the Alert rather than moving focus."},styling:{cssParts:["sign-in-page","panel","title","error","providers","provider","divider","form","field","submit"],dataAttributes:[...e,"data-provider","data-status"],cssCustomProperties:[]},publicMethods:[]};export{t as signInPageContract};
@@ -0,0 +1,3 @@
1
+ import type { ComponentContract } from './types.js';
2
+ /** Contract for the SignUpPage block: provider buttons above a credentials form with confirmation and terms. */
3
+ export declare const signUpPageContract: ComponentContract;