@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{autoFocusEvents as t,dismissalEvents as o,forceMountProp as a,openChangeCompleteEvent as n,portalPart as e,portalPropsSansForceMount as s}from"./overlay-parts.js";import{PART_DATA_ATTRIBUTES as i}from"./styling-hooks.js";var d={name:"Dialog",purpose:`An accessible modal (or non-modal) dialog with focus trapping, scroll locking, and top-layer rendering. Given plain body content as children, the root derives its whole anatomy \u2014 Portal, Overlay, a panel with a derived Title/Description, the body, an optional footer, and a close button. With role="alertdialog" it is the interruptive confirmation: always modal, never closed by an outside interaction, focused on Cancel first, with derived Action and Cancel buttons from confirmLabel/cancelLabel. Manual composition of Trigger/Portal/Overlay/Content/Title/Description/Close/Action/Cancel is reached only through each framework's primitives/dialog subpath, never through this recipe's children.`,props:[{name:"title",type:"string",required:!1,description:"The panel's accessible name, rendered as the Title part. In Web Components, `title` shadows `HTMLElement.title` (harmless since the host is `display: contents`); an empty string counts as unset."},{name:"description",type:"string",required:!1,description:"The derived panel's accessible description, rendered as the Description part."},{name:"dismissible",type:"boolean",defaultValue:"true",required:!1,description:"Whether the panel can be dismissed. `false` forces dismiss to `'none'` (overriding any other value) and withholds the close button. The close button gates on this prop alone, not on `dismiss`, because `dismiss` governs implicit channels (Escape, outside); once `dismiss='none'` the close button is the only exit, so withholding it would strand the panel."},{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:"modal",type:"boolean",defaultValue:"true",required:!1,description:"Whether the page is inert and locked from scrolling. true puts up a barrier (native showModal()); false leaves the page interactive (native show()). Owns three things: focus trap, inertness of everything outside, and body-scroll lock. The scroll lock mutates document.body.style.overflow and paddingRight while modal overlays are open, reference-counted across stacked Dialog/Drawer/LoadingOverlay, and restored to their exact prior strings on close. Modal does NOT own whether a dismissal channel closes the dialog \u2014 that is the dismiss prop. Outside dismissal cannot happen while the page is live; a non-modal dialog only reports it."},{name:"dismiss",type:"'any' | 'escape' | 'outside' | 'none'",defaultValue:"'any'",required:!1,description:'Which channels can close the dialog: "any" both Escape and outside, "escape" Escape only, "outside" outside interaction only, "none" neither (closes only via open/defaultOpen, Close part, or Trigger toggle). A policy, not a mute: the three outside events (pointer-down-outside, focus-outside, interact-outside) fire in every mode, and escape-key-down fires wherever the platform delivers Escape to the dialog \u2014 through the cancel event a native <dialog> raises for itself, which it raises only while modal. This prop decides whether an un-prevented one closes the dialog. Dismissal events still fire when prevented, so a consumer can log or veto; dismiss="none" is declarative preventDefault(), not a way to stop hearing about them. Outside dismissal requires modal, so dismiss="outside" on a non-modal dialog still closes on nothing. Resolved value is data-dismiss on Content, not the root.'},{name:"size",type:"'sm' | 'md' | 'lg' | (string & {})",required:!1,description:"Size rung forwarded to the Content panel's data-size; the attribute may be written on Content directly instead."},{name:"role",type:"'dialog' | 'alertdialog'",defaultValue:"'dialog'",required:!1,description:`The panel's role. "alertdialog" is the interruptive confirmation: Content renders role="alertdialog", modal is forced on, the outside channels of dismiss never close it (any resolves to escape, outside to none, reflected in data-dismiss), initial focus lands on Cancel before the first tabbable, the derived close button is withheld because Cancel is the explicit exit, and confirmLabel/cancelLabel default to "Confirm"/"Cancel" so the recipe always derives both buttons.`},{name:"status",type:"'info' | 'success' | 'warning' | 'danger' | (string & {})",required:!1,description:`Severity rung, written to data-status on the Content panel and forwarded to the derived Action button's own status; the data-status attribute may be set directly instead. "danger" is the destructive confirmation.`},{name:"confirmLabel",type:"string",required:!1,description:'Label of the derived Action button, which renders only when this is given \u2014 or always under role="alertdialog", where it defaults to "Confirm". Ignored when children replace the anatomy under manual composition.'},{name:"cancelLabel",type:"string",required:!1,description:'Label of the derived Cancel button, which renders only when this is given \u2014 or always under role="alertdialog", where it defaults to "Cancel". Ignored when children replace the anatomy under manual composition.'}],events:[{name:"open-change",detail:"boolean",description:"Fired with the new open state whenever it changes, controlled or not."},n("dialog"),...o("dialog",{outsideNote:'Only a modal dialog closes on an outside interaction. With modal={false} all three are notification-only \u2014 the payload is still a cancelable event, so the shared payload assertion holds, but there is no dismissal behind it and preventing default changes nothing. They keep firing because they are the only way a consumer learns a non-modal dialog was clicked past. The dismiss policy is the second gate on the same path and behaves the same way: with dismiss="escape" or dismiss="none" these three still fire on a modal dialog and still close nothing, and with dismiss="outside" escape-key-down still fires and still closes nothing.'}),...t("dialog"),{name:"confirm",detail:"Event",description:"Fires when the derived Action button is clicked, before the close. Cancelable: preventDefault() suppresses the close, the supported way to hold a confirmation open while its request is in flight."},{name:"cancel",detail:"Event",description:"Fires when the derived Cancel button is clicked, before the close. Cancelable: preventDefault() suppresses the close."}],parts:[{name:"Trigger",description:'The button that opens the dialog (aria-haspopup="dialog", aria-expanded, aria-controls, data-state).'},{...e,frameworks:["react","webComponents"],frameworksReason:"Vue, Svelte and Angular render no Portal: Content is written where it stands, and showModal()/show() already promote it to the top layer. React and Web Components keep the part so the Overlay can escape a clipping ancestor and land in a chosen container.",description:`${e.description} Shipped by React and Web Components only, and always mounted: Content is a native <dialog> that has to outlive its own close(). Vue, Svelte and Angular render no Portal at all.`,props:[...s]},{name:"Overlay",description:"The scrim behind Content. A real element in all five frameworks \u2014 the four native-<dialog> ports paint its ::backdrop transparent so this part is the single scrim. It carries data-state and animates independently.",props:[{...a,frameworks:["react","vue","svelte"],frameworksReason:"Web Components only hides closed overlays (no unmount for forceMount to prevent). Angular toggles with [hidden] instead of unmounting, so it ships no forceMount."}]},{name:"Content",description:'The panel with role="dialog", labelled/described by Title/Description, aria-modal, data-state and data-dismiss. Handles dismissal (Escape, outside), scroll lock, and focus return; the focus trap, top layer and page inertness come from the platform. A native <dialog> driven by showModal()/show()/close() in all five frameworks, always mounted so close() has an element to fire on \u2014 which is why no framework ships forceMount on this part. Fires all dismissal and auto-focus events (declared on root to avoid duplication across dismissalEvents in overlay-parts).',lightDom:!0,props:[{name:"initialFocus",type:"string",required:!1,description:"CSS selector for the element to focus on open, resolved with querySelector inside Content. A selector rather than a ref because Web Components attributes cannot hold element handles, and five ports take the same value. Applies only when open-auto-focus was not vetoed. Falls back to the first tabbable or Content itself when the selector matches nothing, to prevent focus stranding on <body> inside a modal dialog."},{name:"finalFocus",type:"string",required:!1,description:"CSS selector for the element to focus on close, resolved at document level because Content is gone by then. The element that opened the dialog may no longer exist (a deleted row, a re-rendered list). Applies only when close-auto-focus was not vetoed. Falls back to the element that had focus before opening."},{name:"size",type:"'sm' | 'md' | 'lg' | (string & {})",required:!1,description:"Visual size rung, written to data-size on the content panel; the data-size attribute may be set directly instead."}]},{name:"Title",description:"The dialog's accessible name, referenced by Content's aria-labelledby."},{name:"Description",description:"The dialog's accessible description, referenced by Content's aria-describedby."},{name:"Close",description:"A button that closes the dialog. Rendered anywhere inside Content."},{name:"Action",description:"The button that carries out a confirmed action. Closes after the handler runs, unless preventDefault() is called on the confirm event \u2014 the supported way to hold a confirmation open while the request is in flight. Carries data-status when the root has one.",props:[{name:"disabled",type:"boolean",defaultValue:"false",required:!1,description:"Sets the native disabled attribute so the button neither confirms nor closes the dialog when clicked."}]},{name:"Cancel",description:"The button that abandons the action. Marked with data-skdx-dialog-cancel, so an alertdialog focuses it first (the least destructive option). Its close is vetoable through the cancel event.",props:[{name:"disabled",type:"boolean",defaultValue:"false",required:!1,description:"Sets the native disabled attribute so the button neither cancels nor closes the dialog when clicked."}]},{name:"Dialogs",description:"The host that renders the imperative queue: whatever createDialogs is showing \u2014 an alert, a confirm or a prompt \u2014 as one Dialog at a time, keyed on the entry. React/Vue/Svelte/Web Components take the store as a `dialogs` prop; Angular injects SkdxDialogService instead. Takes no other props: title, description, labels and status arrive on each call. Emits data-kind on the panel.",props:[{name:"dialogs",type:"DialogsStore",required:!0,frameworks:["react","vue","svelte","webComponents"],exception:"imperative",frameworksReason:"Angular resolves the queue by injecting SkdxDialogService, so the host takes no store input.",description:"The queue to render, from createDialogs; Web Components default to a store of their own, read back off the element."}]}],contextApi:[{name:"createDialogs",signature:"() => DialogsStore",description:"Creates the alert / confirm / prompt queue once per app; alert resolves on dismissal, confirm with a boolean, prompt with the text or null. Web Components create one per <skdx-dialogs> by default.",accessors:{react:"createDialogs() from '@skdx/react'",vue:"createDialogs() from '@skdx/vue'",svelte:"createDialogs() from '@skdx/svelte'",angular:"inject(SkdxDialogService) \u2014 alert / confirm / prompt on the service",webComponents:"createDialogs() from '@skdx/web-components', or <skdx-dialogs>.dialogs"}}],slots:[{name:"trigger",description:"Trigger's content \u2014 the button that opens the dialog."},{name:"default",description:"Body content of the derived panel, rendered inside Content after Title/Description and before footer/Close. On the recipe root this is always body content; under full manual composition via primitives, it is Content's hand-composed body."},{name:"title",description:"Title content \u2014 the dialog's accessible name."},{name:"description",description:"Description content \u2014 the dialog's accessible description."},{name:"footer",description:"Content after the body, before the close button (typically action buttons)."}],states:["closed","open"],controlledUncontrolled:"Stateless by default (uncontrolled): starts at defaultOpen and manages its own state internally. Passing open switches to controlled \u2014 the consumer owns state and must update it from open-change, or the dialog will not open/close on its own.",formBehavior:'Not applicable \u2014 Dialog participates in no form; Close and Trigger are type="button".',validationBehavior:"Not applicable.",accessibility:{role:'dialog, or alertdialog under role="alertdialog"',keyboard:[{key:"Escape",behavior:'Requests close (cancelable via escape-key-down). The event fires whatever the dismiss policy is; the close only follows when dismiss allows the escape channel ("any" or "escape").'},{key:"Tab / Shift+Tab",behavior:"Cycles focus within Content only, while modal (native focus trap)."}],ariaAttributes:["aria-modal reflects the modal prop while open","aria-labelledby points at Title's generated id, only once a Title renders \u2014 an unconditional dangling IDREF is no name at all","aria-describedby points at Description's generated id, same condition",'aria-haspopup="dialog", aria-expanded, aria-controls on Trigger',"showModal() makes everything outside an open modal dialog inert; aria-modal documents the barrier."],focusManagement:'Moves focus into Content on open \u2014 to a Cancel part first under role="alertdialog" \u2014 and traps it there while open; returns focus to the prior element on close (typically Trigger). Both fire as cancelable open-auto-focus/close-auto-focus events. A veto is honoured either by suppressing the move before it happens or by undoing it after the platform has made it; the end state matches, but in the compensated case focusin/focusout listeners see an extra round trip. For "focus this field, return there": Content accepts initialFocus and finalFocus selectors, applied only when the event was not vetoed.',namingRequirement:'Always render Title for the accessible name via aria-labelledby. If no visible title, add an explicit aria-label on Content \u2014 a dialog with no name announces as bare "dialog". Under role="alertdialog" render Description too: the alertdialog pattern makes the description part of the announcement, and nothing stands in for it.'},appearance:[{attribute:"data-size",values:["sm","md","lg"],stylesheet:"dialog.css"},{attribute:"data-status",values:["info","success","warning","danger"],stylesheet:"dialog.css"}],styling:{cssParts:["trigger","overlay","content","title","description","close","action","cancel","footer","body","close-icon"],dataAttributes:[...i,"data-state","data-kind","data-dismiss","data-skdx-dialog-cancel","data-status","data-disabled",{name:"data-size",frameworks:["webComponents"],exception:"attribute-passthrough",frameworksReason:"The custom element mirrors a consumer-authored data-size from its host onto the native dialog it renders, because the skin sizes the content off that node. The other frameworks spread the attribute straight onto the content element."},{name:"data-skdx-dialog-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:[{name:"setOpen",signature:"(open: boolean) => void",frameworks:["webComponents"],exception:"imperative",frameworksReason:"Only the custom element publishes it. The other four re-render with a new open 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:"Opens or closes the dialog and emits open-change, exactly as the trigger would."}]};export{d as dialogContract};
@@ -0,0 +1,5 @@
1
+ import type { ComponentContract } from './types.js';
2
+ /**
3
+ * A visual or semantic divider between content, decorative or not.
4
+ */
5
+ export declare const dividerContract: ComponentContract;
@@ -0,0 +1 @@
1
+ import{ROOT_DATA_ATTRIBUTES as e}from"./styling-hooks.js";var a={name:"Divider",purpose:'A visual or semantic divider between content. Renders a native <hr> with role="separator" and aria-orientation (vertical only) by default, or role="none" when decorative.',props:[{name:"orientation",type:"'horizontal' | 'vertical'",defaultValue:"'horizontal'",required:!1,description:"Layout axis, always exposed as a data-orientation styling hook and, when not decorative, also as aria-orientation (vertical only \u2014 horizontal is the ARIA default and is omitted)."},{name:"decorative",type:"boolean",defaultValue:"false",required:!1,description:'When true, the separator is purely visual and removed from the accessibility tree (role="none").'},{name:"role",type:"string",required:!1,frameworks:["angular","webComponents"],exception:"attribute-passthrough",frameworksReason:"React, Vue and Svelte take `role` on the element through attribute passthrough.",description:"Overrides the default `separator`/`none` role, e.g. `doc-pagebreak`."},{name:"inset",type:"'inset' | (string & {})",required:!1,description:"Whether the rule is indented from the edge, written to data-inset; the data-inset attribute may be set directly instead."}],events:[],slots:[],appearance:[{attribute:"data-inset",values:["inset"],stylesheet:"divider.css"}],states:["default"],controlledUncontrolled:"Stateless \u2014 Divider holds no internal state.",formBehavior:"Not applicable \u2014 Divider does not participate in forms.",validationBehavior:"Not applicable \u2014 Divider carries no value and participates in no validation.",accessibility:{role:"separator (or none when decorative)",keyboard:[],ariaAttributes:["aria-orientation reflects the orientation prop when vertical and not decorative",'aria-label names the separator; it must land on the element carrying role="separator", not on a boxless host or a custom-element host that has no role',"aria-labelledby names the separator from another element; an IDREF cannot resolve across a shadow root, where aria-label is the only labelling path"],focusManagement:"Not focusable; not part of the tab order.",namingRequirement:"Unnamed by default, which is correct for a plain rule. A separator that divides named regions may be named with aria-label or aria-labelledby; the name must be set on the role-bearing element."},styling:{cssParts:["separator"],dataAttributes:[...e,"data-orientation","data-inset"],cssCustomProperties:["--skdx-divider-color","--skdx-divider-thickness","--skdx-divider-inset","--skdx-divider-min-length"]},publicMethods:[]};export{a as dividerContract};
@@ -0,0 +1,3 @@
1
+ import type { ComponentContract } from './types.js';
2
+ /** The Drawer contract: a panel that slides in from a viewport edge, modal by default. */
3
+ export declare const drawerContract: ComponentContract;
@@ -0,0 +1 @@
1
+ import{autoFocusEvents as a,dismissalEvents as o,forceMountProp as e,openChangeCompleteEvent as n,portalPart as t}from"./overlay-parts.js";import{PART_DATA_ATTRIBUTES as s}from"./styling-hooks.js";var l={name:"Drawer",purpose:`An accessible panel that slides in from a viewport edge \u2014 a side sheet, navigation drawer, or (placement="bottom") a bottom sheet. Modal by default with focus trapping, scroll locking and stacking; non-modal keeps dismissal and stacking but leaves the page interactive. The recipe derives its anatomy \u2014 Portal, Overlay, panel with Title/Description, body, optional footer, and close button. Manual composition is reached only through each framework's primitives/drawer subpath.`,props:[{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:"dismissible",type:"boolean",defaultValue:"true",required:!1,description:"Whether the panel can be dismissed. `false` forces the dismiss policy to `'none'` and withholds the close button; `dismiss` still applies while `true`. The close button is gated on this prop alone, never on `dismiss` \u2014 if dismiss is `'none'`, the explicit close button is the only way out."},{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:"placement",type:"'start' | 'end' | 'top' | 'bottom'",defaultValue:"'end'",required:!1,description:'Which viewport edge the drawer is anchored to, expressed logically: start/end follow the writing direction (start is left under dir="ltr" and right under dir="rtl"), top/bottom are physical. placement="bottom" is the bottom-sheet case. Content publishes it twice, not interchangeably: data-placement is this value verbatim, unresolved, for logical CSS (inset-inline-start, translate with logical sign); data-side is the *physical* edge the same value resolves to under the ambient writing direction \u2014 start becomes left under dir="ltr" and right under dir="rtl", while top and bottom pass through unchanged. All five frameworks resolve it, and @skdx/skins positions from data-side, because a slide-in needs a physical translate and CSS cannot resolve a logical edge to one.'},{name:"modal",type:"boolean",defaultValue:"true",required:!1,description:'Whether the drawer traps focus, locks body scroll, and blocks page interaction. A non-modal drawer skips the focus trap and scroll lock but keeps Escape, outside-interaction dismissal (see dismiss), and overlay stacking. The scroll lock mutates document.body.style: overflow becomes "hidden" and paddingRight becomes the scrollbar width, so the page does not shift. The lock is reference-counted across stacked overlays (Dialog, Drawer, LoadingOverlay share one counter) and both properties restore to their original strings. On by default: a drawer scrolling the page while the user drags inside is the failure mode; defaulting safe costs one prop to opt out.'},{name:"dismiss",type:"'any' | 'escape' | 'outside' | 'none'",defaultValue:"'any'",required:!1,description:"Which dismissal channels close the drawer: any (both); escape (Escape key only); outside (pointer-down or focus-move outside only); none (neither, leaving Close/Trigger/open prop as the only ways out). A policy, not a mute: all four dismissal events (escape-key-down, pointer-down-outside, focus-outside, interact-outside) keep firing and remain cancelable, so a consumer can observe and respond to policy-refused attempts. One prop covering both channels, so the policy reads as a single value across Drawer and Dialog. Unlike Dialog, a drawer dismisses on outside interaction whether or not modal \u2014 that is the point of a side sheet you can shrug off \u2014 so modal={false} does not turn outside dismissal off; dismiss is the only declarative way to disable it. The resolved value reflects as data-dismiss on Content, not the root, because the root renders no element in four of five frameworks."},{name:"size",type:"'sm' | 'md' | 'lg' | (string & {})",required:!1,description:"Size rung forwarded to the Content panel's data-size; the attribute may be written on Content directly instead."}],events:[{name:"open-change",detail:"boolean",description:"Fired with the new open state whenever it changes, controlled or not."},n("drawer"),...o("drawer"),...a("drawer")],parts:[{name:"Trigger",description:'The button that opens the drawer (aria-haspopup="dialog", aria-expanded, aria-controls, data-state).'},{...t,description:`${t.description} Shipped by React, Vue, Svelte and Web Components. Angular portals via the [skdxPortal] attribute directive (skdxPortal input carries the same container capability). In Web Components, force-mount does not apply (parts hide with hidden attribute, never unmount) and container is a property, not attribute, because a DOM node cannot cross one.`},{name:"Overlay",description:"The scrim rendered behind Content, typically dimming the page. A real element (not ::backdrop pseudo-element) animated independently of the panel with its own data-state. Rendered whether modal or not; non-modal usually styles it as pointer-events: none or omits it entirely.",props:[e]},{name:"Content",description:'The sliding panel: role="dialog", labelled/described by Title/Description, with aria-modal and data-state reflecting state, plus data-placement (logical prop verbatim) and data-side the physical edge it resolves to under ambient writing direction. Also carries data-dismiss (the resolved dismiss policy value) because the root renders no element in four of five frameworks. Owns dismissal (Escape, outside interaction) and \u2014 while modal \u2014 the focus trap, scroll lock, and focus return on close. Fires all six dismissal/auto-focus events declared on the root (see dismissalEvents in ./overlay-parts).',props:[e,{name:"initialFocus",type:"string",required:!1,description:'CSS selector for the element to receive focus when the drawer opens, resolved with querySelector inside Content. A selector string (not a handle) because an element cannot cross HTML attributes; the Web Components port needs initial-focus="\u2026". Applies only when open-auto-focus was not vetoed (a veto already means "I am placing focus myself"). When the selector matches nothing, focus falls back to the first tabbable in Content with a warning; the fallback prevents strand-on-body mistakes. Inert on non-modal \u2014 a non-modal drawer does not move focus in, so there is no initial move to redirect.'},{name:"finalFocus",type:"string",required:!1,description:"CSS selector for the element focus should return to when the drawer closes, resolved with querySelector at document level. Unlike initialFocus (target inside Content), this target is outside by definition (the list item the drawer was editing, a toast, a field). Applies only when close-auto-focus was not vetoed; falls back to the element that had focus before opening (typically Trigger) with a warning, preventing strand-on-body mistakes. Live on non-modal too: a non-modal drawer never moves focus in but does return focus it would otherwise strand, so when Escape closes a non-modal drawer the user tabbed into, focus goes here instead of Trigger."},{name:"size",type:"'sm' | 'md' | 'lg' | (string & {})",required:!1,description:"Visual size rung, written to data-size on the content panel; the data-size attribute may be set directly instead."}]},{name:"Title",description:"The drawer's accessible name, referenced by Content's aria-labelledby."},{name:"Description",description:"The drawer's accessible description, referenced by Content's aria-describedby."},{name:"Close",description:"A button that closes the drawer. Rendered anywhere inside Content."}],slots:[{name:"trigger",description:"Trigger's content \u2014 the button that opens the drawer."},{name:"default",description:"The panel's body content, rendered inside Content after any Title/Description and before footer/Close. On the recipe root always; on manual composition through primitives, this is Content's body."},{name:"title",description:"Title's content \u2014 the drawer's accessible name."},{name:"description",description:"Description's content \u2014 the drawer's accessible description."},{name:"footer",description:"Content placed after the body inside the panel, typically action buttons."}],states:["closed","open"],controlledUncontrolled:"Uncontrolled by default: starts at defaultOpen and manages its own state. Passing open switches to controlled \u2014 the consumer owns state and must update it from open-change.",formBehavior:'Not applicable \u2014 Drawer participates in no form; Close and Trigger are type="button".',validationBehavior:"Not applicable.",accessibility:{role:"dialog",keyboard:[{key:"Escape",behavior:'Requests close (cancelable via escape-key-down), modal or not. Fires under every dismiss policy; actually closes only when dismiss is "any" or "escape".'},{key:"Tab / Shift+Tab",behavior:"Cycles focus within Content only, while modal. A non-modal drawer does not trap Tab \u2014 focus leaves it, reported as focus-outside."}],ariaAttributes:["aria-modal reflects the modal prop while open","aria-labelledby points at Title's generated id, emitted only once a Title has rendered \u2014 an unconditional attribute at an absent id leaves the panel with no accessible name, since the platform does not fall back past a dangling IDREF","aria-describedby points at Description's generated id, on the same condition",'aria-haspopup="dialog", aria-expanded, and aria-controls on Trigger',`While a modal drawer is open, everything outside it is inert. No framework renders a native <dialog> here, so unlike Dialog none of the five gets this from the platform \u2014 each writes inert on the portal container's siblings itself, making aria-modal="true" a true statement`],focusManagement:"While modal, moves focus into Content when opened \u2014 to initialFocus selector when given and matches, else to the first tabbable \u2014 and returns focus on close to finalFocus selector when given and matches, else to the element that had focus before opening (typically Trigger). Both selectors are advisory: no match falls back to the default rather than strand-on-body. Both moves are announced as cancelable open-auto-focus / close-auto-focus events, and preventing default genuinely suppresses the move in all five frameworks (no uncancelable platform move involved). A non-modal drawer does not move focus in \u2014 nothing pulls the user out of the page \u2014 but returns focus it would otherwise strand: if the active element is inside Content when a non-modal drawer closes, close-auto-focus fires and, unless vetoed, focus goes back to Trigger or to finalFocus (live in that mode even though initialFocus is not). Focus never moved in needs no return, so no event fires in that case.",namingRequirement:'Always render Title \u2014 it supplies the accessible name referenced by aria-labelledby. A drawer with no visible title must instead carry an explicit aria-label on Content: role="dialog" with no name announces as a bare "dialog", and omitting Title leaves aria-labelledby pointing at nothing.'},appearance:[{attribute:"data-size",values:["sm","md","lg"],stylesheet:"drawer.css"}],styling:{cssParts:["trigger","overlay","content","title","description","close","footer","body","close-icon"],dataAttributes:[...s,"data-state","data-placement","data-side","data-dismiss","data-size",{name:"data-skdx-drawer-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:[{name:"setOpen",signature:"(open: boolean) => void",frameworks:["webComponents"],exception:"imperative",frameworksReason:"Only the custom element publishes it. The other four re-render with a new open 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:"Opens or closes the drawer and emits open-change, exactly as the trigger would."}]};export{l as drawerContract};
@@ -0,0 +1,3 @@
1
+ import type { ComponentContract } from './types.js';
2
+ /** The Editable contract: text that reads as text until it's asked to become an input, and hands focus back when done. */
3
+ export declare const editableContract: ComponentContract;
@@ -0,0 +1 @@
1
+ import{changeDetail as t}from"./change-reason.js";import{constraintValidationMethods as i,webComponentsValidationMethods as r}from"./form-validity.js";import{ROOT_DATA_ATTRIBUTES as a}from"./styling-hooks.js";var d={name:"Editable",purpose:"An inline-edit control: preview reads as text, acts as button; input/textarea replaces it in edit mode; submit/cancel/edit triggers. Root owns draft value, edit state, activation, submit gestures, and focus handoff. Composed of root plus Preview, Input, Textarea, SubmitTrigger, CancelTrigger, and EditTrigger parts.",props:[{name:"name",type:"string",required:!1,description:"Form field name; when set, the root renders one visually-hidden input carrying the committed value, so an Editable submits like any other form control. Absent by default \u2014 a deliberate opt-in."},{name:"form",type:"string",required:!1,description:"Id of the form to submit with, mirroring the native form attribute, for an Editable rendered outside its <form>. Only meaningful alongside `name`."},{name:"value",type:"string",required:!1,description:"Controlled text paired with value-change. Tracks live draft while editing, not just committed text \u2014 use commit event if only submitted result matters."},{name:"defaultValue",type:"string",required:!1,description:"Initial text for uncontrolled usage. Starts empty when omitted, so preview shows placeholder and root carries data-empty."},{name:"editing",type:"boolean",required:!1,description:"Controlled edit state \u2014 whether the input is showing instead of the preview. Pair with the edit-change event."},{name:"defaultEditing",type:"boolean",defaultValue:"false",required:!1,description:"Whether to start in edit mode, for uncontrolled usage. Starting true focuses the input on mount, so use it only when the edit is the reason the surface appeared."},{name:"placeholder",type:"string | { edit: string; preview: string }",required:!1,description:"Text rendered by Preview when empty and set as editor placeholder. Plain string sets both; object form sets separately (preview's doubles as accessible name while empty, so reads as label; editor's is hint). An Editable with neither placeholder nor value renders an unnamed button \u2014 always supply one, an aria-label, or Label part. On <skdx-editable> attribute takes only string form; object form is JS property."},{name:"finalFocusEl",type:"() => HTMLElement | null",required:!1,description:"Where focus goes when edit ends, overriding default (Preview). Function resolved when focus moves, not render, since target element often doesn't exist yet. Returning null falls back to Preview. Property-only on <skdx-editable>: functions have no attribute form."},{name:"disabled",type:"boolean",defaultValue:"false",required:!1,description:"Blocks editing entirely and takes the preview out of the tab order."},{name:"readOnly",type:"boolean",defaultValue:"false",required:!1,description:"Shows the value but blocks entering edit mode. The preview stays focusable, unlike disabled, so the text is still reachable by keyboard."},{name:"required",type:"boolean",defaultValue:"false",required:!1,description:"Rejects blank submit: pre-edit text is restored, no commit event fires, edit mode closes. Whitespace counts as blank."},{name:"maxLength",type:"number",required:!1,description:"Maximum number of characters the input accepts, forwarded to the native maxLength attribute."},{name:"activationMode",type:"'click' | 'dblclick' | 'focus' | 'none'",defaultValue:"'click'",required:!1,description:"Which pointer gesture on Preview enters edit mode: 'click' (default), 'dblclick', 'focus'. 'none' matches no gesture, for entry via EditTrigger or controlled editing prop only. Keyboard activation (Enter/Space) works in every mode, including 'none'."},{name:"submitMode",type:"'blur' | 'enter' | 'both' | 'none'",defaultValue:"'both'",required:!1,description:"Which gestures commit the draft: 'enter', 'blur', 'both', or 'none' (SubmitTrigger only). Escape always cancels."},{name:"invalid",type:"boolean",defaultValue:"false",required:!1,description:`Marks current value as invalid (server rejection or Field rule). Published as data-invalid on root, Preview, editor and aria-invalid="true" on editor (Preview's role="button" deprecates it in ARIA 1.2, so carries styling hook only). Consumer-owned: never set by component.`},{name:"selectOnFocus",type:"boolean",defaultValue:"true",required:!1,description:"Select the whole value when edit mode opens, so typing replaces it. With false the caret is placed at the end instead, so typing appends."},{name:"multiline",type:"boolean",defaultValue:"false",required:!1,description:"Whether the derived editor is a Textarea instead of an Input. Ignored under hand composition."},{name:"showControls",type:"boolean",defaultValue:"false",required:!1,description:"Whether the derived anatomy includes a SubmitTrigger/CancelTrigger pair after the editor. Off by default, since a derived editable that already commits on blur and Enter would otherwise grow two buttons on upgrade. Ignored under hand composition."}],events:[{name:"value-change",description:"Fired with new text on every keystroke while editing, and with restored text when edit is cancelled or rejected.",detail:t("string")},{name:"value-commit",description:"Fired once with final text on successful submit. Never fires for an Escape-cancel or a required field submitted empty \u2014 both restore pre-edit text instead.",detail:"string"},{name:"value-revert",description:"Fired when edit is abandoned: Escape-cancel, a CancelTrigger click, or a required field submitted blank. All three also fire value-change with restored text; value-revert distinguishes abandonment from typing. Fires after value is restored, so `value` is on-screen and `previousValue` is discarded draft.",detail:"{ value: string; previousValue: string }"},{name:"edit-change",detail:"boolean",description:"Fired with the new edit state whenever it flips, controlled or not."}],parts:[{name:"Preview",description:'Read-mode text that starts an edit, rendered as role="button" for keyboard reachability (not pointer-only). Renders nothing while editing, carries data-empty when blank.'},{name:"Input",lightDom:!0,description:"Single-line editor. Value, placeholder, and constraints come from root's context, so draft cannot diverge from what root tracks."},{name:"Textarea",lightDom:!0,description:"Multi-line editor, alternative to Input with same wiring. Auto-resize implementation shared across all five packages, not duplicated.",props:[{name:"autoResize",type:"boolean",defaultValue:"false",required:!1,description:"Grow the editor to fit its content instead of showing a scrollbar. `resize: none` removes the drag handle while this is on."},{name:"maxRows",type:"number",required:!1,description:"Caps auto-resize growth to this many rows, based on computed line-height; past the cap the editor scrolls again."},{name:"minRows",type:"number",defaultValue:"2",required:!1,description:"Editor's opening size and floor auto-resize won't shrink below. Rendered as native rows attribute when autoResize off, applied as minimum on measured height when on. When minRows and maxRows disagree, maxRows wins."},{name:"rows",type:"number",required:!1,frameworks:["angular"],exception:"attribute-passthrough",frameworksReason:"React, Vue and Svelte reach the same capability without a declared member: `rows` lands on the rendered <textarea> through their normal attribute passthrough, where it beats `minRows`. Angular templates forward no unknown attribute to a projected host, so the same attribute has to be a declared input there. Web Components has no counterpart at all: its <textarea> lives in the shadow template with `rows` bound from `minRows`, so a second `rows` would be a rival source of truth for one attribute the element already writes.",description:"Native rows attribute on the editor, overriding the opening size minRows would otherwise set."}]},{name:"Label",lightDom:!0,description:`A real <label> naming the editor and Preview's aria-labelledby target. Renders a <label> (not styled <span>): its for resolves to Input or Textarea, so clicking focuses the editor and platform computes the name. Names the Preview (role="button"), so empty preview announces label instead of placeholder, making placeholder-less Editables nameable. Renders in both modes \u2014 a label that disappears when value empties is a name that comes and goes. Area and Control are NOT parts: pure layout for consumers.`},{name:"SubmitTrigger",description:"Button that commits the draft. Renders nothing outside edit mode."},{name:"CancelTrigger",description:"Button that discards draft and restores pre-edit text. Renders nothing outside edit mode."},{name:"EditTrigger",description:"Button that opens edit from outside preview (e.g., pencil icon beside text, where clicking text shouldn't edit). Renders nothing while editing."}],slots:[{name:"default",description:"The control's body \u2014 a Preview, an Input or Textarea, and whichever of the triggers the flow needs. Each part decides for itself whether to render in the current mode, so the same markup covers both."}],states:["preview","edit","empty","disabled","readonly","invalid"],controlledUncontrolled:"Two independent controlled/uncontrolled axes \u2014 value and editing \u2014 each starting from its default* prop and switching to controlled when the matching prop is passed. The pre-edit text is always held internally, since restoring it on cancel must work whether or not the value is controlled. It is snapshotted on the transition of editing from false to true, not by the activation gesture, so all three ways in \u2014 the gesture, defaultEditing on mount, and a controlled flip from outside \u2014 restore the text that was on screen when that edit opened.",formBehavior:"Not a native form control in itself \u2014 the editor is a real input, but the root submits nothing. A consumer inside a form serialises the committed value themselves.",validationBehavior:"One rule: required rejects blank submit by restoring previous text rather than committing \u2014 deliberately not an error state, but not silent (rejection fires value-revert with discarded draft). Editor carries aria-required, since native required attribute has no form owner. Everything else (length, pattern, server errors) belongs to surrounding Field, which reads committed value and drives consumer-owned invalid prop. Pair required with invalid for visible rejection vs one announcement.",accessibility:{role:"button (Preview)",keyboard:[{key:"Enter / Space (on the Preview)",behavior:"Enters edit mode. Works in every activation mode, so the pointer-flavoured modes never make the control keyboard-inaccessible."},{key:"Enter (in the single-line Input)",behavior:"Commits the draft while submitMode includes 'enter'. Single-line only: the multi-line Textarea needs plain Enter for a newline, so its chord is the row below."},{key:"Cmd/Ctrl+Enter (in the multi-line Textarea)",behavior:"Commits the draft while submitMode includes 'enter'. A plain Enter is left entirely alone and inserts a newline, because a multi-line editor that submitted on Enter could not be used to write a second line."},{key:"Escape",behavior:"Always cancels, restoring the pre-edit text and returning focus to the Preview, regardless of submitMode. There is no configuration that traps a user in an edit. The text it restores is the text that was on screen when this edit opened, including when the edit was opened by the controlled editing prop rather than by a gesture."},{key:"Tab",behavior:"Leaves the editor, which commits while submitMode includes 'blur'."}],ariaAttributes:['role="button" on the Preview, so read-mode text that opens an editor is announced as the control it is',"The placeholder doubles as the Preview's accessible name while the value is empty \u2014 an empty preview with no placeholder is an unnamed button",'aria-disabled with data-disabled while disabled, and aria-disabled with data-readonly while readOnly \u2014 role="button" supports aria-disabled and supports aria-readonly in no ARIA version, so read-only is announced as the unavailable action it is (the Preview keeps its tab stop and refuses to open). The editor carries the real read-only semantics through the native readonly attribute on the textbox.',"aria-label or aria-labelledby on the Input/Textarea, which is required rather than optional (see namingRequirement). A mounted Label part satisfies it natively instead: its `for` resolves to the editor, which is a labelable control, so the platform computes the name with no ARIA at all.","aria-labelledby on the Preview while a Label is mounted, pointing at it, and withheld otherwise \u2014 a dangling IDREF is *no* name, and it would silently beat the content name the Preview would otherwise have. This is the one route by which an empty Editable with no placeholder is still a named button.",`aria-required="true" on the editor while required. The native required attribute is also set, but the editor has no form owner, so the browser never evaluates it and the constraint was invisible to both the platform and assistive technology \u2014 the real enforcement is the root's restore-on-blank. The editor is a textbox, whose role supports aria-required; the Preview is a role="button", which supports it in no version of ARIA, so it carries nothing.`,`aria-invalid="true" on the editor while invalid, and data-invalid on the root, the Preview and the editor. Same split and the same reason: textbox supports aria-invalid, and role="button" only inherits it under an ARIA 1.2 "deprecated on this role" annotation, which is exactly the wall FileUpload's dropzone hit.`],focusManagement:`Focus moves into editor when edit mode opens, back to the Preview when it closes by any route (submit, cancel, rejection) or to finalFocusEl's result. selectOnFocus decides whether caret starts selected or at end. Under activationMode="focus", return trip is guarded so root-caused focus doesn't immediately re-enter, which would loop forever. Guard covers finalFocusEl too \u2014 override returning Preview must not reopen editor.`,namingRequirement:"Preview needs a name: its own text while valued, placeholder when empty, mounted Label, or aria-label. Input/Textarea editor needs one too, from <label>, aria-label, or aria-labelledby \u2014 the placeholder does not count (disappears on content, editor opens on existing content nearly always). Triggers need names stating what they do \u2014 icon-only cancel/submit are two identical buttons to screen readers otherwise."},styling:{cssParts:["editable","label","preview","input","textarea","submit-trigger","cancel-trigger","edit-trigger"],dataAttributes:[...a,"data-state","data-empty","data-disabled","data-readonly","data-invalid",{name:"data-skdx-editable-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:[...i.map(e=>({...e,frameworks:["vue","webComponents"],exception:"imperative",frameworksReason:"Vue re-publishes the wrapped control's own methods from Input and Textarea with defineExpose, and the custom element reaches them through ElementInternals. React, Svelte and Angular hand the consumer the native control itself, which already carries them."})),...r.filter(e=>e.name==="setCustomValidity"),{name:"focus",signature:"(): void",description:"Moves keyboard focus to whichever part is showing \u2014 the editor while editing, the preview otherwise.",frameworks:["vue","webComponents"],exception:"element-handoff",frameworksReason:"Vue hides the Preview and editor inside the root component instance, and the custom element forwards focus() to them. React, Svelte and Angular hand the consumer the root element."}]};export{d as editableContract};
@@ -0,0 +1,3 @@
1
+ import type { ComponentContract } from './types.js';
2
+ /** Contract for the EmptyState block: a placeholder for a region with nothing to show. */
3
+ export declare const emptyStateContract: ComponentContract;
@@ -0,0 +1 @@
1
+ import{ROOT_DATA_ATTRIBUTES as e}from"./styling-hooks.js";var n={name:"EmptyState",purpose:"A placeholder for a region with nothing to show \u2014 no content yet, no results, first use, or disconnected \u2014 composing Heading and Text above a consumer-supplied icon and actions. Ships in the blocks package of each framework, not the core package.",props:[{name:"title",type:"string",required:!0,description:"Heading text naming the empty region, rendered into a derived Heading."},{name:"description",type:"string",required:!1,description:"Supporting copy rendered below the title, explaining why the region is empty. No description region renders when omitted."},{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. Both slot spellings are declared under `slots`.",description:"Decorative illustration or glyph rendered above the title, always aria-hidden. No icon region renders when omitted. A prop in React, Svelte, and Angular; Vue and Web Components use the `icon` slot."},{name:"actions",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:"Primary and secondary controls the consumer supplies, rendered below the content. No actions region renders when omitted. A prop in React, Svelte, and Angular; Vue and Web Components use the `actions` slot."},{name:"headingLevel",type:"1 | 2 | 3 | 4 | 5 | 6",defaultValue:"3",required:!1,description:"Outline level of the derived title heading, lowered or raised to fit the surrounding outline."},{name:"size",type:"'sm' | 'md' | 'lg' | (string & {})",required:!1,description:"Visual size rung, written to data-size on the root; the skin scales the icon, spacing and title by it."},{name:"align",type:"'center' | 'start' | (string & {})",defaultValue:"'center'",required:!1,description:"Text and content alignment rung, written to data-align on the root."}],events:[],slots:[{name:"default",description:"Extra content rendered between the description and the actions region."},{name:"icon",description:"The icon prop's content \u2014 a decorative illustration or glyph."},{name:"actions",description:"The actions prop's content \u2014 the region's primary and secondary controls."}],appearance:[{attribute:"data-size",values:["sm","md","lg"],stylesheet:"empty-state.css"},{attribute:"data-align",values:["start"],stylesheet:"empty-state.css"}],states:["default"],controlledUncontrolled:"Stateless \u2014 EmptyState holds no internal state.",formBehavior:"Not applicable \u2014 EmptyState participates in no form.",validationBehavior:"Not applicable \u2014 EmptyState carries no value and participates in no validation.",accessibility:{role:"generic (a <div>; the heading inside gives the region its name where the consumer needs one)",keyboard:[],ariaAttributes:["the icon region is aria-hidden so the heading alone carries the meaning","no aria attribute is written on the root itself \u2014 it is a generic container, not a landmark"],focusManagement:"Nothing inside the block is focusable except the consumer-supplied actions."},styling:{cssParts:["empty-state","icon","title","description","content","actions"],dataAttributes:[...e,"data-size","data-align",{name:"data-skdx-empty-state-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{n as emptyStateContract};
@@ -0,0 +1,3 @@
1
+ import type { ComponentContract } from './types.js';
2
+ /** The Field contract: wraps any control and wires its label, description, and error text to it via DOM discovery. */
3
+ export declare const fieldContract: ComponentContract;
@@ -0,0 +1 @@
1
+ import{ROOT_DATA_ATTRIBUTES as e}from"./styling-hooks.js";var a={name:"Field",purpose:"Wraps one form control and wires its label, description, and error text to it \u2014 generating ids and setting aria-describedby, aria-invalid, and aria-labelledby on the control \u2014 so any control inside a Field satisfies WCAG 3.3.1 and 3.3.3 without consumer-written ARIA. Owns field-level validation: validate callback, change/blur/submit modes, server-error injection, and native constraint-validation fallback.",props:[{name:"validate",type:"(value: unknown) => string | string[] | null | undefined | Promise<string | string[] | null | undefined>",required:!1,description:"Custom validator returning one, several, or no error messages. May be async; superseded runs are discarded. Spelled `validate` in all five frameworks; the method is `checkValidity()` to avoid collision. **Property-only on `<skdx-field>`**: functions have no attribute form."},{name:"mode",type:"'change' | 'blur' | 'submit'",defaultValue:"'blur'",required:!1,description:"When validation first runs. Regardless of mode, a field that has already failed re-validates on every input so the error clears as soon as it is fixed."},{name:"errors",type:"string | string[]",required:!1,description:"Server-injected errors, always shown and listed before `validate` messages. Clearing the prop clears them. Unlike React Aria, keystroke alone does not clear them \u2014 a server error states a fact the client cannot recheck, so dropping it on input would silently hide an unsolved problem. A `reset()` clears them until the next render, since the prop is declarative."},{name:"value",type:"unknown",required:!1,description:"Value handed to `validate`. Omit to read the discovered control's `checked` (checkbox/radio) or `value` property. **Property-only on `<skdx-field>`**: values are rarely strings and don't serialize across the attribute boundary."},{name:"name",type:"string",required:!1,description:"Field name, used as the fallback link text in a Form's ErrorSummary."},{name:"required",type:"boolean",required:!1,description:'Whether an answer is mandatory. Set as the native `required` attribute on labelable controls, `aria-required="true"` on groups and widget-role elements. Render a RequiredIndicator inside the Label; its text joins the accessible name so the requirement is announced. No `data-required` hook \u2014 `[required]` and `[aria-required="true"]` are already selectors.'},{name:"disabled",type:"boolean",required:!1,description:'Whether the field is unavailable. Set as the native `disabled` attribute where available, `aria-disabled="true"` otherwise (widgets stay focusable). Mirrored as `data-disabled` on the Field and control. Both withdrawn only when the Field wrote them, so a consumer-set `disabled` survives untouched.'},{name:"getCharacterCountMessage",type:"(remaining: number) => string",required:!1,description:'Words all character-count copy: rendered count, announced pause message, and over-limit error. Negative remaining means over the limit. One prop for all three to keep announced and rendered counts in sync. Defaults to GOV.UK wording, e.g. "You have 12 characters remaining". **Property-only on `<skdx-field>`**: functions have no attribute form.'},{name:"invalidMessage",type:"string",required:!1,description:'Fallback message when the control fails native constraint validation but reports no message (jsdom, some browsers leave validationMessage empty). Browser messages are already localized; this one needs translating. Defaults to "This field is invalid.".'},{name:"validationDebounceTime",type:"number",defaultValue:"0",required:!1,description:"Milliseconds `mode: 'change'` waits after the last keystroke before running `validate`. Only change mode debounces; blur/submit re-validate already-failed fields undebounced. A focusout cancels pending runs and validates immediately, so blur still answers at once."},{name:"label",type:"string",required:!1,description:"Label text, which derives a Label part with RequiredIndicator inside it before the control. No prop, no element \u2014 labels are opt-in consumer text. A consumer-authored Label takes precedence, so both recipe and hand-composed anatomy work in the same Field."},{name:"description",type:"string",required:!1,description:"Help text, which derives a Description part after the control and adds its id to `aria-describedby`. No prop, no element \u2014 consumer-authored Description takes precedence."},{name:"density",type:"'compact' | (string & {})",required:!1,description:"Vertical rhythm rung, written to data-density on the root; the data-density attribute may be set directly instead."}],events:[{name:"validity-change",description:"Fires whenever the field's validity or interaction state changes. Bubbles, so Form's ErrorSummary can re-scan. `validity` is the control's live `ValidityState` (or null if none), letting consumers word error messages per constraint or style on which constraint failed.",detail:"{ valid: boolean; errors: string[]; touched: boolean; dirty: boolean; filled: boolean; count: number; validity: ValidityState | null }"}],parts:[{name:"Label",description:"The field's label. Renders a `<label>` with `for` pointing to the control, or `<legend>` in Fieldset mode (groups get `aria-labelledby` instead). Double-click focuses the control instead of selecting text."},{name:"Description",description:"Supplementary help text. Its id joins the control's `aria-describedby` so it is announced with the control.",props:[{name:"as",type:"PolymorphicTag",defaultValue:"'span'",required:!1,frameworks:["react","vue","svelte","webComponents"],exception:"as-directive",frameworksReason:"Angular uses an attribute directive on the consumer's element \u2014 `<section skdx-ng-card>` \u2014 its idiomatic syntax. Eleven such directives predate this pattern.",description:"Element name to render instead of the default <span>, from the closed allowlist in POLYMORPHIC_TAGS. Tag name only, never a component \u2014 the list is closed because Lit needs a static-html literal per tag. React additionally reaches this through asChild, which wins when both are set."}]},{name:"Error",description:"The field's error text. Renders nothing while the field is valid; when it renders, its generated id joins the control's `aria-describedby` and the control gains `aria-invalid=\"true\"`. Renders current messages when given no children of its own. Children are content, not a render function; reach error details through the `validity-change` event's `ValidityState` instead.",props:[{name:"as",type:"PolymorphicTag",defaultValue:"'span'",required:!1,frameworks:["react","vue","svelte","webComponents"],exception:"as-directive",frameworksReason:"Angular uses an attribute directive on the consumer's element \u2014 `<section skdx-ng-card>` \u2014 its idiomatic syntax. Eleven such directives predate this pattern.",description:"Element name to render instead of the default <span>, from the closed allowlist in POLYMORPHIC_TAGS. Tag name only, never a component \u2014 the list is closed because Lit needs a static-html literal per tag. React additionally reaches this through asChild, which wins when both are set."}]},{name:"CharacterCount",description:"A running character count \u2014 GOV.UK's pattern, works for Textarea and TextField alike. maxLength is a soft limit and is deliberately not the control's native maxlength, which truncates silently; exceeding it makes the Field invalid (data-invalid, aria-invalid on the control, a message in Error, blocked submit) and adds data-over-limit here and on the Field. Count is announced one typing pause (1000ms) after the last keystroke, not continuously. Pass your own copy to override generated text.\n\n**Primitives-only in all five packages; the Field root's recipe never derives one.** maxLength is consumer-provided, so `maxLength` and `threshold` are declared on this part and never on the Field root.",props:[{name:"maxLength",type:"number",required:!0,description:"The soft limit the count counts down to."},{name:"threshold",type:"number",defaultValue:"0",required:!1,description:"Percentage of maxLength before the count renders or announces."}]},{name:"RequiredIndicator",description:"The \"mandatory\" marker, rendered *inside* the Label while Field is `required`. Its placement matters: inside the label means its text joins the control's accessible name so the requirement is announced. Deliberately not `aria-hidden` \u2014 hiding it leaves it visible to users who don't need it announced and silent for those who do. Defaults to `*`; pass words for more explicit marking."},{name:"Fieldset",description:'A Field rendering `<fieldset>` with Label in `<legend>` \u2014 the grouping radio/checkbox groups need, since `<label for>` cannot reference `[role="radiogroup"]`; the group gets `aria-labelledby` instead. Same props, same validation model and states as Field root.\n\n**Public and headless in all five packages, deliberately not a recipe.** Field root takes `label`/`description` and derives the parts; Fieldset derives nothing. It is the advanced path \u2014 the consumer composes Label, controls and Error inside it. A recipe Field can sit inside a hand-composed Fieldset.',props:[{name:"validate",type:"(value: unknown) => string | string[] | null | undefined | Promise<string | string[] | null | undefined>",required:!1,description:'The group\'s validator, same shape and async handling as the root\'s. Spelled on Fieldset rather than inherited because group rules are those no single control can state \u2014 "pick at least one", "end date must not precede start". Named `validate` so the method is `checkValidity()`, avoiding collision. **Property-only on `<skdx-fieldset>`** \u2014 functions have no attribute form.'},{name:"mode",type:"'change' | 'blur' | 'submit'",defaultValue:"'blur'",required:!1,description:"When validation first runs for the group. Groups that have failed re-validate on every input regardless of mode."},{name:"errors",type:"string | string[]",required:!1,description:"Server-injected errors for the group, always shown and listed before `validate` messages. Clearing the prop clears them."},{name:"name",type:"string",required:!1,description:"Group name, fallback link text in Form's ErrorSummary when the group renders no error."},{name:"invalidMessage",type:"string",required:!1,description:'Fallback message when the group control fails native constraint validation but reports no message. Browser messages always win \u2014 they are already localized. Defaults to "This field is invalid.".'},{name:"value",type:"unknown",required:!1,description:"Value handed to the group's `validate`. Omit to read the group control's value \u2014 for a radiogroup or checkbox group, whatever its form-participation input would submit."},{name:"required",type:"boolean",required:!1,description:'Whether an answer is mandatory for the group. Groups are always `aria-required="true"` since `[role="radiogroup"]` has no native `required`.'},{name:"disabled",type:"boolean",required:!1,description:"Whether the group is unavailable. Set as the native `disabled` attribute on the rendered `<fieldset>`, which cascades to every native control it contains. Mirrored as `data-disabled` on the Fieldset root."},{name:"getCharacterCountMessage",type:"(remaining: number) => string",required:!1,description:"Words the character-count copy for the group, exactly as on the Field root. Declared on the Fieldset too because dropping it would put announced and rendered counts in different languages."},{name:"validationDebounceTime",type:"number",defaultValue:"0",required:!1,description:"Milliseconds `mode: 'change'` waits after the last input in the group before running `validate`. Group validators receive the whole answer set, so in change mode they do real work \u2014 cross-field comparisons, lookups \u2014 on every keystroke. A focusout cancels pending runs and validates immediately; already-failed groups re-validate undebounced."},{name:"density",type:"'compact' | (string & {})",required:!1,description:"Vertical rhythm rung, written to data-density on the Fieldset; the data-density attribute may be set directly instead."}],methods:[{name:"checkValidity",signature:"(): Promise<boolean>",description:"Runs the group's validation now and resolves to whether it is valid. Form's `trySubmit()` calls this on every Fieldset and Field."},{name:"reset",signature:"(): void",description:"Clears the group's messages and its `touched`/`dirty` state."}]}],slots:[{name:"default",description:"A Label, the control, an optional Description, and an Error."}],appearance:[{attribute:"data-density",values:["compact"],stylesheet:"field.css"}],states:["valid","invalid","dirty","touched","filled","over-limit","required","disabled"],controlledUncontrolled:"The Field never owns the control's value; only validation state. Validation is uncontrolled; `errors` injects state from outside without claiming the rest.",formBehavior:"Not a form control itself \u2014 adds no value to submission and renders no input. Listens (capture-phase) for the host form's `submit` and prevents it while invalid or validation is pending. Async validators block the initial submit; the last pending Field to settle re-dispatches through `requestSubmit()` with `data-skdx-field-resubmit` on the form, and Fields answer from computed state instead of re-running.",validationBehavior:'Four merged sources in order: `errors` (server), the `validate` callback, the native `validationMessage` of the discovered control when `ValidityState` is invalid (so `required`/`type="email"`/`pattern` work without config), and CharacterCount over `maxLength`. Native message is *appended* to the first two, de-duplicated on exact string match, never substituted \u2014 a control that is both `required` and failing a custom rule must report both. `invalidMessage` is the fallback where the engine reports empty `validationMessage`. `mode` decides when the first run happens; `validationDebounceTime` controls `change` mode\'s wait after the last keystroke. After failure, every input re-validates undebounced. Newly-raised errors are announced assertively through the live announcer \u2014 silent on a failed submit only when an ErrorSummary renders.',accessibility:{role:"generic (a `<div>`, or a `<fieldset>` in group mode)",keyboard:[],ariaAttributes:["aria-describedby on the control \u2014 Description id and Error id while invalid",'aria-invalid="true" on the control while invalid',"aria-labelledby on the control in group mode, merging the legend id into whatever exists \u2014 the Field adds and withdraws its own id, never replacing it","required/aria-required and disabled/aria-disabled on the control \u2014 the native attribute where the control has one, the ARIA state where it does not","Every id the Field writes points at a rendered part. Label `for` and control `id` appear as a pair or not at all \u2014 so server renders with no control emit neither rather than a broken link.",'aria-errormessage is deliberately **not** used; Error is routed through `aria-describedby` instead. An `aria-errormessage` target is only exposed while the element carries `aria-invalid="true"` (a rendering-order race condition). Support is inconsistent; the Error is already in `aria-describedby`, where every screen reader reads it. Consumers who want it can set it on their own control \u2014 the Field merges into `aria-describedby` and never touches `aria-errormessage`.'],focusManagement:"Field moves no focus. Form ErrorSummary focuses failing fields, and for groups, the first control inside (GOV.UK rule).",namingRequirement:"Label supplies the accessible name via `for`/`id` (single control) or `aria-labelledby` (group). RequiredIndicator inside the Label is part of that name, making the requirement audible."},styling:{cssParts:["field","label","legend","required-indicator","description","error","character-count"],dataAttributes:[...e,"data-skdx-field","data-skdx-field-name","data-skdx-field-message","data-valid","data-invalid","data-touched","data-dirty","data-filled","data-over-limit","data-disabled","data-skdx-field-required-indicator","data-skdx-field-character-count","data-skdx-field-control","data-skdx-field-description","data-skdx-field-error","data-skdx-field-pending","data-skdx-field-resubmit",{name:"data-skdx-field-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.'},"data-orientation","data-density"],cssCustomProperties:[]},frameworkExtensions:[{framework:"angular",name:"control",type:"AbstractControl",description:'An Angular Reactive Forms control to mirror. Its `errors` are mapped through `errorMessages` and merged ahead of `validate` messages; `touched`/`dirty` are replayed as `input`/`focusout` events the engine listens for. Angular-only because Reactive Forms exists nowhere else \u2014 other frameworks reach this place via `errors` and `value` props. Mirroring is deliberately one-way and one-shot per transition \u2014 it can set `touched` and `dirty`, never clear them, because it works by replaying DOM events and there is no event that means "untouched". Clearing those flags is `reset()`\'s job: it withdraws `data-touched` and `data-dirty` and returns the field to mount state, so `markAsUntouched()` on the control pairs with a `reset()` call rather than travelling through the mirror.'},{framework:"angular",name:"errorMessages",type:"Record<string, string>",description:"Maps a Reactive Forms error key (`required`, `minlength`, \u2026) to the message shown for it; unmapped keys are shown verbatim. Meaningless without `control`, and Angular-only because the key space is Angular's validators', not this library's."}],publicMethods:[{name:"checkValidity",signature:"(): Promise<boolean>",description:"Runs validation now and resolves to whether the field is valid, reached through the component instance or element. Named for the platform's own method to avoid collision with the `validate` prop. Returns a promise since validators may be async; the `validity-change` event signals changes."},{name:"reset",signature:"(): void",description:"Resets the field to mount state: clears messages, withdraws `data-touched`/`data-dirty`, cancels pending runs, then re-derives `filled`, `count`, and over-limit error from the control. Async runs in flight are invalidated, not awaited. Clearing `errors` prop as part of reset is deliberate \u2014 it will re-apply on the next render since it is declarative."}]};export{a as fieldContract};
@@ -0,0 +1,3 @@
1
+ import type { ComponentContract } from './types.js';
2
+ /** The FileUpload contract: a controllable File[] list, filled via a native file picker or drag-and-drop. */
3
+ export declare const fileUploadContract: ComponentContract;
@@ -0,0 +1 @@
1
+ import{changeDetail as e}from"./change-reason.js";import{constraintValidationMethods as t,setCustomValidityMethod as i}from"./form-validity.js";import{ROOT_DATA_ATTRIBUTES as a}from"./styling-hooks.js";var s={name:"FileUpload",purpose:"A controllable File[] list. Dropzone and trigger open a visually-hidden native input; drag-and-drop applies the same accept pattern as the picker.",props:[{name:"value",type:"File[]",required:!1,description:"Selected files for controlled usage. PROPERTY-ONLY on <skdx-file-upload>: File[] cannot serialize through HTML attributes."},{name:"defaultValue",type:"File[]",defaultValue:"[]",required:!1,description:"Initial files for uncontrolled usage; form reset restores this list. PROPERTY-ONLY on <skdx-file-upload>: needed so uncontrolled mode has a seed and resets restore the initial state, not always empty."},{name:"accept",type:"string",required:!1,description:"Comma-separated file-type filter (extensions or MIME patterns), applied to picker and drag-and-drop alike."},{name:"multiple",type:"boolean",defaultValue:"false",required:!1,description:"Allow selecting/dropping more than one file; false replaces the existing file on new selection."},{name:"disabled",type:"boolean",defaultValue:"false",required:!1,description:"Disables the dropzone, trigger, and file input."},{name:"name",type:"string",required:!1,description:"Form field name. Every selected file is submitted as its own entry under it; without it nothing is submitted."},{name:"form",type:"string | undefined",required:!1,defaultValue:"undefined",description:"Form id when FileUpload lives outside its form. **Web Components:** property is `formId` (not `form`, which is read-only per spec)."},{name:"required",type:"boolean",defaultValue:"false",required:!1,description:"Marks the field required. valueMissing while no file is selected."},{name:"readOnly",type:"boolean",defaultValue:"false",required:!1,description:"Shows selection but blocks changes: dropzone refuses interaction, trigger is inert, ItemDelete disabled. Unlike disabled, the list stays focusable and readable \u2014 dropzone keeps tab stop and announces aria-disabled (not aria-readonly, unsupported on button role)."},{name:"invalid",type:"boolean",defaultValue:"false",required:!1,description:'External invalidity flag (server rejection, cross-field rules). Reflected as data-invalid on dropzone, ORed with derived invalidity (required with no files). Not aria-invalid\u2014role="button" inherits and deprecates it; see ariaAttributes for accessible signalling.'},{name:"maxFiles",type:"number",required:!1,description:"Most files the list may hold. Files past the cap are rejected with `too-many-files` instead of being added. Ignored while `multiple` is false, which caps the list at 1 anyway."},{name:"maxFileSize",type:"number",required:!1,description:"Largest accepted file size in bytes; a bigger file is rejected with `file-too-large`."},{name:"minFileSize",type:"number",required:!1,description:"Smallest accepted file size in bytes; a smaller file is rejected with `file-too-small`."},{name:"removeLabel",type:"(fileName: string) => string",defaultValue:"(fileName) => `Remove ${fileName}`",required:!1,description:"Words every ItemDelete's accessible name from the name of the file it removes. Declared once on the root rather than per row so the wording \u2014 and its translation \u2014 lives in one place; a consumer's own aria-label on a delete button still wins over it."},{name:"validator",type:"(file: File) => string[] | null | undefined",required:!1,description:"Per-file check run after the built-in ones. Return error codes to reject the file, or null/undefined/[] to accept it. Codes are opaque strings, merged into the same `file-reject` errors array as the built-in codes. PROPERTY-ONLY on <skdx-file-upload>: a function cannot round-trip through an HTML attribute."},{name:"directory",type:"boolean",defaultValue:"false",required:!1,description:"Lets the picker select a whole directory, forwarded to the hidden input as `webkitdirectory`. Named for the capability rather than for the attribute, because the attribute is prefixed and specified nowhere: it is supported in Chromium, Firefox and Safari, and a browser without it simply opens an ordinary file picker, so this is browser-dependent by construction. Every file in the chosen directory arrives through the normal validation pipeline, so accept and the size bounds still apply."},{name:"capture",type:"'user' | 'environment'",required:!1,description:"'user' (front camera) or 'environment' (rear). Mobile only; desktop falls back to file picker."},{name:"preventDocumentDrop",type:"boolean",defaultValue:"true",required:!1,description:'Suppress browser open-on-drop outside mounted dropzones. Enabled by default (misses cause destructive navigation). Uses document dragover+drop listeners, exempting `[data-part="dropzone"]`.'},{name:"showList",type:"boolean",defaultValue:"true",required:!1,description:"Whether the derived anatomy includes an ItemGroup listing the selected files. Ignored under hand composition."},{name:"showPreview",type:"boolean",defaultValue:"false",required:!1,description:"Whether a derived Item's default row includes an ItemPreview. Ignored under hand composition, and by renderFile when supplied."},{name:"fileStatus",type:"(file: File) => { status?: FileUploadItemStatus; progress?: number } | undefined",required:!1,description:"Per-file upload state: keyed by File (not index). Surfaces as data-state/data-progress. Consumer owns transport and this callback. Ignored with hand composition."},{name:"renderFile",type:"(file: File) => React.ReactNode",required:!1,description:`Render row content. Route for accessible progress readout: compose role="progressbar" or aria-describedby text when status='uploading'.`},{name:"requiredMessage",type:"string",required:!1,description:"Override valueMissing message so it can be translated. Message is unreachable otherwise: Web Components hides it in a shadow root; others use visually-hidden inputs. Yields to consumer's setCustomValidity."}],events:[{name:"value-change",detail:e("File[]"),description:"Fires with the new file list whenever files are added or removed."},{name:"file-reject",description:"Fires once per rejected file before committed batch. ORDERING IS PART OF THE CONTRACT: every file-reject fires BEFORE the single value-change. Consumer retains rejections; no component state. Batch with all rejects fires no value-change.",detail:"{ file: File; errors: string[] }"}],parts:[{name:"Dropzone",description:'Drag-and-drop / click-to-browse target with role="button", data-dragging, data-disabled. Trigger is its *sibling*, not child.',props:[{name:"disableClick",type:"boolean",defaultValue:"false",required:!1,description:"Suppresses the dropzone's own click-to-open behaviour, leaving drag-and-drop and Enter/Space activation untouched. For layouts where a sibling Trigger is the only thing that should open the picker, so a stray click on the surrounding drop surface does nothing."}]},{name:"Label",description:'Names the Dropzone, which points aria-labelledby at it while it is mounted. The Dropzone is a role="button" and so takes its name from its own content too \u2014 this part is for the layouts where the visible label sits outside the drop surface. Rendered as a span rather than a <label>, which would associate itself with the hidden file input instead of the element carrying the button role.'},{name:"ItemGroup",description:"The list wrapper the Item rows sit in. Pure structure \u2014 it renders no content of its own and reads no state \u2014 so a file list can be laid out as a list rather than as a run of siblings, and so the skin has one element to hang the column gap on. Emits the `item-group` part."},{name:"Item",description:"A single file's row, addressed by the `File` it shows. Consumer owns per-file status (data-state/data-progress). Publishes file to nested parts.",props:[{name:"file",type:"File",required:!0,description:"File this row shows; stable identity for nested parts. Compared by identity, not name. PROPERTY-ONLY on <skdx-file-upload-item>."},{name:"status",type:"'idle' | 'uploading' | 'complete' | 'error'",defaultValue:"'idle'",required:!1,description:"This file's upload status, set by the consumer that owns the transport. Reflected as `data-state` \u2014 the attribute a component emits its own lifecycle on; `data-status` is the separate severity scale other families expose as a prop."},{name:"progress",type:"number",required:!1,description:'Upload progress 0-100, consumer-set. Reflected as `data-progress`. STYLING HOOK AND NOTHING ELSE: when status="uploading", also provide role="progressbar" or aria-describedby for a11y.'}]},{name:"ItemName",description:"The file's name as readable text, taken from the enclosing Item's file. Content rather than decoration: the name is the only thing that distinguishes one row from the next, so it has to be text in the accessibility tree and not a background image or a `::before`. Children override it, for the layouts that truncate or highlight the name themselves; with no children it renders `file.name`."},{name:"ItemSizeText",description:"The file's size as readable text \u2014 `999B`, `1.5kB`, `1.2MB` \u2014 taken from the enclosing Item's file. A raw `File.size` is a byte count, which tells a reader nothing and is read out digit by digit by a screen reader, so this part formats it through Intl.NumberFormat's unit style: the decimal separator, the grouping and the unit abbreviation all come from the viewer's locale. `formatFileSize` in @skdx/shared is the written-down version the five copies are held to. Children override it."},{name:"ItemPreview",description:"The slot for a thumbnail or a file-type icon, in the enclosing Item. A container and nothing else: it renders no image itself, because the only way to show one is an object URL, and an object URL that a component creates is one it also has to revoke \u2014 a lifetime this component cannot know. Compose an <img> whose src the consumer owns, and give it the alt text (usually empty, since ItemName already carries the name)."},{name:"ItemDelete",description:"Delete button, named by file and removeLabel. Moves focus to next/previous delete button before removing its row, or to Dropzone when empty.",props:[{name:"file",type:"File",required:!1,defaultValue:"the enclosing Item's file",description:"File to remove, compared by identity. Defaults to enclosing Item's file. Optional; PROPERTY-ONLY on <skdx-file-upload-item-delete>."}]},{name:"Clear",description:"The button that empties the whole list in one action, firing a single value-change with an empty list and announcing how many files went. Disabled while the list is already empty, and while the root is disabled or readOnly \u2014 the same three conditions ItemDelete answers to. A common need for any multi-file upload; it is a part rather than a root prop because where the control sits, and whether it exists at all, is a layout decision."}],slots:[{name:"default",description:"FileUploadLabel/Dropzone/Trigger/Input plus FileUploadItem rows."},{name:"item",description:"A single selected file's row."}],states:["default","dragging","disabled","readonly","invalid","idle","uploading","complete","error"],controlledUncontrolled:"Supports both: value + onValueChange (controlled) or defaultValue (uncontrolled).",formBehavior:'Form-associated: each file is a separate form entry, so formData.getAll(name) returns the File objects. Empty is valueMissing when required, surfaced on Dropzone data-invalid and aria-describedby description. Form reset restores the files the component was created with (defaultValue) and fires value-change; does not simply clear the list. React/Vue/Svelte/Angular use two visually-hidden controls: one carries value via DataTransfer, another carries required. Split because input.files only binds imperatively. Neither may be type="hidden" or readonly (bars constraint validation). Web Components uses shadow root input and ElementInternals.',validationBehavior:"required is native constraint validation (checkValidity/reportValidity). Selection-time validation is separate, never blocks: files checked against accept/maxFileSize/minFileSize/maxFiles/validator callback; failures drop with file-reject carrying codes (file-invalid-type | file-too-large | file-too-small | too-many-files). Consumer renders rejections; Field owns persistent message.",accessibility:{role:"button (FileUploadDropzone)",keyboard:[{key:"Enter/Space",behavior:"Opens the native file picker when the dropzone is focused."}],ariaAttributes:['aria-disabled on dropzone when disabled or readOnly (role="button" unsupports aria-readonly).',"aria-labelledby on dropzone, pointing at Label part when mounted.","aria-label on each ItemDelete, from removeLabel and file name.",'aria-describedby on the dropzone while required, pointing at visually-hidden description: "Required" when satisfied, "Required. No file selected" when not. This is the sole accessible signal for both required-ness and invalidity. aria-required is global in no version of ARIA; aria-invalid is global but deprecated on this role in ARIA 1.2.',"Live announcements: batch additions/rejections, and each removal."],namingRequirement:'Dropzone MUST have an accessible name (only visible part to a11y). Role="button" takes name from content or Label part. Each ItemDelete named from its file. Tests enforce both.',focusManagement:"Dropzone is keyboard-activatable button; hidden input never focused. Delete moves focus to next/prev ItemDelete, then Dropzone, before row unmounts."},styling:{cssParts:["file-upload","dropzone","label","trigger","item","delete","input","item-delete","item-group","item-name","item-size","item-preview","clear"],dataAttributes:[...a,"data-disabled","data-readonly","data-dragging","data-invalid","data-state","data-progress",{name:"data-skdx-file-upload-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,i,{name:"addFiles",signature:"(files: FileList | File[]): void",description:"Route external sources (paste, drag library, camera, test) through validation and announcement pipeline. NOT a paste listener: component paste handler would compete with all others on the page."}]};export{s as fileUploadContract};
@@ -0,0 +1,3 @@
1
+ import type { ComponentContract } from './types.js';
2
+ /** Contract for the FilterBar block: a search field, filter controls, applied filters and a clear action. */
3
+ export declare const filterBarContract: ComponentContract;
@@ -0,0 +1 @@
1
+ import{ROOT_DATA_ATTRIBUTES as e}from"./styling-hooks.js";var r={name:"FilterBar",purpose:"The filtering surface above a table, list, card grid or report, composing TextField, TagGroup and Button. Renders a search field, the consumer's filter controls, the applied filters as removable tags, and a clear action. Owns only interaction and presentation; the application owns query state, URLs and requests. Ships in the blocks package of each framework, not the core package.",props:[{name:"label",type:"string",defaultValue:"'Filters'",required:!1,description:"Accessible name of the root region, written to aria-label."},{name:"searchLabel",type:"string",required:!1,description:"Accessible name of the search field. No search region renders when omitted."},{name:"searchPlaceholder",type:"string",required:!1,description:"Placeholder shown in the empty search field."},{name:"searchValue",type:"string",required:!1,description:"Current search text, for controlled usage."},{name:"defaultSearchValue",type:"string",defaultValue:"''",required:!1,description:"Initial search text, for uncontrolled usage."},{name:"clearSearchLabel",type:"string",defaultValue:"'Clear search'",required:!1,description:"Accessible name of the search field's clear button."},{name:"activeFilters",type:"ReadonlyArray<{ id: string; label: string }>",required:!1,description:"The applied filters, in display order, rendered as removable tags. No active region renders when omitted or empty."},{name:"activeFiltersLabel",type:"string",defaultValue:"'Active filters'",required:!1,description:"Accessible name of the active-filters tag list."},{name:"clearLabel",type:"string",defaultValue:"'Clear filters'",required:!1,description:"Text rendered on the clear-filters button."},{name:"actions",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:'Controls rendered at the end of the bar, such as a "Save view" button. No actions region renders when omitted. A prop in React, Svelte, and Angular; Vue and Web Components use the `actions` slot.'}],events:[{name:"search-value-change",detail:"{ value: string }",description:"Fires with the new text whenever the search field changes, controlled or not."},{name:"remove-filter",detail:"{ id: string; label: string }",description:"Fires with the removed filter when its tag's remove control is activated."},{name:"clear",detail:"void",description:"Fires when the clear-filters button is activated. Providing a listener renders the button while filters are active."}],slots:[{name:"default",description:"The consumer's filter controls, laid out in the filters region."},{name:"actions",description:"The actions prop's content, at the end of the bar."}],states:["default"],controlledUncontrolled:"The search text works controlled through searchValue or uncontrolled through defaultSearchValue; the active filters and their removal are always controlled by the consumer.",formBehavior:"Not applicable \u2014 FilterBar participates in no form.",validationBehavior:"Not applicable \u2014 FilterBar carries no value of its own and participates in no validation.",accessibility:{role:'generic (a <div> named by label through aria-label; the derived search field is a type="search" input named by searchLabel)',keyboard:[{key:"ArrowLeft/ArrowRight/Home/End",behavior:"Moves between tags in the derived TagGroup, which is one Tab stop."},{key:"Delete/Backspace",behavior:"Removes the focused tag's filter, moving focus to its neighbour."}],ariaAttributes:["aria-label on the root names the region from label","the derived search input carries aria-label from searchLabel","the derived TagGroup is named by activeFiltersLabel through aria-label"],focusManagement:"Focus stays where the user put it; removing the last tag moves focus per the composed TagGroup's own removal behaviour."},styling:{cssParts:["filter-bar","search","filters","actions","active","tags","clear"],dataAttributes:[...e,{name:"data-skdx-filter-bar-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{r as filterBarContract};
@@ -0,0 +1,3 @@
1
+ import type { ComponentContract } from './types.js';
2
+ /** The FloatingPanel contract: a non-modal window the user can drag, resize, and minimize/maximize. */
3
+ export declare const floatingPanelContract: ComponentContract;
@@ -0,0 +1 @@
1
+ import{dismissalEvents as t,forceMountProp as a,openChangeCompleteEvent as i,portalPart as e}from"./overlay-parts.js";import{PART_DATA_ATTRIBUTES as r}from"./styling-hooks.js";var s={name:"FloatingPanel",purpose:"A non-modal window: draggable by its header, resizable from eight grips, switchable between default/minimized/maximized stages, and clamped to a boundary or viewport. Position and size are published as CSS custom properties, so the consumer owns the painting.",props:[{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:"position",type:"{ x: number; y: number }",required:!1,description:"Controlled top-left corner in CSS pixels, measured from the boundary's top-left. Pair with position-change or the panel will refuse to move."},{name:"defaultPosition",type:"{ x: number; y: number }",defaultValue:"{ x: 0, y: 0 }",required:!1,description:"Starting top-left corner for uncontrolled usage, measured from the boundary."},{name:"size",type:"{ width: number; height: number }",required:!1,description:"Controlled box in CSS pixels. Pair with size-change or the panel will refuse to resize."},{name:"defaultSize",type:"{ width: number; height: number }",defaultValue:"{ width: 320, height: 240 }",required:!1,description:"Starting box for uncontrolled usage."},{name:"minSize",type:"{ width: number; height: number }",defaultValue:"{ width: 160, height: 120 }",required:!1,description:"Smallest box the panel can be resized to. Every resize is clamped to it."},{name:"maxSize",type:"{ width: number; height: number }",defaultValue:"{ width: Infinity, height: Infinity }",required:!1,description:"Largest box the panel can be resized to."},{name:"boundary",type:"Element | null",defaultValue:"null",required:!1,description:"Element the panel may not be dragged or resized out of. Position is measured from this element's top-left corner, and the panel follows that corner as the page scrolls. The viewport constrains the panel when omitted."},{name:"stage",type:"'default' | 'minimized' | 'maximized'",required:!1,description:"Controlled window state. Pair with stage-change. 'default' uses the stored position and size, 'maximized' fills the boundary, 'minimized' collapses to header height."},{name:"defaultStage",type:"'default' | 'minimized' | 'maximized'",defaultValue:"'default'",required:!1,description:"Starting window state, for uncontrolled usage."},{name:"draggable",type:"boolean",defaultValue:"true",required:!1,description:"Whether the header can move the panel. Setting false drops the move cursor."},{name:"resizable",type:"boolean",defaultValue:"true",required:!1,description:"Whether resize grips do anything. Setting false makes every ResizeTrigger inert and non-focusable."},{name:"step",type:"number",defaultValue:"10",required:!1,description:"How far one arrow key moves or resizes the panel, in pixels. Shift+arrow uses ten times this value."},{name:"disabled",type:"boolean",defaultValue:"false",required:!1,description:"Freezes the geometry: drag, resize, and stage changes are refused. Opening and closing still work."},{name:"getGestureAnnouncement",type:"(gesture: 'move' | 'resize', detail: { position: { x: number; y: number }; size: { width: number; height: number } }) => string",required:!1,description:"Words the live-region message announced once per drag or resize. Numbers arrive rounded to whole CSS pixels. Return an empty string to announce nothing."},{name:"title",type:"string",required:!1,description:"The panel's heading, rendered in the derived Header. Omitting it withholds Content's aria-labelledby \u2014 a dangling IDREF is not a weak name but no name. Name a title-less panel with aria-label on the recipe instead."},{name:"stages",type:"Array<{ stage: 'default' | 'minimized' | 'maximized'; label: string }>",defaultValue:"[]",required:!1,description:"The window controls the derived Header renders \u2014 one StageTrigger per entry, each switching the panel to its stage. Empty by default gives no controls. The label is required rather than derived from the stage name."},{name:"dismissible",type:"boolean",defaultValue:"true",required:!1,description:"Whether the derived Header renders a CloseTrigger. False withholds it for a panel whose only exit is the consumer's own control."}],events:[{name:"open-change",detail:"boolean",description:"Fired with the new open state whenever the panel opens or closes, controlled or not."},i("panel"),{name:"position-change",description:"Fired with the clamped position on every drag frame and every arrow-key nudge. Throttle if the work is expensive.",detail:"{ x: number; y: number }"},{name:"size-change",description:"Fired with the clamped size on every resize frame and every arrow-key nudge.",detail:"{ width: number; height: number }"},{name:"position-commit",description:"Fired once when a gesture settles, carrying the same position position-change last reported. This is the event to persist geometry: position-change fires on every drag frame and every arrow-key nudge. A resize also fires this because a grip pulling the west or north edge relocates the panel's origin.",detail:"{ x: number; y: number }"},{name:"size-commit",description:"Fired once when a resize gesture settles. The settled counterpart to size-change. A move never fires it \u2014 dragging the header changes no dimension.",detail:"{ width: number; height: number }"},{name:"stage-change",description:"Fired with the new stage whenever a StageTrigger is pressed.",detail:"'default' | 'minimized' | 'maximized'"},...t("panel")],parts:[{name:"Trigger",description:'The button that opens the panel. Carries aria-haspopup="dialog", aria-expanded, and aria-controls.'},{...e,description:`${e.description} Shipped by React, Vue, Svelte and Web Components. Angular uses the [skdxPortal] directive instead. In Web Components the part exists but force-mount does not: its parts never unmount, they hide with the hidden attribute.`},{name:"Content",description:'The movable surface: role="dialog" with aria-modal="false", named by Title, publishing current geometry as --skdx-floating-panel-x/y/width/height. Being non-modal, it reports focus leaving without closing.',props:[a]},{name:"Header",description:"The drag handle. Pointer-drags move the panel; arrow keys nudge it by step (ten times with Shift), clamped to the boundary. The final position is announced once the gesture ends."},{name:"Title",description:"The panel's accessible name, referenced by Content's aria-labelledby."},{name:"CloseTrigger",description:"A button that closes the panel, for a close affordance inside the header."},{name:"ResizeTrigger",description:'One edge or corner grip, rendered as role="separator" with aria-valuenow/valuemin/valuemax describing the dimension it pulls \u2014 width for east/west and corners, height for north/south \u2014 plus aria-orientation on the four edges. Arrow keys resize by step, clamped to minSize, maxSize, and the boundary.',props:[{name:"direction",type:"'n' | 's' | 'e' | 'w' | 'ne' | 'nw' | 'se' | 'sw'",required:!0,description:"Which edge or corner this grip pulls; corners move two edges at once. There is no default \u2014 a grip that does not say what it resizes cannot resize anything."}]},{name:"StageTrigger",description:"A minimize/maximize/restore button carrying aria-pressed. Pressing it while already in that stage restores 'default', making one button both minimize and restore.",props:[{name:"stage",type:"'default' | 'minimized' | 'maximized'",required:!0,description:"The stage this button switches to."}]}],slots:[{name:"trigger",description:"Trigger's content \u2014 the button that opens the panel."},{name:"default",description:"Content's body \u2014 typically a Header wrapping a Title, CloseTrigger and StageTriggers, the panel's own content, and the ResizeTrigger grips."}],states:["closed","open","dragging","resizing","default","minimized","maximized","disabled","on","off"],controlledUncontrolled:"Four independent controlled/uncontrolled axes \u2014 open, position, size, and stage \u2014 each starting from its default* prop and switching to controlled when the matching prop is passed. Passing a controlled value without its change event freezes that axis rather than fighting the consumer for it.",formBehavior:'Not applicable \u2014 FloatingPanel participates in no form; Trigger is type="button".',validationBehavior:"Not applicable \u2014 FloatingPanel collects no value.",accessibility:{role:'dialog (Content, aria-modal="false"), separator (ResizeTrigger)',keyboard:[{key:"Enter / Space (on Trigger)",behavior:"Toggles the panel: opens it when closed, closes it when open. Trigger is a disclosure button carrying aria-expanded, which APG requires to toggle rather than only open."},{key:"Arrow keys (on Header)",behavior:"Move the panel by step pixels, clamped to the boundary. The landing position is announced politely once movement stops."},{key:"Shift + Arrow keys (on Header)",behavior:"Move the panel by ten times step, for crossing a large boundary without holding a key down."},{key:"Arrow keys (on a ResizeTrigger)",behavior:"Resize the panel from that edge or corner by step pixels, clamped to minSize, maxSize, and the boundary. The landing size is announced politely once resizing stops."},{key:"Shift + Arrow keys (on a ResizeTrigger)",behavior:"Resize by ten times step."},{key:"Escape",behavior:"Requests close (cancelable via escape-key-down) and returns focus to Trigger."},{key:"Tab",behavior:"Moves through the panel and then out of it into the rest of the page \u2014 the panel is non-modal and traps nothing."}],ariaAttributes:['aria-haspopup="dialog", aria-expanded, and aria-controls on Trigger',`role="dialog" with aria-modal="false" on Content, whose id matches Trigger's aria-controls`,"aria-labelledby on Content pointing at Title",'role="separator" with aria-valuenow/aria-valuemin/aria-valuemax on each ResizeTrigger, describing the dimension it controls. aria-valuemax is the effective ceiling \u2014 min(maxSize, room left in boundary).',"aria-orientation on the four edge ResizeTriggers; corners omitted as they move two axes","aria-pressed on each StageTrigger reflecting whether the panel is in that stage","aria-disabled and data-disabled on every geometry trigger while disabled is set, never the native disabled attribute. A frozen trigger stays reachable and announced as operable-but-refusing.",'aria-keyshortcuts="ArrowUp ArrowDown ArrowLeft ArrowRight" on Header while draggable and each ResizeTrigger while resizable.'],focusManagement:"Focus is not trapped \u2014 the panel is non-modal and the page beneath stays reachable by Tab. Escape and CloseTrigger return focus to Trigger. Header is a tab stop while draggable; each ResizeTrigger while resizable, so a fixed-size panel does not spend eight stops on inert grips. disabled does not remove any: it freezes the geometry and is announced with aria-disabled.",namingRequirement:'Content must be named by a Title (or explicit aria-label). Header and every ResizeTrigger need their own aria-label when focusable: an unnamed "separator" tells the user nothing about what the arrow keys will do to it. Both are keyboard-operable controls, not decoration.'},styling:{cssParts:["trigger","content","header","title","close-trigger","resize-trigger","stage-trigger"],dataAttributes:[...r,"data-state","data-stage","data-dragging","data-resizing","data-direction","data-disabled",{name:"data-skdx-floating-panel-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-floating-panel-x","--skdx-floating-panel-y","--skdx-floating-panel-width","--skdx-floating-panel-height"]},publicMethods:[]};export{s as floatingPanelContract};
@@ -0,0 +1,3 @@
1
+ import type { ComponentContract } from './types.js';
2
+ /** Contract for the ForgotPasswordPage block: an email field that requests a reset link, replaced by a success alert. */
3
+ export declare const forgotPasswordPageContract: ComponentContract;
@@ -0,0 +1 @@
1
+ import{ROOT_DATA_ATTRIBUTES as e}from"./styling-hooks.js";var r={name:"ForgotPasswordPage",purpose:"A password-recovery block composing Heading, Text, Alert, Form, Field, TextField and Button. It asks for one address, reports it through a request-reset event, and swaps the whole form for a success alert once the consumer says the request was accepted. Ships in the blocks package of each framework, not the core package.",props:[{name:"title",type:"string",defaultValue:"'Reset your password'",required:!1,description:"Heading text, rendered into a derived <h1> that names the section."},{name:"description",type:"string",required:!1,description:"Supporting copy rendered into a derived Text below the title, explaining what the reset link does. No description region renders when omitted."},{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 request 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, so an accepted request cannot be sent twice by accident."},{name:"pending",type:"boolean",defaultValue:"false",required:!1,description:"Marks the request in flight, making the submit button busy and unusable while the email field stays editable, so the user can still correct a typo."},{name:"emailLabel",type:"string",defaultValue:"'Email'",required:!1,description:"Label of the email field the reset link is requested for."},{name:"submitLabel",type:"string",defaultValue:"'Send reset link'",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:"request-reset",detail:"{ email: string }",description:"Fires when the form is submitted with an address that passes native constraint validation, carrying that address. The native submit is prevented, so the consumer performs the request and then sets success or error."}],slots:[{name:"default",description:"Extra fields rendered inside the form, above the submit button."},{name:"footer",description:"Navigation below the form, such as a link back to the sign-in page."}],states:["default"],controlledUncontrolled:"Stateless apart from the address the native input holds; error, success and pending are always controlled by the consumer.",formBehavior:"The form is a core Form root with one required, natively validated email field; an invalid form reports through constraint validation and emits nothing. No form renders at all while success is set.",validationBehavior:'The email field is required and type="email", and 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 while the email field has focus (native form submission)."}],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 email field is labelled through the core Field, which wires aria-describedby and aria-invalid"],focusManagement:"Focus stays where the user put it; an accepted request announces the success Alert rather than moving focus."},styling:{cssParts:["forgot-password-page","panel","title","description","error","success","form","field","submit","footer"],dataAttributes:[...e,{name:"data-skdx-forgot-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-forgot-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 forgotPasswordPageContract};
@@ -0,0 +1,3 @@
1
+ /** The canonical form property rule: families with name for submission expose form for out-of-tree form association. */
2
+ /** Families that expose `form` for native form association. */
3
+ export declare const FORM_ASSOCIATED_FAMILIES: readonly ["AngleSlider", "Autocomplete", "Checkbox", "CheckboxCard", "CheckboxGroup", "Combobox", "DateField", "DatePicker", "FileUpload", "NumberField", "PinInput", "RadioCard", "RadioGroup", "Rating", "Select", "Slider", "Switch", "TagsInput", "TextField", "TextArea", "TimeField", "ToggleGroup", "Transfer", "TreeSelect"];
@@ -0,0 +1 @@
1
+ var e=["AngleSlider","Autocomplete","Checkbox","CheckboxCard","CheckboxGroup","Combobox","DateField","DatePicker","FileUpload","NumberField","PinInput","RadioCard","RadioGroup","Rating","Select","Slider","Switch","TagsInput","TextField","TextArea","TimeField","ToggleGroup","Transfer","TreeSelect"];export{e as FORM_ASSOCIATED_FAMILIES};
@@ -0,0 +1,3 @@
1
+ import type { ComponentContract } from './types.js';
2
+ /** Contract for the FormSection block: a titled group of fields inside a larger form. */
3
+ export declare const formSectionContract: ComponentContract;
@@ -0,0 +1 @@
1
+ import{ROOT_DATA_ATTRIBUTES as e}from"./styling-hooks.js";var o={name:"FormSection",purpose:"A titled group inside a larger form \u2014 a heading, supporting text, the group's fields and a footer for the group's own actions \u2014 composing Heading and Text around consumer-supplied fields. Composes with the core Form, Field, TextField, Select, Checkbox, Switch, RadioGroup and FileUpload untouched. Ships in the blocks package of each framework, not the core package.",props:[{name:"title",type:"string",required:!0,description:"Heading text naming the group, rendered into a derived Heading."},{name:"description",type:"string",required:!1,description:"Supporting copy rendered below the title, explaining the group's fields. No description region renders when omitted."},{name:"headingLevel",type:"1 | 2 | 3 | 4 | 5 | 6",defaultValue:"2",required:!1,description:"Outline level of the derived title heading, lowered or raised to fit the surrounding form outline."},{name:"actions",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:"Save, cancel or other controls rendered in a footer below the fields. No footer region renders when omitted. A prop in React, Svelte, and Angular; Vue and Web Components use the `actions` slot."},{name:"variant",type:"'bordered' | 'split' | (string & {})",required:!1,description:"Layout rung, written to data-variant on the root; bordered draws a bounded panel and split places the header beside the content on wide viewports."}],events:[],slots:[{name:"default",description:"The group's fields, rendered into the content region."},{name:"actions",description:"The actions prop's content \u2014 the group's own footer controls."}],appearance:[{attribute:"data-variant",values:["bordered","split"],stylesheet:"form-section.css"}],states:["default"],controlledUncontrolled:"Stateless \u2014 FormSection holds no internal state.",formBehavior:"Adds no form-state logic of its own; the fields the consumer places inside compose with the core Form, Field, TextField, Select, Checkbox, Switch, RadioGroup and FileUpload untouched.",validationBehavior:"Not applicable \u2014 FormSection carries no value and delegates validation to the fields it groups.",accessibility:{role:"region (native <section> named by its heading through aria-labelledby and described by its description)",keyboard:[],ariaAttributes:["aria-labelledby on the <section> points at the derived title heading","aria-describedby on the <section> points at the derived description, present only when one is given"],focusManagement:"Nothing inside the block is focusable except the consumer-supplied fields and actions."},styling:{cssParts:["form-section","header","title","description","content","footer"],dataAttributes:[...e,"data-variant",{name:"data-skdx-form-section-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{o as formSectionContract};
@@ -0,0 +1,7 @@
1
+ import type { PublicMethodContract } from './types.js';
2
+ /** The two constraint-validation methods every form-associated component exposes, matching HTMLInputElement's wording. */
3
+ export declare const constraintValidationMethods: PublicMethodContract[];
4
+ /** The third constraint-validation method, appended only by contracts that mirror a control's ValidityState. */
5
+ export declare const setCustomValidityMethod: PublicMethodContract;
6
+ /** The three constraint-validation methods for components where only the custom element publishes them, the other four exposing the native control instead. */
7
+ export declare const webComponentsValidationMethods: PublicMethodContract[];
@@ -0,0 +1 @@
1
+ var t=["webComponents"],o="The custom element reaches constraint validation through ElementInternals, which is a custom-element API. React, Vue, Svelte and Angular render a native control the consumer already holds a ref to and call these on it directly, so there is no wrapper method to contract.",a=e=>({...e,frameworks:t,frameworksReason:o,exception:"imperative"}),n=[{name:"checkValidity",signature:"(): boolean",description:"Returns whether the current value satisfies the constraints, firing an invalid event if not. Same contract as the native method."},{name:"reportValidity",signature:"(): boolean",description:"Same as checkValidity, but also shows the browser's validation message when the value is invalid."}],r={name:"setCustomValidity",signature:"(message: string): void",description:"Sets an externally-computed error on the wrapped native control, exactly like the native method: a non-empty message makes the control invalid (customError) and is what reportValidity() shows; '' clears it."},i=[...n,r].map(a);export{n as constraintValidationMethods,r as setCustomValidityMethod,i as webComponentsValidationMethods};
@@ -0,0 +1,3 @@
1
+ import type { ComponentContract } from './types.js';
2
+ /** The Form contract: a form root wired to the native Constraint Validation API with a styleable error system. */
3
+ export declare const formContract: ComponentContract;
@@ -0,0 +1 @@
1
+ import{ROOT_DATA_ATTRIBUTES as e}from"./styling-hooks.js";var r={name:"Form",purpose:"Form root wired to the native Constraint Validation API with a styleable error system and per-field snapshots. No custom validators \u2014 the consumer's inputs validate themselves.",props:[{name:"errors",type:"Record<string, string | string[]>",required:!1,description:"Server or cross-field errors, keyed by field `name`. Marks the field `aria-invalid` and clears on next `change`."},{name:"validationMode",type:"'submit' | 'blur' | 'change'",defaultValue:"'change'",required:!1,description:"When ValidityState refreshes and messages show: `change` (default) on change/blur, `blur` on blur only, `submit` on submit only."},{name:"validationBehavior",type:"'native' | 'aria'",defaultValue:"'native'",required:!1,description:"Whether validation blocks submit: `native` blocks it; `aria` lets it through with failing controls marked `aria-invalid`."},{name:"errorSummary",type:"string",required:!1,description:"Error summary heading copy; omit it to skip the summary part."},{name:"submitLabel",type:"string",required:!1,description:"Submit button label; omit it to skip the submit button part."},{name:"density",type:"'compact' | (string & {})",required:!1,description:"Vertical rhythm rung, written to data-density on the root; the data-density attribute may be set directly instead."}],events:[{name:"submit",detail:"void",description:"Fires only after validation passes, or under `validationBehavior: 'aria'` regardless."},{name:"reset",detail:"void",description:"Fires on native reset, clearing per-field ValidityState snapshots and server errors."},{name:"field-invalid",description:"Fires per failing field on submit, non-cancelable; lets a consumer react to blocked submit.",detail:"{ name: string; validity: ValiditySnapshot }"}],parts:[{name:"Field",description:"Groups Label, Control, and Message for one field; wires their ids together.",props:[{name:"name",type:"string",required:!0,description:"Field name; key for submit, ValidityState storage, and error summary link text."},{name:"label",type:"string",required:!1,description:"Label copy; derives a Label part and points control `aria-labelledby` to it."},{name:"message",type:"string",required:!1,description:"Catch-all message copy, shown when the field is invalid."}]},{name:"Control",description:"Wraps the control and wires `name`/`id` from Field, plus `aria-invalid` and `aria-describedby` on failure.",slots:[{name:"default",description:"One control element \u2014 a native `<input>`/`<select>`/`<textarea>` or a component wrapping one."}]},{name:"Message",description:"Validation message for one Field; shown only while its condition matches.",props:[{name:"match",type:"keyof ValidityState",required:!1,description:"ValidityState flag this message shows for; omit for the catch-all."},{name:"forceMatch",type:"boolean",defaultValue:"false",required:!1,description:"Show message regardless of native validity; for errors the browser cannot derive."}]},{name:"ErrorSummary",lightDom:!0,description:'Error summary with `role="alert"` and `tabindex="-1"`, listing links to failing fields. **It must have an accessible name** \u2014 heading or `aria-label` \u2014 since it takes focus on arrival.',props:[{name:"autoFocus",type:"boolean",defaultValue:"true",required:!1,description:"Focus the summary when it appears; turn off if your routing already moves focus."}]}],slots:[{name:"default",description:"FormField(s) plus a FormSubmit."}],appearance:[{attribute:"data-density",values:["compact"],stylesheet:"form.css"}],states:["default"],controlledUncontrolled:"Not applicable \u2014 Form owns no external controlled state, only internal validity snapshots.",formBehavior:"On submit, checkValidity() runs on every field; failure blocks submit and fires `field-invalid` per field. Fields re-validate on blur/change per `validationMode`. Under `validationBehavior: 'aria'`, submit fires regardless with snapshots taken first.",validationBehavior:"Delegates to native constraint validation on consumer inputs, plus the `errors` map for browser-opaque failures.",accessibility:{role:"generic (native <form>)",keyboard:[],ariaAttributes:["FormControl injects aria-invalid/aria-describedby onto its child once that field fails validation"],focusManagement:"A blocked submit moves focus to the ErrorSummary or the first failing control.",namingRequirement:"The ErrorSummary must have an accessible name \u2014 heading or `aria-label` \u2014 since it takes focus."},styling:{cssParts:["form","field","label","message","submit","control","error-summary","error-summary-title","error-summary-list","error-summary-link"],dataAttributes:[...e,"data-skdx-error-summary","data-skdx-form-field","data-skdx-form-message","data-skdx-field-name","data-density",{name:"data-skdx-form-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-form-field-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:[{name:"validate",signature:"(): Promise<boolean>",description:"Runs full form validation without short-circuiting; resolves to whether it passed."}]};export{r as formContract};
@@ -0,0 +1,3 @@
1
+ import type { ComponentContract } from './types.js';
2
+ /** The Heading contract: an h1–h6 whose outline level and visual size are decoupled. */
3
+ export declare const headingContract: ComponentContract;
@@ -0,0 +1 @@
1
+ import{ROOT_DATA_ATTRIBUTES as e}from"./styling-hooks.js";var a={name:"Heading",purpose:"An <h1>\u2013<h6> whose outline level and visual size are separate\u2014level is the required `as` prop, size is the `size` prop, written to the data-size attribute the skin reads (or set the attribute directly). visuallyHidden composes .skdx-visually-hidden for headings screen readers need but the layout has no room for.",props:[{name:"as",type:"'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6'",required:!0,description:"Which heading element to render. Required with no default: the outline level belongs to the document this library does not own, so a default would be a guess. Skipping a rung is a navigation defect for anyone moving by heading."},{name:"visuallyHidden",type:"boolean",defaultValue:"false",required:!1,description:"Hides the heading visually while keeping it in the accessibility tree, composing the .skdx-visually-hidden utility. Use for headings that name regions for screen readers where visual design already names them by position."},{name:"size",type:"'sm' | 'md' | 'lg' | 'xl' | (string & {})",required:!1,description:"Visual size rung, written to data-size on the root; the data-size attribute may be set directly instead."}],events:[],slots:[{name:"default",description:"The heading text."}],appearance:[{attribute:"data-size",values:["sm","md","lg","xl"],stylesheet:"heading.css"}],states:["default"],controlledUncontrolled:"Stateless \u2014 Heading holds no internal state.",formBehavior:"Not applicable \u2014 Heading participates in no form.",validationBehavior:"Not applicable \u2014 Heading carries no value and participates in no validation.",accessibility:{role:"heading, with aria-level implied by the rendered h1\u2013h6 element",keyboard:[],ariaAttributes:[],focusManagement:`Not focusable by default. A heading that is a skip-link target takes the consumer's own tabindex="-1".`},styling:{cssParts:["heading"],dataAttributes:[...e,"data-size"],cssCustomProperties:[]},publicMethods:[]};export{a as headingContract};
@@ -0,0 +1,3 @@
1
+ import type { ComponentContract } from './types.js';
2
+ /** The Image contract: a native img with a required alt and a Fallback part shown on error. */
3
+ export declare const imageContract: ComponentContract;
@@ -0,0 +1 @@
1
+ import{ROOT_DATA_ATTRIBUTES as e}from"./styling-hooks.js";var a={name:"Image",purpose:`A native <img> with a required alt and a Fallback part shown on error. Loading status is read from the mounted <img>'s own native load/error events, not Avatar's off-DOM probe, which would double-fetch and defeat loading="lazy".`,props:[{name:"src",type:"string",required:!1,description:"Image source, passed straight through to the native src."},{name:"alt",type:"string",required:!0,description:'Accessible name for the image, required at the type level. alt="" is the decorative opt-out; omitting it announces the filename instead.'},{name:"srcSet",type:"string",required:!1,description:"Responsive candidate list, passed through to the native srcset."},{name:"sizes",type:"string",required:!1,description:"Layout size hints, passed through to the native sizes."},{name:"loading",type:"'eager' | 'lazy'",defaultValue:"'lazy'",required:!1,description:"Load timing, passed straight through to the native loading."},{name:"decoding",type:"'sync' | 'async' | 'auto'",defaultValue:"'async'",required:!1,description:"Decode hint, passed straight through to the native decoding."},{name:"fetchPriority",type:"'high' | 'low' | 'auto'",defaultValue:"'auto'",required:!1,description:"Fetch priority, passed through to the native fetchpriority."},{name:"fit",type:"'contain' | 'cover' | 'fill' | 'none' | 'scale-down'",required:!1,description:"How the image fills its box, emitted as object-fit."},{name:"position",type:"string",required:!1,description:"Image alignment within its box, emitted as object-position."},{name:"fallback",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:"Rendered in the Fallback part once loading fails; a prop in React/Svelte/Angular, a slot in Vue and Web Components."},{name:"crossOrigin",type:"string",required:!1,description:"CORS mode, passed straight through to the native crossorigin."},{name:"referrerPolicy",type:"string",required:!1,description:"Referrer policy, passed through to the native referrerpolicy."}],events:[{name:"loading-status-change",detail:"'idle' | 'loading' | 'loaded' | 'error'",description:"Fires the new loading status ('idle' | 'loading' | 'loaded' | 'error') on every transition, sourced from the <img>'s own native load/error events, not Avatar's off-DOM probe image."}],parts:[{name:"Fallback",description:"Renders in place of the <img> once loading status is 'error'. A node or slot, not a second load machine."}],slots:[{name:"fallback",description:"Content shown in place of the <img> once loading status is 'error'."}],states:["idle","loading","loaded","error"],controlledUncontrolled:"Stateless \u2014 Image tracks its own image-loading status internally, not consumer-driven.",formBehavior:"Not applicable \u2014 Image does not participate in forms.",validationBehavior:"Not applicable \u2014 Image carries no value and participates in no validation.",accessibility:{role:"img (native <img>; the Fallback part carries whatever role its own content provides once it renders)",keyboard:[],ariaAttributes:["alt is required at the type level, so it cannot be omitted the way a lint rule can be silenced",'alt="" is the legal decorative opt-out, distinct from an absent alt attribute, which announces the filename instead'],focusManagement:"Not focusable; not part of the tab order.",namingRequirement:`Named by the required alt prop. alt="" opts a purely decorative image out of the accessibility tree's name; alt itself cannot be omitted.`},styling:{cssParts:["root","fallback"],dataAttributes:[...e,"data-loading-status"],cssCustomProperties:["--skdx-image-radius"]},publicMethods:[]};export{a as imageContract};
@@ -0,0 +1,8 @@
1
+ import type { ComponentContract } from './types.js';
2
+ /**
3
+ * Every component contract, declared rather than discovered. A contract file
4
+ * that never reaches this list is invisible to the cross-contract invariants,
5
+ * the parity tooling and the docs site, so `registry.test.ts` fails the build
6
+ * when the directory and this array disagree.
7
+ */
8
+ export declare const CONTRACTS: readonly ComponentContract[];
@@ -0,0 +1 @@
1
+ import{accordionContract as t}from"./accordion.js";import{alertContract as o}from"./alert.js";import{angleSliderContract as r}from"./angle-slider.js";import{aspectRatioContract as m}from"./aspect-ratio.js";import{autocompleteContract as a}from"./autocomplete.js";import{avatarContract as i}from"./avatar.js";import{badgeContract as n}from"./badge.js";import{boxContract as c}from"./box.js";import{breadcrumbContract as p}from"./breadcrumb.js";import{buttonContract as C}from"./button.js";import{calendarContract as f}from"./calendar.js";import{cardContract as e}from"./card.js";import{carouselContract as l}from"./carousel.js";import{chatComposerContract as s}from"./chat-composer.js";import{chatMessageContract as d}from"./chat-message.js";import{checkboxContract as g}from"./checkbox.js";import{checkboxCardContract as b}from"./checkbox-card.js";import{checkboxGroupContract as u}from"./checkbox-group.js";import{clipboardContract as h}from"./clipboard.js";import{collapsibleContract as k}from"./collapsible.js";import{colorPickerContract as x}from"./color-picker.js";import{comboboxContract as P}from"./combobox.js";import{commandContract as v}from"./command.js";import{commentContract as w}from"./comment.js";import{commentThreadContract as y}from"./comment-thread.js";import{confirmDialogContract as S}from"./confirm-dialog.js";import{conversationListContract as F}from"./conversation-list.js";import{dashboardLayoutContract as G}from"./dashboard-layout.js";import{dateFieldContract as I}from"./date-field.js";import{datePickerContract as M}from"./date-picker.js";import{dialogContract as T}from"./dialog.js";import{dividerContract as A}from"./divider.js";import{drawerContract as B}from"./drawer.js";import{editableContract as D}from"./editable.js";import{emptyStateContract as L}from"./empty-state.js";import{fieldContract as O}from"./field.js";import{fileUploadContract as R}from"./file-upload.js";import{filterBarContract as U}from"./filter-bar.js";import{floatingPanelContract as q}from"./floating-panel.js";import{forgotPasswordPageContract as z}from"./forgot-password-page.js";import{formContract as N}from"./form.js";import{formSectionContract as j}from"./form-section.js";import{headingContract as E}from"./heading.js";import{imageContract as H}from"./image.js";import{kbdContract as J}from"./kbd.js";import{labelContract as K}from"./label.js";import{linkContract as Q}from"./link.js";import{listContract as V}from"./list.js";import{listboxContract as W}from"./listbox.js";import{loadingOverlayContract as X}from"./loading-overlay.js";import{mentionsContract as Y}from"./mentions.js";import{menuContract as Z}from"./menu.js";import{menubarContract as _}from"./menubar.js";import{navigationMenuContract as $}from"./navigation-menu.js";import{notificationCenterContract as tt}from"./notification-center.js";import{numberFieldContract as ot}from"./number-field.js";import{onboardingChecklistContract as rt}from"./onboarding-checklist.js";import{pageContainerContract as mt}from"./page-container.js";import{paginationContract as at}from"./pagination.js";import{passwordInputContract as it}from"./password-input.js";import{pinInputContract as nt}from"./pin-input.js";import{popoverContract as ct}from"./popover.js";import{progressContract as pt}from"./progress.js";import{qrCodeContract as Ct}from"./qr-code.js";import{radioCardContract as ft}from"./radio-card.js";import{radioGroupContract as et}from"./radio-group.js";import{ratingContract as lt}from"./rating.js";import{resetPasswordPageContract as st}from"./reset-password-page.js";import{resizableContract as dt}from"./resizable.js";import{scrollAreaContract as gt}from"./scroll-area.js";import{selectContract as bt}from"./select.js";import{signInPageContract as ut}from"./sign-in-page.js";import{signUpPageContract as ht}from"./sign-up-page.js";import{skeletonContract as kt}from"./skeleton.js";import{sliderContract as xt}from"./slider.js";import{speedDialContract as Pt}from"./speed-dial.js";import{spinnerContract as vt}from"./spinner.js";import{splitButtonContract as wt}from"./split-button.js";import{statCardContract as yt}from"./stat-card.js";import{stepperContract as St}from"./stepper.js";import{switchContract as Ft}from"./switch.js";import{tableContract as Gt}from"./table.js";import{tabsContract as It}from"./tabs.js";import{tagGroupContract as Mt}from"./tag-group.js";import{tagsInputContract as Tt}from"./tags-input.js";import{textContract as At}from"./text.js";import{textFieldContract as Bt}from"./text-field.js";import{textareaContract as Dt}from"./textarea.js";import{timeContract as Lt}from"./time.js";import{timeFieldContract as Ot}from"./time-field.js";import{timelineContract as Rt}from"./timeline.js";import{toastContract as Ut}from"./toast.js";import{toggleContract as qt}from"./toggle.js";import{toggleGroupContract as zt}from"./toggle-group.js";import{toolbarContract as Nt}from"./toolbar.js";import{tourContract as jt}from"./tour.js";import{transferContract as Et}from"./transfer.js";import{treeContract as Ht}from"./tree.js";import{treeSelectContract as Jt}from"./tree-select.js";import{usageCardContract as Kt}from"./usage-card.js";import{userMenuContract as Qt}from"./user-menu.js";import{verificationPageContract as Vt}from"./verification-page.js";import{workspaceSwitcherContract as Wt}from"./workspace-switcher.js";var Kr=[t,o,r,m,a,i,n,c,p,C,f,e,G,mt,ut,L,yt,s,d,w,y,S,F,U,j,tt,rt,Kt,Qt,Wt,ht,z,st,Vt,l,b,g,u,h,k,x,P,v,I,M,T,B,Z,D,O,R,q,N,E,H,J,K,Q,V,W,X,Y,_,$,ot,at,it,nt,ct,pt,Ct,ft,et,lt,dt,gt,bt,A,kt,xt,Pt,vt,wt,St,Ft,Gt,It,Mt,Tt,At,Bt,Dt,Lt,Ot,Rt,Ut,qt,zt,Nt,jt,Et,Ht,Jt];export{Kr as CONTRACTS};
@@ -0,0 +1,3 @@
1
+ import type { ComponentContract } from './types.js';
2
+ /** The Kbd contract: a semantic keyboard-shortcut label with no state, ARIA, or behavior beyond native kbd. */
3
+ export declare const kbdContract: ComponentContract;
@@ -0,0 +1 @@
1
+ import{ROOT_DATA_ATTRIBUTES as e}from"./styling-hooks.js";var a={name:"Kbd",purpose:"A keyboard-shortcut label. A semantic <kbd> wrapper with no state, ARIA, or behavior \u2014 sizing, font, and border/chip styling are brand-layer concerns.",props:[{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:[],slots:[{name:"default",description:'Key or key combination label, e.g. "\u2318" or "K". Combinations may be siblings joined by a separator or nested as per the HTML spec. Nested and sibling forms render identically.'}],appearance:[{attribute:"data-size",values:["sm","md","lg"],stylesheet:"kbd.css"}],states:["default"],controlledUncontrolled:"Stateless \u2014 Kbd holds no internal state.",formBehavior:"Not applicable \u2014 Kbd does not participate in forms.",validationBehavior:"Not applicable \u2014 Kbd carries no value and participates in no validation.",accessibility:{role:'generic (native <kbd>, implicit "no corresponding role" semantics \u2014 read as plain text)',keyboard:[],ariaAttributes:[`role="img" plus aria-label naming the key, on a Kbd whose entire content is a non-alphanumeric symbol \u2014 neither is emitted by the component, both are the author's to set`],focusManagement:"Not focusable; not part of the tab order.",namingRequirement:'If content is a word or alphanumeric key ("K", "Esc"), it is announced as-is. If content is a non-alphanumeric symbol ("\u2318", "\u21B5"), pair it with role="img" and aria-label naming the key, since <kbd> has no implicit role and bare symbols are unannounced or misread.'},styling:{cssParts:["kbd"],dataAttributes:[...e,"data-size"],cssCustomProperties:[]},publicMethods:[]};export{a as kbdContract};
@@ -0,0 +1,3 @@
1
+ import type { ComponentContract } from './types.js';
2
+ /** The Label contract: a native label element that guards against double-click text selection on its control. */
3
+ export declare const labelContract: ComponentContract;
@@ -0,0 +1 @@
1
+ import{ROOT_DATA_ATTRIBUTES as t}from"./styling-hooks.js";var o={name:"Label",purpose:"A label element that associates with a form control (via native `for`/`htmlFor` or by wrapping it) and prevents double-click text selection from stealing focus away from the control it labels.",lightDom:!0,props:[{name:"for",type:"string",required:!1,description:"Id of the control this label names. Spelled `for` (Web Components, Angular, Vue, Svelte) or `htmlFor` in React \u2014 both refer to the same attribute. Omit to associate the control by nesting it inside the label."}],events:[],slots:[{name:"default",description:"Label text or content."}],states:["default"],controlledUncontrolled:"Stateless \u2014 Label holds no internal state.",formBehavior:"Associates with a form control via the native `for`/`htmlFor` attribute (or by wrapping the control) \u2014 not a form control itself.",validationBehavior:"Not applicable \u2014 Label carries no value and participates in no validation.",accessibility:{role:"generic (native <label>, implicit labelling semantics)",keyboard:[],ariaAttributes:[],focusManagement:"Not focusable itself; a mousedown handler prevents a double click (detail > 1) from selecting text, without blocking the click-to-focus behavior on the associated control.",namingRequirement:"Its text content becomes the accessible name of the control it is associated with."},styling:{cssParts:["label"],partsCaveat:"`::part(label)` does not match in Web Components; the `<label>` lives in light DOM. A shadow-encapsulated label could not name light-DOM controls by id, so light-DOM rendering is permanent. Style as an ordinary descendant: `skdx-label > label { \u2026 }`. The `part` attribute is kept for name consistency across packages.",dataAttributes:[...t,"data-disabled"],cssCustomProperties:[]},publicMethods:[]};export{o as labelContract};
@@ -0,0 +1,3 @@
1
+ import type { ComponentContract } from './types.js';
2
+ /** The Link contract: a styled anchor with a rel safety default, an inferred external flag, and a DOM-intact disabled state. */
3
+ export declare const linkContract: ComponentContract;
@@ -0,0 +1 @@
1
+ import{ROOT_DATA_ATTRIBUTES as e}from"./styling-hooks.js";var n={name:"Link",purpose:'A styled anchor. Auto-sets rel="noopener noreferrer" on target="_blank" unless rel is set explicitly \u2014 the same guard each package applies to its other anchors \u2014 infers external from a cross-origin href, and keeps href/aria-disabled/DOM intact when disabled, since disabled is invalid on <a>.',props:[{name:"href",type:"string",required:!1,description:"The link destination, passed straight through to the native href."},{name:"target",type:"string",required:!1,description:"Browsing context, passed straight through to the native target."},{name:"rel",type:"string",required:!1,description:'Passthrough to the native rel. Defaults to "noopener noreferrer" against reverse tabnabbing when target is "_blank" and rel is undefined; an explicit rel \u2014 including "" \u2014 always wins.'},{name:"download",type:"boolean | string",required:!1,description:"Download hint, passed straight through to the native download."},{name:"underline",type:"'auto' | 'always' | 'hover' | 'none'",defaultValue:"'auto'",required:!1,description:"Underline treatment, reflected as data-underline for the skin to style. 'auto' underlines only inside running text (p, li, td, blockquote, etc.), not when the link stands alone."},{name:"external",type:"boolean",required:!1,description:"Whether the link is cross-origin, reflected as data-external. Inferred from href's origin when omitted (or, during SSR, an absolute/protocol-relative href); an explicit value always wins, and the inference must not throw on a malformed href \u2014 it falls back to false."},{name:"disabled",type:"boolean",defaultValue:"false",required:!1,description:`Disables the link while keeping href and the anchor in the DOM: sets aria-disabled="true" and tabindex="-1", intercepts click with preventDefault/stopPropagation and keydown's Enter with preventDefault, and emits data-disabled. Never sets a disabled attribute \u2014 invalid on <a>.`},{name:"as",type:"PolymorphicTag",defaultValue:"'a'",required:!1,frameworks:["react","vue","svelte","webComponents"],exception:"as-directive",frameworksReason:"Angular renders a fixed <a> with no as input and no directive alternative, matching all three sibling anchor components in that package \u2014 BreadcrumbLink, NavigationMenuLink, Toolbar \u2014 none of which take an element choice either. Svelte accepts only <a>: spreading anchor attributes across the tag union makes the props type too complex for the compiler to represent, and narrowing to a single tag is the only spelling that checks.",description:"Element name to render instead of the default <a>, from the closed allowlist in POLYMORPHIC_TAGS, where supported. React alone additionally reaches this through asChild, which merges Link's props onto its single child instead of rendering its own <a> \u2014 letting a consumer's router link supply isActive/isPending itself \u2014 and wins over as when both are set."}],events:[],slots:[{name:"default",description:"The link's text or content."}],states:["default","hover","focus","active","disabled"],controlledUncontrolled:"Stateless \u2014 disabled, external and underline are plain consumer-owned inputs; Link holds no internal state.",formBehavior:"Not applicable \u2014 Link does not participate in forms.",validationBehavior:"Not applicable \u2014 Link carries no value and participates in no validation.",accessibility:{role:"link (native <a> with an href)",keyboard:[{key:"Enter",behavior:"Activates the link (native browser behavior). When disabled, keydown is intercepted and Enter is prevented, so the navigation does not happen even though the element stays reachable by mouse and script."}],ariaAttributes:['aria-disabled="true" when disabled is set \u2014 href and the anchor itself stay in the DOM, so this is what tells assistive tech the activation will not land'],focusManagement:'Native tab order via href. tabindex="-1" removes the tab stop when disabled is set; the element is not removed from the DOM, only from the tab order, since the disabled attribute is invalid on <a>.',namingRequirement:"Named by its own text content or an aria-label when the link's content is a bare icon."},styling:{cssParts:["root"],dataAttributes:[...e,"data-underline","data-external","data-disabled"],cssCustomProperties:["--skdx-link-color","--skdx-link-color-hover","--skdx-link-color-visited","--skdx-link-underline-offset"]},publicMethods:[{name:"focus",signature:"(): void",description:"Moves DOM focus to the link's underlying anchor element."}]};export{n as linkContract};
@@ -0,0 +1,3 @@
1
+ import type { ComponentContract } from './types.js';
2
+ /** The List contract: a structural list container that restores role="list" on the container only when markers is false. */
3
+ export declare const listContract: ComponentContract;
@@ -0,0 +1 @@
1
+ import{ROOT_DATA_ATTRIBUTES as e}from"./styling-hooks.js";var n={name:"List",purpose:'A structural list of items, native <ul>/<ol>/<dl> by default. Renders role="list" on the container when markers is false, since Safari/VoiceOver otherwise drop list semantics along with the visual markers. As a <dl> it is a description list: every Item holds a Term and the Description that follows it.',props:[{name:"as",type:"'ul' | 'ol' | 'dl'",defaultValue:"'ul'",required:!1,description:"Element the list root renders. ul and ol hold Item/<li> entries; dl is a description list whose Items each pair a Term (<dt>) with a Description (<dd>), and whose root carries no role at all. React alone additionally reaches this through asChild, which merges List's props onto its single child instead of rendering its own <ul>/<ol>/<dl>."},{name:"markers",type:"boolean",defaultValue:"true",required:!1,description:'true keeps native markers and semantics. false sets list-style: none and adds role="list" to the container (WebKit bug 170179), reflected as data-markers="false". Under as="dl" only the list-style half applies: a role on a <dl> orphans its pairs, so none is written.'},{name:"spacing",type:"'1' | '2' | '3' | '4' | '5' | '6' | '8' | '10' | '12' | '16' | string",required:!1,description:"Emits gap, the same Space resolution as Box: a space-scale key resolves to var(--skdx-space-<key>), any other string passes through verbatim."},{name:"start",type:"number",required:!1,description:"Passthrough to the native start attribute. Valid on <ol> only \u2014 when as is not 'ol', the component must not emit it."},{name:"reversed",type:"boolean",defaultValue:"false",required:!1,description:"Passthrough to the native reversed attribute. Valid on <ol> only \u2014 when as is not 'ol', the component must not emit it."},{name:"items",type:"ReadonlyArray<{ label: string; value: string }>",required:!1,description:'The label/value pairs an as="dl" list renders itself from \u2014 one Item per entry wrapping a Term and a Description, in the same DOM a hand-composed list would write. Absent prop, absent output: with no items the list renders whatever children it was given.'},{name:"orientation",type:"'horizontal' | 'vertical'",defaultValue:"'horizontal'",required:!1,description:'How each pair reads under as="dl": horizontal puts the description beside its term, vertical stacks it underneath. Emitted as data-orientation on the root; the framework packages ship no CSS for it, only @skdx/skins does.'},{name:"density",type:"'compact' | (string & {})",required:!1,description:"Vertical rhythm rung, written to data-density on the root; the data-density attribute may be set directly instead."},{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. Both slot spellings are declared under slots.",description:"Default marker for every Item's Indicator when the item sets none of its own; a prop in React/Svelte/Angular, a slot in Vue and Web Components."}],events:[],parts:[{name:"Item",description:`One list entry; renders <li>, or the <div> grouping one Term with its Description under as="dl" \u2014 a wrapper the spec allows inside a <dl>, and the element a grid or flex row is usually applied to. Sets list-style: none when an icon (its own or List's) is present, so the Indicator replaces the marker. React alone additionally composes via asChild, merging Item's props onto its single child; since the Indicator renders alongside children, asChild wraps the consumer's element around it rather than placing it beside it.`,props:[{name:"value",type:"number",required:!1,description:"Passthrough to the native <li value>. Meaningful on <ol> only."},{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, for the same reasons List's icon prop does.",description:"Overrides List's icon for this item only; a prop in React/Svelte/Angular, a slot in Vue and Web Components."}],slots:[{name:"icon",description:"Per-item override of List's icon slot."}]},{name:"Term",description:`The key half of a pair under as="dl" \u2014 a <dt>, natively associated with the <dd> that follows it. A component in React/Vue/Svelte, a directive in Angular, and the consumer's own <dt> in Web Components.`},{name:"Description",description:`The value half of a pair under as="dl" \u2014 a <dd>. A component in React/Vue/Svelte, a directive in Angular, and the consumer's own <dd> in Web Components.`},{name:"Indicator",description:"The marker-replacement glyph \u2014 wraps nothing \u2014 rendered inside Item from icon (its own or List's)."}],slots:[{name:"default",description:'List items \u2014 typically Item parts, one per entry. Under as="dl" that is Term/Description pairs, optionally each wrapped in an Item; nothing else may go here, since any other element between the <dl> and a <dt> breaks the pairing.'},{name:"icon",description:"Default marker rendered before every item's content."}],appearance:[{attribute:"data-density",values:["compact"],stylesheet:"list.css"}],states:["default","horizontal","vertical"],controlledUncontrolled:"Stateless \u2014 List and its parts hold no internal state.",formBehavior:"Not applicable \u2014 List presents values, it collects none.",validationBehavior:"Not applicable \u2014 List carries no value and participates in no validation.",accessibility:{role:'list (native <ul>/<ol>/<dl>; role="list" is added to the container, and only there, when markers is false and as is not "dl")',keyboard:[],ariaAttributes:['role="list" is emitted on the container exactly when markers is false and as is not "dl"; omitted when markers is true since native semantics are already intact \u2014 WebKit bug 170179','role="list" is never emitted on Item; the container is the element that lost semantics, so it is the only one that needs them restored','Under as="dl" the <dt>/<dd> pairing is what associates a term with its description, and adding ARIA on top would duplicate or contradict it','A name for a <dl> belongs on an element wrapping the root, never on the <dl> itself: <dl> has no implicit ARIA role, and any role written on it \u2014 group and list included \u2014 replaces the list semantics the pairing depends on, which axe reports as one dlitem violation per pair. <div role="group" aria-label="Invoice details"> around the list names it and leaves the semantics intact. assertListContract rejects a role on a <dl> root'],focusManagement:"Not focusable; not part of the tab order. Focus, if any, belongs to interactive content composed inside an Item.",namingRequirement:"Optional but recommended on a wrapper around a <dl> root when a page has more than one list. Each pair is named by its own Term; there is nothing else to name."},styling:{cssParts:["root","item","indicator","term","description"],dataAttributes:[...e,"data-markers","data-orientation","data-density",{name:"data-skdx-list-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-list-gap","--skdx-list-marker-color","--skdx-list-indent"]},publicMethods:[{name:"getDefaultIcon",signature:"(): Element | undefined",description:"A fresh clone of the List's light-DOM icon slot content, or undefined when the slot is empty. Web-Components-only: an item that inherits the List's icon renders it into its own shadow tree, which the ancestor's slotted node cannot reach.",frameworks:["webComponents"],exception:"imperative",frameworksReason:"React, Vue, Svelte and Angular hand the inherited icon down as a renderable value on the list context \u2014 React's `context.icon`, Vue's `context.slots.icon`, Svelte's `list.icon`, Angular's injected list `icon` \u2014 so an item reads it directly and no framework has an instance to call a method on. Only the custom element has to clone the node, because a slotted element renders in exactly one place and every item needs its own copy."}]};export{n as listContract};
@@ -0,0 +1,3 @@
1
+ import type { ComponentContract } from './types.js';
2
+ /** The Listbox contract: an always-visible list of selectable options with roving focus, typeahead, and single or multiple selection. */
3
+ export declare const listboxContract: ComponentContract;