@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{changeDescription as i,changeDetail as e}from"./change-reason.js";import{SELECTION_ATTRIBUTE_RULE as t,SELECTION_INPUT_RULE as o,SELECTION_OUTPUT_RULE as a}from"./selection-value.js";import{ROOT_DATA_ATTRIBUTES as n}from"./styling-hooks.js";var d={name:"Listbox",purpose:"An always-visible list of selectable options with one tab stop, roving focus, typeahead, and single or multiple selection \u2014 the selection list a Select wraps in a popup, usable on its own. Given options and no hand-composed ListboxItem/ListboxGroup children, the root derives one ListboxItem per entry (grouped where options nests a group) instead of the consumer writing the loop.",props:[{name:"options",type:"ReadonlyArray<{ value: string; label?: string; disabled?: boolean } | { label: string; options: Array<{ value: string; label?: string; disabled?: boolean }> }>",required:!1,description:"Flat or grouped option data to render automatically as ListboxItems (and, for a group, a ListboxGroup/ListboxLabel pair), instead of hand composing them as children. Ignored when children declares its own ListboxItem or ListboxGroup. Property-only on <skdx-listbox> (@property({ attribute: false })): an HTML attribute cannot carry an array of objects."},{name:"renderOption",type:"(option: { value: string; label?: string; disabled?: boolean }, state: { selected: boolean }) => React.ReactNode",required:!1,frameworks:["react","svelte","angular"],exception:"render-prop",frameworksReason:'Web Components uses a named slot (`slot="option"`) since HTML attributes cannot carry functions. Vue uses a scoped slot (`#option`) instead of a prop. Angular uses a TemplateRef input.',description:"Customises how a derived option renders inside its ListboxItem. Receives the option and whether it is currently selected. Only read while options is deriving the anatomy."},{name:"value",type:"string | string[]",required:!1,description:`Selected option value(s), for controlled usage. Pair with a value-change event/emit/callback. ${o} ${a} ${t}`},{name:"defaultValue",type:"string | string[]",required:!1,description:`Initially selected value(s), for uncontrolled usage. Same shape as \`value\`. ${o} ${t}`},{name:"multiple",type:"boolean",defaultValue:"false",required:!1,description:'Allows more than one option to be selected. Sets `aria-multiselectable="true"`, makes choosing an option toggle it instead of replacing, and enables range-selection keys: Shift+ArrowDown/ArrowUp, Shift+Space, Control+Shift+Home/End, and Control+A.'},{name:"disabled",type:"boolean",defaultValue:"false",required:!1,description:"Disables every option at once, exposed as aria-disabled/data-disabled on the list and on each option. An individual Item can still be disabled on its own; the two OR together."},{name:"allowSelectAll",type:"boolean",defaultValue:"true",required:!1,description:"Whether Control+A selects every enabled option while `multiple`, or clears if all are already selected. Inert while single-select. Default true (normative for multi-select lists); disable if Control+A should stay with the page (e.g. in an editor pane)."},{name:"orientation",type:"'horizontal' | 'vertical'",defaultValue:"'vertical'",required:!1,description:"Layout axis of the option list. Reflected as aria-orientation and data-orientation, and it is what picks the arrow-key pair: a vertical list roves on ArrowDown/ArrowUp, a horizontal one on ArrowRight/ArrowLeft. This can never be a skin-only attribute \u2014 it changes the keyboard, so it is a component property that the skin then reads for its flex-direction. Home/End, PageUp/PageDown, typeahead and every selection key are unaffected: they name positions in the list rather than directions on screen."},{name:"focusOnHover",type:"boolean",defaultValue:"false",required:!1,description:"Whether moving the pointer over an option moves roving focus onto it. Off by default since Listbox roves real DOM focus; hovering would move document.activeElement. Never moves focus onto a disabled option, never selects."},{name:"disallowEmptySelection",type:"boolean",defaultValue:"false",required:!1,description:"Whether the last selected option refuses to be deselected, so the list always holds at least one value once it holds any. Only reachable while `multiple`. Prevents deselecting via toggle, Control+A clear, or keyboard range operations. Never creates a selection \u2014 a list that starts empty stays empty until the user picks something."},{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:"shape",type:"'square' | 'rounded' | (string & {})",required:!1,description:"Corner rounding rung, written to data-shape on the root; the data-shape attribute may be set directly instead."},{name:"size",type:"'sm' | 'lg' | (string & {})",required:!1,description:"Visual size rung, written to data-size on the root; the data-size attribute may be set directly instead."}],events:[{name:"value-change",description:`${i("the selection")} Carries the whole selection, not the single option that was toggled; selectedValue names that option. ${a}`,detail:e("string[]","selectedValue: string | null")},{name:"value-change-detail",frameworks:["angular"],exception:"event-shape",frameworksReason:"Angular's `valueChange` emits the scalar so `[(value)]` round-trips the value itself; this second output carries the detail object the other four hand to `value-change`.",description:"Fires with valueChange, carrying the previous selection, the change reason and the toggled option.",detail:e("string[]","selectedValue: string | null")}],parts:[{name:"Item",description:`One selectable option (role="option"), holding the list's single tab stop while it is the active one.`,props:[{name:"value",type:"string",required:!0,description:"Identifier committed to the root's value when this option is chosen."},{name:"disabled",type:"boolean",defaultValue:"false",required:!1,description:"Excludes this option from selection and from arrow/typeahead navigation. It stays in the DOM and keeps `aria-selected`, so it is still announced as part of the list."},{name:"textValue",type:"string",required:!1,description:"Text typeahead matches this option against, published as `data-text-value`. Required in practice whenever the option renders more than its label \u2014 an ItemIndicator glyph, an icon, a second line \u2014 because the fallback is the option's whole rendered text content, glyph included."},{name:"posInSet",type:"number | undefined",required:!1,description:`This option's 1-based position in the whole option set, emitted as aria-posinset. Only needed when the rendered options are a window onto a longer list \u2014 a virtualized listbox, or one that pages in more rows as the user scrolls \u2014 where a screen reader counting the DOM announces "3 of 20" for row 4,003 of a million. Absent by default, so the browser's own count stands for an ordinary list. This is the one piece of virtualized-listbox accessibility that belongs inside a package: the consumer owns the windowing, but only the option can carry the attribute.`},{name:"setSize",type:"number | undefined",required:!1,description:'Size of the whole option set this option belongs to, emitted as aria-setsize. Set together with `posInSet`: a position without a size announces "item 4 of an unknown number", which is worse than the DOM count it replaces.'}]},{name:"ItemIndicator",description:"Selected-state glyph inside an Item, rendered only while that option is selected. `aria-hidden`: the option's `aria-selected` already carries the state.",props:[{name:"forceMount",type:"boolean",defaultValue:"false",required:!1,description:"Keep the indicator mounted even while its option isn't selected."}]},{name:"Group",description:'A labelled group of related Items (role="group"), pointing `aria-labelledby` at its own Label.'},{name:"Label",description:"The heading naming its Group, carrying the id the Group references. Not an option, and not focusable."}],slots:[{name:"default",description:"Listbox content \u2014 Item, Group, and Label parts. Given options and no ListboxItem/ListboxGroup here, the root derives this content itself instead."},{name:"item",description:"An Item's content \u2014 its label, and optionally an ItemIndicator."}],appearance:[{attribute:"data-density",values:["compact"],stylesheet:"listbox.css"},{attribute:"data-shape",values:["square","rounded"],stylesheet:"listbox.css"},{attribute:"data-size",values:["sm","lg"],stylesheet:"listbox.css"}],states:["disabled","multiple","selected","active"],controlledUncontrolled:"The selected value supports controlled (value + value-change) and uncontrolled (defaultValue) usage. There is no open state to control \u2014 the list is always visible. In Angular the pair is split: `valueChange` emits the scalar for `[(value)]`, `valueChangeDetail` carries the detail.",formBehavior:"None. No `name`/hidden-input form participation. Listbox is a picker whose result the consumer commits; wrap it in a Field and submit the value you hold.",validationBehavior:"None. No `required`/`invalid` flag or constraint validation.",accessibility:{role:"listbox (root); group (each Group); option (each Item)",keyboard:[{key:"Tab",behavior:"Moves into the list, landing on its single tab stop \u2014 the selected option, or the first enabled one \u2014 and back out again. Focus is never trapped."},{key:"ArrowDown / ArrowUp",behavior:"Moves roving focus to the next/previous enabled option (no wrap) while `orientation` is `vertical`. A `horizontal` list answers ArrowRight/ArrowLeft instead, and leaves the vertical pair to the page \u2014 one axis, one owner."},{key:"ArrowRight / ArrowLeft",behavior:"Moves roving focus to the next/previous enabled option (no wrap) while `orientation` is `horizontal`. Inert on a vertical list, which is the default."},{key:"Home / End",behavior:"Moves roving focus to the first/last enabled option."},{key:"PageDown / PageUp",behavior:"Moves roving focus ten enabled options down/up, clamped at the ends. Ten is a literal count rather than a measured screenful: a package has no rendered row height to divide a scroll box by. The listbox pattern does not specify these two keys at all, and the alternative reading \u2014 aliasing them to Home/End, which is what the one reference documenting them does \u2014 would leave the user with no coarse move at all. Ten is what the combobox pattern makes normative for its listbox, so Select already jumps ten, and two components in the same family presenting the same list must answer the same key the same way."},{key:"Printable characters",behavior:"Typeahead: moves focus to the next option whose text starts with what was typed, matched against `textValue` when given. A 1s buffer accumulates characters into one search; repeating a single letter cycles through the options starting with it, as a native `<select>` does. Typeahead moves focus only \u2014 it never selects, since selection follows Enter/Space."},{key:"Enter or Space",behavior:"Selects the focused option \u2014 replacing the selection, or toggling it when `multiple`. Space is claimed by the option, so it never starts a typeahead search and never scrolls the list."},{key:"Shift+ArrowDown / Shift+ArrowUp",behavior:"While `multiple`: moves roving focus to the next/previous enabled option **and toggles that option**, so a run can be extended without leaving the keyboard. The toggle is literal, as APG states it \u2014 walking down selects each option arrived at, and walking back up deselects them again, which is how an overshot run is shrunk. Clamped like the plain arrows: at either end there is nothing to extend onto, so nothing moves and nothing is selected. While single-select these are the plain arrows, since a list with one selected option has no selection to extend."},{key:"Shift+Space",behavior:'While `multiple`: selects every enabled option between the selection anchor and the focused one, inclusive, in either direction \u2014 APG\'s "Selects contiguous items from the most recently selected item to the focused item." Additive: it selects what it spans and leaves the rest of the selection alone. The anchor is the option the user last acted on directly: every non-range commit (click, Enter, Space, and the Shift+Arrow toggle) moves it, whether that commit selected or deselected the option; a range commit deliberately leaves it where it is, so repeated Shift+Space grows one range from a fixed origin instead of dragging the origin along behind the focus; and losing the selection entirely drops it, since with nothing selected there is no "most recently selected item" to name \u2014 a Shift+Space then selects only the focused option. Unlike Enter/Space this key is read on the list rather than on the option, because a range needs the whole option list and the anchor, which only the list has. While single-select it is the plain Space the option claims.'},{key:"Control+Shift+Home / Control+Shift+End",behavior:'While `multiple`: selects every enabled option from the focused one to the first (Home) or last (End) option of the list, inclusive \u2014 APG\'s "Selects the focused option and all options up to the first option" and its downward twin. Additive, exactly like Shift+Space: the span is added to the selection rather than replacing it. Focus deliberately does not move \u2014 APG makes that half optional, and leaving it put is what keeps these two agreeing with Shift+Space, which also selects a span without moving. A range commit, so the selection anchor stays where the last non-range commit left it and a following Shift+Space still runs from there rather than from the end of the list. Inert while single-select.'},{key:"Control+A",behavior:"While `multiple` and `allowSelectAll`: selects every enabled option, and \u2014 once every enabled option is already selected \u2014 clears them again. The toggle is the optional half of the normative rule and the half that makes the key usable, since without it the only way back out of a select-all is to click every option. Disabled options are never swept in: they are not a selection target by any other route, and one added here could not be removed from the keyboard. Inert while single-select, and left entirely to the page when `allowSelectAll` is off."}],ariaAttributes:['aria-multiselectable="true" on the list while `multiple` (absent otherwise, never "false")','aria-orientation on the list, always present and always matching `orientation` \u2014 unlike aria-multiselectable this is not a presence flag, since "horizontal" and "vertical" are both real answers',"aria-disabled on the list and on each disabled option","aria-selected on every option, selected or not","aria-posinset and aria-setsize on an option that declares them, and on no other \u2014 the browser counts the DOM correctly for a list that is entirely present, and a partial or contradictory pair is worse than none","aria-labelledby on each Group, pointing at its Label"],focusManagement:'Real roving focus, not virtual: exactly one option carries tabindex="0" (the selected one, else the first enabled one) and every other carries tabindex="-1", so document.activeElement is always the option being announced. Focusing an option moves the tab stop onto it. Disabled options are never the tab stop and are skipped by the arrows. Deliberately unlike Combobox, which keeps DOM focus on its input and tracks the highlighted option with aria-activedescendant \u2014 there is no input here to keep focus in, which is exactly what the collection-focus rule turns on.',namingRequirement:'role="listbox" takes no accessible name from its content, so the consumer must supply one with aria-label or aria-labelledby. Nothing in the component can do this for it: unlike Select, there is no trigger to point at. Each Group is named by its own Label automatically.'},styling:{cssParts:["listbox","item","item-indicator","group","label"],dataAttributes:[...n,"data-multiple","data-orientation","data-disabled","data-state","data-value","data-text-value","data-density","data-shape","data-size",{name:"data-skdx-listbox-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{d as listboxContract};
@@ -0,0 +1,3 @@
1
+ import type { ComponentContract } from './types.js';
2
+ /** The LoadingOverlay contract: a scrim and indicator over a busy region, with a delay that suppresses flash on fast responses. */
3
+ export declare const loadingOverlayContract: ComponentContract;
@@ -0,0 +1 @@
1
+ import{ROOT_DATA_ATTRIBUTES as e}from"./styling-hooks.js";var n={name:"LoadingOverlay",purpose:"A busy-state overlay for a region or the whole viewport, with delay to suppress flash-of-spinner on fast responses and aria-busy on the covered content. Composed of root, Backdrop, and Content parts.",props:[{name:"visible",type:"boolean",required:!1,description:"Controlled busy state \u2014 whether work is in flight. Pair with the visible-change event."},{name:"fullScreen",type:"boolean",defaultValue:"false",required:!1,description:"Cover the viewport instead of the root's box (position: fixed; inset: 0) and lock body scroll while visible. An inline overlay never locks the body \u2014 freezing the whole page for a spinner over one card is a bug, not a feature."},{name:"loadedLabel",type:"string",required:!1,description:"Text announced when the overlay hides, closing the appearance announcement loop. Optional (default undefined) \u2014 announcing every completion on a page full of small loads would be excessive, so this is opt-in. When omitted the overlay still clears its message from the live region on hide, which lets two consecutive loads announce twice."},{name:"loadingLabel",type:"string",defaultValue:"'Loading'",required:!1,description:'Text announced when the overlay appears, and the default indicator label inside Content. Name the work ("Loading invoices") when more than one region can be busy.'},{name:"delay",type:"number",defaultValue:"0",required:!1,description:"Milliseconds to wait after visible turns true before rendering. Responses arriving inside the window never render an overlay at all, which stops the flash-of-spinner on fast requests. The timer cancels if visible flips back or on unmount. Default 0 (show immediately) so nothing is hidden from a slow connection."},{name:"emphasis",type:"'low' | 'medium' | 'high' | (string & {})",required:!1,description:"Scrim strength rung forwarded to the Backdrop's data-emphasis; the attribute may be written on Backdrop directly instead."}],events:[{name:"visible-change",detail:"boolean",description:"Fired when the overlay actually appears or disappears (after delay). Reports the effective transition rather than echoing the prop back, because the moment a delayed overlay paints is what the caller cannot derive. With delay 0 the two coincide."}],parts:[{name:"Backdrop",description:'The scrim layer, present only while visible. Decorative and aria-hidden \u2014 the busy state comes from aria-busy and the announcement, not the dimmed rectangle. A CSS exit transition on hide is React-only: React alone keeps the node painted with `data-state="hidden"` until its running animation ends, Vue and Svelte unmount the instant `visible` turns false, and Angular and Web Components hide the node with `hidden`, which resolves to `display: none` and cannot be transitioned. Every framework reports the effective transition through `visible-change`, so a caller that needs to sequence work against the hide has that signal in all five.',props:[{name:"emphasis",type:"'low' | 'medium' | 'high' | (string & {})",required:!1,description:"Scrim strength rung, written to data-emphasis on the backdrop; the data-emphasis attribute may be set directly instead."}]},{name:"Content",description:"The centered indicator layer, present only while visible on the same terms as Backdrop, exit transition included. It sits inside the inert wrapper, so nothing here is focusable or announced \u2014 announcements come from the root instead."}],slots:[{name:"default",description:"The covered content plus Backdrop and Content layers. It stays in the DOM and reading order \u2014 busy, not gone."}],appearance:[{attribute:"data-emphasis",values:["low","medium","high"],stylesheet:"loading-overlay.css"}],states:["hidden","visible","full-screen"],controlledUncontrolled:"Controlled. The caller owns visibility through visible and hears the effective transition through visible-change. There is nothing for a user to act on (no trigger, dismissal, or gesture), so uncontrolled mode has no event to change state from. The delay sits between the requested state and the rendered one, so parts mount against the effective visibility rather than the prop.",formBehavior:"Not applicable \u2014 LoadingOverlay participates in no form.",validationBehavior:"Not applicable \u2014 LoadingOverlay collects no value.",accessibility:{role:"none \u2014 the root is a generic element carrying aria-busy, not a landmark or a live region of its own",keyboard:[],ariaAttributes:["aria-busy on the root while visible, which tells assistive technology the content underneath is being updated. The root is never itself inert, or this attribute would be removed from the accessibility tree and the busy state would reach nobody","inert on the covered wrapper \u2014 never on the root \u2014 while visible, so the content and layers are out of the tab order and accessibility tree while the element naming the state stays in it","The loadingLabel is announced through the shared live announcer, deliberately rendered outside the inert subtree: a live region inside an inert subtree announces nothing. Announced after the delay, so finished work is never announced as started","aria-hidden on the Backdrop, which is decoration","loadedLabel when supplied is announced on the hide transition; when omitted the overlay clears its message from the shared region, so a second identical loadingLabel still registers as a mutation and is announced"],focusManagement:"Focus is neither moved nor trapped. The covered region is inert while visible, so focus cannot land inside it, but nothing is pulled away from wherever the user is: a busy region is not modal.",namingRequirement:'loadingLabel is the accessible name of the busy state. Default "Loading" is enough for one region; name the work when there is more than one, since identical announcements tell the user nothing about which finished.'},styling:{cssParts:["root","covered","backdrop","content"],dataAttributes:[...e,"data-state","data-full-screen","data-emphasis",{name:"data-skdx-loading-overlay-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 loadingOverlayContract};
@@ -0,0 +1,18 @@
1
+ import type { ComponentContract } from './types.js';
2
+ /** Stable member IDs for parity tooling, shaped component/part/kind/name in kebab-case. */
3
+ /** Which of a contract's four member lists an ID points into. */
4
+ export type MemberKind = 'prop' | 'event' | 'slot' | 'method';
5
+ /** The `root` segment used for members declared on the component itself rather than on a part. */
6
+ export declare const ROOT_PART = "root";
7
+ /**
8
+ * Builds one member ID from a component, a {@link PartContract} name (or {@link ROOT_PART}), a kind, and a member name.
9
+ *
10
+ * @example
11
+ * ```ts
12
+ * memberId('Popover', 'Content', 'prop', 'sideOffset'); // 'popover/content/prop/side-offset'
13
+ * memberId('Popover', ROOT_PART, 'event', 'open-change'); // 'popover/root/event/open-change'
14
+ * ```
15
+ */
16
+ export declare function memberId(component: string, part: string, kind: MemberKind, name: string): string;
17
+ /** Every member ID a contract declares, root members first, then parts. */
18
+ export declare function contractMemberIds(contract: ComponentContract): string[];
@@ -0,0 +1 @@
1
+ var o="root";function m(t){return t.replace(/([a-z0-9])([A-Z])/g,"$1-$2").replace(/[\s_]+/g,"-").toLowerCase()}function s(t,n,e,r){return`${m(t)}/${m(n)}/${e}/${m(r)}`}function a(t,n,e){return[...(e.props??[]).map(r=>s(t,n,"prop",r.name)),...(e.events??[]).map(r=>s(t,n,"event",r.name)),...(e.slots??[]).map(r=>s(t,n,"slot",r.name)),...(e.methods??[]).map(r=>s(t,n,"method",r.name))]}function p(t){let{name:n}=t;return[...a(n,o,{...t,slots:[]}),...t.slots.map(e=>s(n,o,"slot",e.name)),...t.publicMethods.map(e=>s(n,o,"method",e.name)),...(t.parts??[]).flatMap(e=>a(n,e.name,e))]}export{o as ROOT_PART,p as contractMemberIds,s as memberId};
@@ -0,0 +1,3 @@
1
+ import type { ComponentContract } from './types.js';
2
+ /** Contract for a free-text field whose trigger characters open a suggestion popup over one token, leaving the rest of the text and the caret untouched. */
3
+ export declare const mentionsContract: ComponentContract;
@@ -0,0 +1 @@
1
+ import{changeDescription as n,changeDetail as e}from"./change-reason.js";import{constraintValidationMethods as i,setCustomValidityMethod as r}from"./form-validity.js";import{dismissalEvents as o,forceMountProp as t,openChangeCompleteEvent as s,popperContentProps as l,popperMeasurementProperties as d,portalPart as h,portalPropsSansForceMount as p}from"./overlay-parts.js";import{VIRTUAL_FOCUS_RULE as u}from"./rules.js";import{PART_DATA_ATTRIBUTES as c}from"./styling-hooks.js";var a="mention: { trigger: string; value: string; text: string; start: number; end: number } | null",w={name:"Mentions",purpose:`A multi-line text field where a trigger character such as "@" opens a floating listbox that filters a collection, and choosing an item replaces only the typed token rather than the whole value. Real DOM focus stays on the textarea for the entire interaction; the highlighted item is virtual focus (aria-activedescendant), and the popup is anchored to the caret rather than to the field. Unlike a Combobox, the component's value is the free text the user wrote and the query is a substring inside it.`,props:[{name:"value",type:"string",required:!1,description:"The field's full text, for controlled usage. Pair it with the value-change event. This is the whole textarea value, not the mention that was just picked; the picked item rides along in the event detail."},{name:"defaultValue",type:"string",defaultValue:"''",required:!1,description:"Initial text of the field, for uncontrolled usage, and the text a form reset restores."},{name:"triggers",type:"string | readonly string[]",defaultValue:"'@'",required:!1,description:`Characters that open a mention when typed at a word boundary. More than one is the common requirement \u2014 "@" for people beside "#" for issues \u2014 so a string is read one character at a time ("@#" configures both) and an array says the same thing where an attribute would be awkward. Each entry is exactly one character; multi-character triggers are not supported. The active character is reported on every query-change event, published as data-trigger, and matched against each Item's own trigger, so each trigger addresses its own collection without a second collection prop.`},{name:"options",type:"Array<{ value: string; label?: string; trigger?: string; disabled?: boolean }>",required:!1,description:"Declares the mentionable collection as data instead of hand-composed Item children, and the derived Content renders one Item per entry. An entry with no `trigger` belongs to the first configured trigger. The list is flat: mention popups are short and ranked, so there is no group form here. Property-only on `<skdx-mentions>` (`@property({ attribute: false })`): an array of objects has no attribute form."},{name:"filter",type:"'manual' | ((itemText: string, query: string) => boolean | number)",defaultValue:"'manual'",required:!1,description:"How Items are narrowed against the active query \u2014 the substring between the trigger character and the caret, never the whole field value. `'manual'` (default): the consumer renders only matching Items, which is what an async lookup keyed on query-change needs. A predicate moves filtering inside: every Item is measured by `textValue` or its rendered text, and rejected ones stop being options. Return a boolean to filter or a number to rank (0 excludes, positive keeps and orders by score). With `options` supplied and no `filter`, a case-insensitive match on the query narrows the derived list. On `<skdx-mentions>` this is property-only (`el.filter = \u2026`): attributes carry strings, not predicates."},{name:"serialize",type:"(item: { value: string; textValue: string; trigger: string }) => string",defaultValue:"(item) => `${item.trigger}${item.textValue}`",required:!1,description:'Builds the text that replaces the typed token when an item is chosen. The default writes the trigger character followed by the item\'s text, so picking Alice under "@ali" leaves "@Alice". Return anything the field should contain instead \u2014 a bare name, a wiki link, a "user:1234" token \u2014 and the same string reaches the value-change detail as `text`. Property-only on `<skdx-mentions>`: attributes cannot carry functions.'},{name:"appendSpace",type:"boolean",defaultValue:"true",required:!1,description:"Whether a single space follows an inserted mention so typing continues cleanly, skipped when the text already carries on with whitespace. Set false where a mention is normally followed by punctuation."},{name:"allowedSpaces",type:"number",defaultValue:"0",required:!1,description:"How many spaces a query may contain before the mention is abandoned. Zero means the first space ends it, which is what a handle needs; raise it for a collection whose labels are full names. A line break always ends a mention regardless of this number."},{name:"requireWordBoundary",type:"boolean",defaultValue:"true",required:!1,description:'Whether a trigger only opens a mention at the start of the value or directly after a non-word character, which is what keeps "user@example.com" from opening a popup mid-address. Set false to accept a trigger anywhere.'},{name:"open",type:"boolean",required:!1,description:"Controlled open state of the popup. Pair with the open-change event."},{name:"defaultOpen",type:"boolean",defaultValue:"false",required:!1,description:"Initial open state of the popup, for uncontrolled usage."},{name:"autoHighlight",type:"boolean",defaultValue:"true",required:!1,description:"Keeps the first item highlighted whenever the filtered list changes while open, so Enter always has a target. On by default, the opposite of Combobox: there the draft text is itself a valid answer, while a mention popup exists only to be committed and an unhighlighted list would make Enter insert a line break in the middle of a half-typed handle."},{name:"loop",type:"boolean",defaultValue:"true",required:!1,description:"Wraps arrow navigation around the ends of the item list. On by default; set false to clamp at the ends."},{name:"loading",type:"boolean",defaultValue:"false",required:!1,description:'Marks items as in flight, exposed as `aria-busy="true"` plus `data-loading` on Input and Content, and suppresses the result-count announcement \u2014 a count measured mid-fetch would announce "0 results available" for every keystroke.'},{name:"autoResize",type:"boolean",defaultValue:"false",required:!1,description:"Grows the field to fit its content instead of showing a scrollbar, on the same measurement Textarea uses. A scrolling field moves the caret under the popup, so a long message reads better with this on."},{name:"minRows",type:"number",defaultValue:"2",required:!1,description:"The field's opening size, and the floor auto-resize will not shrink below. Rendered as the native rows attribute when autoResize is off, and applied as a minimum on the measured height when it is on, so the same number means the same thing either way."},{name:"maxRows",type:"number",required:!1,description:"Caps auto-resize growth to this many rows, based on computed line-height. Where minRows and maxRows disagree the cap wins, matching Textarea."},{name:"disabled",type:"boolean",defaultValue:"false",required:!1,description:"Disables the field so no mention can ever open. Distinct from readOnly, which still allows focus and text selection."},{name:"readOnly",type:"boolean",defaultValue:"false",required:!1,description:"Makes the field read-only, exposed as the native readonly attribute plus aria-readonly/data-readonly. Trigger detection is suspended, since nothing can be inserted."},{name:"invalid",type:"boolean",defaultValue:"false",required:!1,description:"Marks the field as invalid, exposed as aria-invalid and data-invalid on the Input."},{name:"name",type:"string",required:!1,description:"Form field name. The full text of the field is submitted under it; without a name the component submits nothing at all."},{name:"form",type:"string | undefined",required:!1,defaultValue:"undefined",description:"Id of the `<form>` this field submits into, so it can live outside that form's subtree. Web Components names this `formId`, not `form`: the element already publishes a readonly `form` accessor."},{name:"required",type:"boolean",defaultValue:"false",required:!1,description:"Marks the field required for native constraint validation: valueMissing while the text is empty. It says nothing about mentions \u2014 a message with no mention in it is still a valid message."},{name:"getResultCountLabel",type:"(count: number) => string",defaultValue:"defaultGetResultCountLabel",required:!1,description:'Formats the message announced through the shared LiveAnnouncer whenever the rendered item count changes while the popup is open. Return an empty string to announce nothing. The default singularises: "1 result available" for a count of one, "3 results available" otherwise. Property-only on `<skdx-mentions>`, like `filter` and `serialize`.'},{name:"placeholder",type:"string",required:!1,description:"Placeholder text forwarded to the derived Input. Ignored under full manual composition, where the Input is written by hand."},{name:"renderOption",type:"(option: MentionsOptionData, state: { highlighted: boolean }) => ReactNode",required:!1,frameworks:["react","svelte","angular"],exception:"render-prop",frameworksReason:'Web Components uses a named light-DOM slot (`slot="option"`, keyed by `data-value`), the platform-native form of the hook, and Vue uses a scoped slot (`#option`). Both are that framework\'s own idiom for the same customisation, and neither is visible to a prop extractor.',description:"Custom rendering for an `options`-derived Item \u2014 an avatar beside a handle, a secondary line of context. Angular takes a `TemplateRef` instead of a function. Ignored for hand-composed Item children."},{name:"aria-label",type:"string",required:!1,frameworks:["react","vue","svelte","angular"],exception:"attribute-passthrough",frameworksReason:"React forwards `aria-label` literally; Vue and Svelte declare it as `ariaLabel`, which the extractor folds back; Angular takes `ariaLabel`. The derived name resolves to `aria-label ?? placeholder` in all five. Web Components declares no property at all \u2014 it claims the native attribute off the host and relocates it onto the derived control, which is the platform mechanism for the same capability.",description:"Convenience accessible name for the derived Input, and for Content, which takes no name from its own contents. Equivalent to naming Input directly under manual composition."},{name:"emptyMessage",type:"string",required:!1,frameworks:["angular","svelte"],exception:"derived-anatomy",frameworksReason:"Angular and Svelte fold the Empty part into their derived anatomy behind this prop. React, Vue and Web Components publish the same part for the consumer to place by hand, so the prop would only restate what writing the part already says.",description:"Content for the derived Empty part, shown when the query matches no items. Where this prop is absent the package renders a hardcoded placeholder string instead."}],events:[{name:"value-change",description:`${n("the field's text")} Carries the whole field value, never the mention alone; \`mention\` names the item that was just inserted and the range it replaced, and is null for an ordinary keystroke.`,detail:e("string",a)},{name:"value-change-detail",frameworks:["angular"],exception:"event-shape",frameworksReason:"Angular's `valueChange` emits the scalar so `[(value)]` round-trips the text itself; this second output carries the detail object the other four hand to `value-change`.",description:"Fires with valueChange, carrying the previous text, the change reason and the inserted mention.",detail:e("string",a)},{name:"query-change",detail:"{ trigger: string; query: string; start: number; end: number } | null",description:"Fires whenever the token under the caret changes, carrying the active trigger, the query substring and the offsets the token occupies \u2014 and null once no mention is being typed. This is the hook an async collection is loaded from: there is no `query` prop, because the query is derived from the text and the caret together and cannot be set without also placing the caret."},{name:"open-change",detail:"boolean",description:"Fired with the new open state whenever it changes, controlled or not."},{name:"highlight-change",detail:"{ value: string | null; previousValue: string | null; reason: 'keyboard' | 'pointer' | 'auto' }",description:"Fires whenever virtual focus moves, carrying the highlighted item value, the value it replaced, and what moved it. Read-only: no `highlight` or `defaultHighlight` prop exists, since a programmatic highlight could name an unrendered item and make aria-activedescendant point at nothing. `value` is the item's value, never its element id. `reason` is not a ChangeReason: `'auto'` covers filtering, re-seeding and the highlight `autoHighlight` assigns on open."},s("popup"),...o("popup")],parts:[{name:"Input",lightDom:!0,description:'The multi-line text field the mentions are typed into \u2014 a real `<textarea>`, so wrapping, line breaks, autosize and the native form value are the platform\'s. Keeps real DOM focus for the whole interaction and carries aria-haspopup="listbox" with aria-controls, aria-autocomplete="list" and the aria-activedescendant naming the highlighted item. HTML permits no role attribute on a textarea, so the field keeps its native textbox role and the popup relationship is announced through haspopup; the field\'s value stays the free text the user wrote.'},{...h,props:[...p,{...t,frameworks:["react","vue","svelte"],exception:"force-mount",frameworksReason:"Web Components never unmounts a closed overlay (it only hides it), so forceMount has no unmount to prevent. Angular ships no Portal part on any overlay family \u2014 it portals with the [skdxPortal] attribute directive instead."}]},{name:"Content",description:'The floating listbox (role="listbox") of mentionable items, positioned below and start-aligned. Its anchor is the caret rather than the field: each adapter measures the caret rectangle and positions Content against a zero-width virtual anchor standing on it, so the popup follows the mention through wrapped lines instead of parking under the whole textarea. One consequence for skins: `--skdx-mentions-trigger-width` measures that anchor and is therefore always 0, so size Content from `--skdx-mentions-available-width` rather than matching the anchor as a dropdown would.',props:[...l({align:"'start'",sideOffset:"4"}),{...t,frameworks:["react","vue","svelte"],exception:"force-mount",frameworksReason:"Web Components never unmounts a closed overlay (it only hides it). Angular keeps this part in the tree and toggles it with [hidden], so neither ships forceMount."}]},{name:"Item",description:'One mentionable entry (role="option"). Highlighted virtually, never focused, so the caret stays exactly where the user left it. An Item whose trigger differs from the active one is not an option at all: unreachable through aria-activedescendant, uncounted in the announcement, and invisible to the Empty part\'s emptiness check \u2014 the same treatment a rejected `filter` result gets. Removed from the DOM in React/Vue/Svelte/Angular; hidden in Web Components, which cannot un-author consumer tags.',props:[{name:"value",type:"string",required:!0,description:"Identifier for this entry, published as data-value and carried on the value-change detail when the entry is inserted. It is not what gets written into the text; `serialize` decides that."},{name:"trigger",type:"string",required:!1,description:"Which trigger character this entry belongs to, so one field can address several collections. Defaults to the first configured trigger, which makes the prop unnecessary for a single-trigger field."},{name:"textValue",type:"string",required:!1,description:"Text the `filter` predicate matches and the default `serialize` writes into the field. Falls back to the entry's rendered text, which is wrong only when the entry renders more than its label \u2014 an avatar, a secondary line \u2014 so supply it then."},{name:"disabled",type:"boolean",defaultValue:"false",required:!1,description:"Excludes this entry from insertion and from pointer or keyboard highlight; exposed as aria-disabled and data-disabled."}]},{name:"Empty",description:"Shown in place of the item list when the active query matches nothing \u2014 because the consumer rendered no Items for it, or because the `filter` predicate rejected every one."}],slots:[{name:"default",description:"Content's body \u2014 the Item entries and an Empty state."}],states:["closed","open","highlighted","disabled","readonly","invalid","loading"],controlledUncontrolled:"value and open are independent controlled/uncontrolled axes, each starting from its default* prop and switching to controlled when the matching prop is passed. The active token is neither: it is derived from the text and the caret on every input, selection and composition-end event, so there is no query prop to control and no token state to go stale. In Angular the pair is split: `valueChange` emits the scalar for `[(value)]`, `valueChangeDetail` carries the detail.",formBehavior:"Form-associated: with a name, the field's full text is submitted under it and a required field with empty text is valueMissing. React, Vue, Svelte and Angular stamp the name on the real `<textarea>` the Input renders, so submission and validation are the platform's own; `<skdx-mentions>` keeps its textarea in a shadow root and is form-associated through ElementInternals, publishing the same value and validity. A form reset restores `defaultValue` \u2014 falling back to the empty string \u2014 in all five packages, and closes any open popup. Mentions are submitted as the text `serialize` produced; there is no second hidden control carrying a structured list.",validationBehavior:"invalid is presentational only (aria-invalid/data-invalid); required, minlength and maxlength participate in native constraint validation on the underlying textarea, reached through checkValidity()/reportValidity(). No membership rule exists and none is planned: text around a mention is the normal case here, and an unresolved handle is a consumer-side concern rather than a constraint the component can state. A field marked invalid must also be pointed at the text explaining why, through aria-describedby; wrapping it in a Field does that wiring automatically.",accessibility:{role:"textbox (Input, the native <textarea>), listbox (Content), option (Item), presentation (Empty)",keyboard:[{key:"Typing",behavior:"Ordinary text entry. Typing a trigger character at a word boundary opens the popup with an empty query; typing on narrows it; typing a space, a line break or a second trigger ends the mention and closes the popup."},{key:"Typing (IME composition)",behavior:"Trigger detection is suspended between compositionstart and compositionend and runs once on the composition-end value. Detecting mid-composition would read the half-formed romaji or pinyin buffer as a query, reopen and re-filter the popup on every intermediate keystroke, and let Enter \u2014 which commits the composition \u2014 insert a mention the user never chose. Enter, ArrowUp and ArrowDown are left entirely to the IME while a composition is active."},{key:"ArrowDown / ArrowUp",behavior:'While the popup is open, moves the highlight by one and prevents the default, wrapping around the ends unless `loop` is false. While it is closed neither key is intercepted: in a multi-line field they are the caret\'s line keys, and stealing them would strand a keyboard user in the first line. Neither key opens the popup, which is the difference from Combobox \u2014 there is no "show me the list" gesture when the list belongs to a token that has not been typed yet.'},{key:"Home / End / PageUp / PageDown",behavior:"Never intercepted, open or closed. These are the caret keys of a multi-line field and a user needs them far more than a jump to the ends of a short mention list, which arrow keys reach in a few presses anyway."},{key:"Enter",behavior:"While the popup is open with an item highlighted, inserts that mention and prevents the default, so no line break is added. With the popup closed, or open with nothing highlighted, it is the textarea's own Enter and inserts a line break."},{key:"Tab",behavior:"While the popup is open with an item highlighted, commits that mention and prevents the default \u2014 the gesture every mention field ships. Otherwise Tab is untouched and moves focus, and Escape always closes the popup first, so the field is never a keyboard trap."},{key:"Escape",behavior:"Closes the popup and leaves the text and the caret exactly as they are. The dismissed token stays closed while it is being edited, so continuing to type does not reopen it; the next trigger character opens a fresh one."},{key:"Backspace",behavior:"Ordinary deletion. Deleting back past the trigger character ends the mention and closes the popup; an inserted mention is plain text and is deleted one character at a time, not as an atom."}],ariaAttributes:['aria-haspopup="listbox" with aria-controls and aria-autocomplete="list" on the Input, which is a real <textarea>; HTML permits no role attribute there, so the field keeps its native textbox role and the popup is announced through haspopup rather than aria-expanded',"aria-activedescendant on the Input naming the highlighted item \u2014 the highlight is virtual, so DOM focus never leaves the field and the caret never moves","Content's id matches the Input's aria-controls, which resolves exactly while the popup is open and is absent while it is closed, since an IDREF resolving to nothing is worse than no IDREF","data-trigger on Content and on the Input naming the trigger character of the active token, and on every Item naming the trigger it belongs to",'aria-busy="true" and data-loading on Input and Content while `loading`',"data-highlighted on the item holding virtual focus, and aria-disabled with data-disabled on a disabled item, which highlight and insertion both skip","the number of rendered items is announced through the shared LiveAnnouncer polite region while the popup is open, formatted by getResultCountLabel \u2014 filtering is otherwise silent to assistive technology \u2014 and suppressed entirely while `loading`","aria-invalid and aria-readonly on the Input, mirroring the matching props, with aria-describedby carrying the text that explains an invalid field",'the highlighted item is scrolled into view on every keyboard move with scrollIntoView({ block: "nearest" }); a highlight assigned while the popup is opening scrolls the popup itself, since floating-ui renders at the document origin before measuring'],focusManagement:`${u} Here the anchor is the Input, a textarea whose caret offset is part of the interaction: the popup must never take focus, and pointer interactions inside Content cancel their own mousedown so both DOM focus and the text selection survive a click. When filtering removes the highlighted item the highlight moves to the first survivor rather than disappearing, and aria-activedescendant is dropped only when no item is left. Inserting a mention puts the caret just past the inserted text \u2014 past the appended space where one was added \u2014 and the adapter sets it in the same task as the value write, so the field never flashes the caret at the end of the value. Blur closes the popup and inserts nothing: an unconfirmed mention is just the text the user typed.`,namingRequirement:"The Input must be named by a <label>, aria-label, or aria-labelledby; a textbox takes no name from its content, and Content is a sibling rather than an ancestor. Wrapping the field in the Field family satisfies this automatically. A placeholder is not a name \u2014 it disappears as soon as the field has text."},styling:{cssParts:["input","content","item","empty"],dataAttributes:[...c,"data-state","data-side","data-align","data-trigger","data-highlighted","data-disabled","data-readonly","data-invalid","data-loading","data-value",{name:"data-skdx-mentions-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:d("mentions")},publicMethods:[...i,r,{name:"focus",signature:"(): void",description:"Moves keyboard focus to the text field, which is where this component keeps real DOM focus.",frameworks:["vue","webComponents"],exception:"element-handoff",frameworksReason:"Vue hides the Input inside the root component instance, and the custom element forwards focus() to its shadow textarea. React, Svelte and Angular hand the consumer the Input element itself."}]};export{w as mentionsContract};
@@ -0,0 +1,3 @@
1
+ import { type ComponentContract } from './types.js';
2
+ /** The Menu contract: a button-triggered WAI-ARIA menu with floating-ui positioning and roving-focus/typeahead navigation. */
3
+ export declare const menuContract: ComponentContract;
@@ -0,0 +1 @@
1
+ import{changeDetail as a}from"./change-reason.js";import{arrowPart as o,closeAutoFocusEvent as i,dismissalEvents as r,forceMountProp as n,menuSubParts as s,openChangeCompleteEvent as l,popperContentProps as d,popperMeasurementProperties as h,portalPart as c,shortcutPart as u,textValueProp as t}from"./overlay-parts.js";import{PART_DATA_ATTRIBUTES as p}from"./styling-hooks.js";import{withoutScope as m}from"./types.js";var w={name:"Menu",purpose:'An accessible menu of actions, opened by a trigger button and positioned via floating-ui (side/align/collision avoidance) or \u2014 under openOn="contextmenu" \u2014 opened by right-click or long-press at the pointer and clamped to the viewport. Full arrow-key/typeahead navigation, nested submenus, and checkbox/radio item support throughout. Composed of a root plus Trigger, Portal, Content, Arrow, Item, CheckboxItem, RadioGroup, RadioItem, ItemIndicator, Group, Label, Separator, and Sub/SubTrigger/SubContent parts.',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. Under openOn="contextmenu" with no point set and no pointer event to place the panel at, it opens at the default (0, 0) point \u2014 clamped to the top-left of the viewport by collisionPadding \u2014 so pair it with point to open somewhere meaningful.'},{name:"openOn",type:"'click' | 'contextmenu'",defaultValue:"'click'",required:!1,description:'Which gesture opens the menu. "click" anchors Content to the Trigger button and honours side, align and the offsets. "contextmenu" turns the Trigger into a right-clickable region: right-click or a 500ms long-press opens Content at the pointer (or at point) with the native browser menu suppressed, the panel is clamped by collisionPadding instead of anchored, side/align/sideOffset/alignOffset are ignored, and modal defaults to false.'},{name:"point",type:"{ x: number; y: number }",required:!1,description:'Viewport coordinates for Content placement under openOn="contextmenu", overriding the pointer position so a programmatic open (defaultOpen, controlled, a custom gesture) lands somewhere meaningful. Still clamped by collisionPadding, and ignored under openOn="click". Property-only on Web Components \u2014 a pair of numbers, not a string.'},{name:"modal",type:"boolean",defaultValue:"true",required:!1,description:'Whether the open menu takes the page out of use: everything outside its portal is marked inert and body scroll is locked, on the same reference-counted mechanism as Dialog and Drawer. Set false to leave the page interactive. Tab closes the menu per WAI-ARIA, not trapped in either mode. Defaults to true under openOn="click" and to false under openOn="contextmenu", where the region the menu was invoked from is usually still the thing being worked on.'},{name:"closeOnSelect",type:"boolean",defaultValue:"true",required:!1,description:"Whether selecting an item closes the menu. Default inherited by Item/RadioItem but not CheckboxItem (which toggles and stays open by default). Independent of select event preventDefault; either veto is enough."},{name:"trigger",type:"ReactElement | Snippet | TemplateRef<unknown>",required:!1,frameworks:["react","svelte","angular"],exception:"render-prop",frameworksReason:`React, Svelte and Angular all take this as a typed prop. Vue takes the identical content through its named #trigger slot and Web Components through light-DOM children marked slot="trigger", neither of which is a declared prop an extractor can see; see the trigger slot entry below for that half. Only in React is the derived trigger a whole interactive element, merged onto the consumer's own via asChild; the other four render their own button and take this as only that button's inner content.`,description:"Trigger for the derived anatomy; none rendered if omitted. Content model differs by package: React is a whole interactive element (via asChild); Svelte/Angular supply inner content of a button the recipe renders."},{name:"items",type:"MenuEntry[]",required:!1,description:"Entries the derived menu renders: Item, Separator, CheckboxItem, RadioGroup, Sub, or Group; recursive for submenus. Supplying it draws the whole anatomy from data; manual composition uses primitives/menu and is the only route to per-item closeOnSelect."},{name:"disabled",type:"boolean",defaultValue:"false",required:!1,description:`Disables the trigger, forwarded to the derived Trigger's own disabled prop. Under openOn="contextmenu" this stands the right-clickable region down and lets the native browser menu through.`},{name:"side",type:"'top' | 'right' | 'bottom' | 'left' | 'start' | 'end'",defaultValue:"'bottom'",required:!1,description:`Which side of the trigger the derived menu opens on \u2014 forwarded to the underlying Content part. Set Content's own side directly under full manual composition. Ignored under openOn="contextmenu", where the panel sits at the pointer and has no anchor to take a side of.`},{name:"align",type:"'start' | 'center' | 'end'",defaultValue:"'start'",required:!1,description:'Alignment of the derived menu along side \u2014 forwarded to the underlying Content part, and start rather than center because a menu panel lines up with the edge of its trigger. Ignored under openOn="contextmenu", for the same reason side is.'},{name:"renderItem",type:"(item: MenuEntry) => React.ReactNode",required:!1,frameworks:["react","svelte","angular"],exception:"render-prop",frameworksReason:`Vue expresses the same customisation as a scoped #item slot and Web Components as a light-DOM slot="item" child keyed by data-value \u2014 each framework's own idiomatic mechanism for the hook, and neither a declared prop an extractor can see. Web Components additionally has no property-only equivalent, since an HTML attribute cannot carry a function; a Web Components entry with no matching slotted node falls back to its plain label, which is what the other ports render when their hook returns nothing. Angular ships the same name as a TemplateRef input.`,description:"Customises what renders *inside* a derived item, not the item itself: role, id, attributes, keyboard, and disabled state stay the library's. Never called for radio options ({ label, value }). Only read while items derives anatomy."},{name:"size",type:"'sm' | 'lg' | (string & {})",required:!1,description:"Size rung forwarded to Content's and SubContent's data-size; the attribute may be written on either part directly instead."}],events:[{name:"open-change",detail:"boolean",description:"Fired with the new open state whenever it changes, controlled or not."},l("menu"),...r("menu"),i("menu"),{name:"select",detail:"MenuEntry | null",description:"Fired by an Item/CheckboxItem/RadioItem when activated. Preventing default keeps the menu open. Under the derived anatomy the root re-fires it carrying the MenuEntry entry that was activated, and only for a plain or checkbox entry: a radio pick reports through its own radio-group entry's onValueChange, because the payload is typed as the item model and a radio option ({ label, value }) is not one. The entry's own onSelect runs first and the root's after it; neither cancels the other."},{name:"item-select",frameworks:["webComponents"],exception:"event-shape",frameworksReason:"React, Vue, Svelte and Angular spell the recipe-level callback select (onSelect / @select / (select)) on the root. <skdx-menu> cannot: its Item part already dispatches a bubbling select through the same host with a different detail, and two same-named events carrying different payloads on one node is a real ambiguity rather than a naming preference, so the recipe's is renamed here alone.",description:"Recipe-level select \u2014 dispatched with the MenuEntry entry that was activated, for plain and checkbox entries only.",detail:"MenuEntry"},{name:"checked-change",detail:"boolean",description:"Fired by a CheckboxItem with the new checked state when selected."},{name:"value-change",detail:a("string"),description:"Fired by a RadioGroup with a RadioItem's value when it is selected."}],parts:[{name:"Trigger",description:'The button that opens the menu and anchors its position. Under openOn="contextmenu" it is instead a focusable region (role="group", tabindex="0") that opens the panel at the pointer on right-click or on a 500ms touch long-press, suppressing the native browser menu; moving more than 10px, lifting the finger, or a browser cancel disarms the press, and touch-action: none applies only while armed so the region scrolls normally.',props:[{name:"disabled",type:"boolean",defaultValue:"false",required:!1,description:'Stands the trigger down so it opens nothing. Under openOn="contextmenu" the native browser context menu is let through instead.'}]},c,{name:"Content",description:`The floating menu panel (role="menu"). Owns positioning, roving focus, and the dismissal interceptors the root declares as escape-key-down / pointer-down-outside / focus-outside / interact-outside. Under openOn="contextmenu" it is placed at the pointer (or at the root's point) and clamped to the viewport by collisionPadding, and its side, align, sideOffset and alignOffset props go unread \u2014 there is no anchor element to position against.`,props:[...d({align:"'start'"}),n,{name:"loop",type:"boolean",defaultValue:"true",required:!1,description:"Whether Up/Down navigation wraps from the last item back to the first."},{name:"size",type:"'sm' | '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."}]},o,{name:"Item",description:'One actionable entry (role="menuitem"). Selecting it fires select and closes the menu unless the handler prevents default or closeOnSelect is false.',props:[{name:"as",type:"PolymorphicTag",defaultValue:"'div'",required:!1,frameworks:["react","vue","svelte","webComponents"],exception:"as-directive",frameworksReason:"Angular has no `as` input. Its element-choice mechanism is an attribute directive the consumer puts on their own element \u2014 `<section skdx-ng-card>` \u2014 which is the same capability spelled the way Angular's template compiler already reads, and eleven such directives predate this one.",description:"Element name to render instead of the default <div>, from the closed allowlist in POLYMORPHIC_TAGS. A tag name only, never a component: the list has to be closed for Lit, which needs a static-html literal per tag and cannot build one from a runtime string. React additionally reaches this through asChild, which takes a component and wins when both are set."},{name:"disabled",type:"boolean",defaultValue:"false",required:!1,description:"Marks the item aria-disabled and blocks selection. The item stays in the roving order and remains focusable, so it is discoverable rather than invisible."},{name:"closeOnSelect",type:"boolean",required:!1,description:"Whether selecting this item closes the menu, overriding the root's closeOnSelect for this item alone. Unset, it inherits the root's value (true by default). Independent of the select event's preventDefault, which keeps the menu open for one activation."},{name:"href",type:"string",required:!1,frameworks:["svelte","webComponents"],exception:"attribute-passthrough",frameworksReason:"React and Vue take href as a plain attribute on the element `as` chose, and Angular puts its item directive on an <a href> the consumer wrote, so none of the three needs a declared member. Svelte and Web Components render the anchor themselves \u2014 Web Components inside a shadow root the attribute cannot reach \u2014 so the value has to arrive as a declared property.",description:'URL for an item that navigates, applied to the anchor the item renders when `as` is "a". Web Components additionally withholds it while the item is disabled, so a disabled entry is not still a working link.'},t]},{name:"CheckboxItem",description:'Toggleable item (role="menuitemcheckbox") whose aria-checked and data-state mirror its checked state. Selecting it reports through checked-change and leaves the menu open unless closeOnSelect says otherwise. Wrap an ItemIndicator for a checked-only glyph.',props:[{name:"checked",type:"boolean",defaultValue:"false",required:!1,description:"The checked state, always externally controlled: the item reports the state it wants through checked-change and never flips itself."},{name:"disabled",type:"boolean",defaultValue:"false",required:!1,description:"Marks the item aria-disabled and blocks selection. The item stays in the roving order and remains focusable, so it is discoverable rather than invisible."},{name:"closeOnSelect",type:"boolean",defaultValue:"false",required:!1,description:"Whether selecting this item closes the menu. Unlike Item and RadioItem this does not inherit the root's closeOnSelect: a checkbox item exists to be toggled, often more than once in a visit, so it stays open unless asked otherwise. Set it true to opt this item into closing."},t]},{name:"RadioGroup",description:'Coordinates a set of mutually-exclusive RadioItems (role="group"), holding the selected value and reporting a new one through value-change. Named by a Label rendered inside it on exactly the same wiring as Group, which it also shadows: a Label inside a RadioGroup nested in a Group names the RadioGroup, not the outer Group.',props:[{name:"value",type:"string",required:!1,description:"The selected RadioItem's value, always externally controlled. Pair with the value-change event."}]},{name:"RadioItem",description:`A single option inside a RadioGroup (role="menuitemradio") whose aria-checked and data-state (checked/unchecked) reflect whether its value matches the group's selected value. Selecting it reports the group's new value through the value-change event and closes the menu. Wrap an ItemIndicator inside it for a glyph shown only while selected.`,props:[{name:"value",type:"string",required:!0,description:"This option's value. Compared against the enclosing RadioGroup's value to decide checked state, and reported through value-change when the option is selected."},{name:"disabled",type:"boolean",defaultValue:"false",required:!1,description:"Marks the item aria-disabled and blocks selection. The item stays in the roving order and remains focusable, so it is discoverable rather than invisible."},{name:"closeOnSelect",type:"boolean",required:!1,description:"Whether selecting this item closes the menu, overriding the root's closeOnSelect for this item alone. Unset, it inherits the root's value (true by default). Independent of the select event's preventDefault, which keeps the menu open for one activation."},t]},{name:"ItemIndicator",description:"The checked-state glyph inside a CheckboxItem or RadioItem, rendered only when checked.",props:[m(n)]},{name:"Group",description:'Groups related items (role="group"). A Label rendered inside it names it: the Group generates an id, gives it to the Label it contains, and points its own aria-labelledby at it \u2014 so the group announces as "Actions, group" rather than as an unnamed one. The attribute is emitted only while a Label is actually there, because a dangling IDREF is a broken relationship rather than a weaker one, and an author-supplied aria-label or aria-labelledby wins over the generated link. A Label rendered outside a Group (the flat "heading then items" arrangement) still renders and still names nothing.'},{name:"Label",description:"A non-interactive heading for a Group \u2014 not itself a menu item and never focusable. Inside a Group or RadioGroup it takes the id that group points aria-labelledby at, which is the only way either of them gets an accessible name; outside one it is presentational text."},{name:"Separator",description:'A horizontal rule between item groups (role="separator", aria-orientation="horizontal").'},u,...s().map(e=>e.name==="SubContent"?{...e,props:[...e.props??[],{name:"size",type:"'sm' | 'lg' | (string & {})",required:!1,description:"Visual size rung, written to data-size on the submenu panel; the data-size attribute may be set directly instead."}]}:e)],slots:[{name:"trigger",description:`Trigger's content \u2014 the button that opens the menu and anchors its position, or under openOn="contextmenu" the right-clickable region, which is itself a tab stop so Shift+F10 and the Menu key can reach it.`},{name:"default",description:"Content's body \u2014 Item/CheckboxItem/RadioGroup/Group/Label/Separator entries."}],appearance:[{attribute:"data-size",values:["sm","lg"],stylesheet:"menu.css"}],states:["closed","open","checked","unchecked","disabled"],controlledUncontrolled:"Stateless by default (uncontrolled): starts at defaultOpen and manages its own state internally. Passing open switches to controlled. CheckboxItem checked and RadioGroup value are always externally controlled (no internal state).",formBehavior:'Not applicable \u2014 Menu participates in no form; Trigger is type="button".',validationBehavior:"Not applicable.",accessibility:{role:'menu (Content), menuitem (Item), menuitemcheckbox (CheckboxItem), menuitemradio (RadioItem), group (Group/RadioGroup), separator (Separator); under openOn="contextmenu" the Trigger is a group rather than a button \u2014 the neutral container role, claiming no widget behaviour the region does not implement and, unlike button, not making its arbitrary wrapped content presentational',keyboard:[{key:"Enter / Space / ArrowDown",behavior:"Opens the trigger and moves focus to the first item."},{key:"Shift+F10 / Menu key (on Trigger)",behavior:`Under openOn="contextmenu", opens Content at the Trigger's own box and moves focus to the first item \u2014 the keyboard equivalent of right-clicking, since the browser fires contextmenu for these keys only on the focused element.`},{key:"ArrowUp (on Trigger)",behavior:"Opens the trigger and moves focus to the *last* item, so a user reaching upward for the bottom of the menu gets there in one keystroke."},{key:"ArrowUp / ArrowDown",behavior:"Moves focus between items, wrapping unless loop is false."},{key:"Home / End",behavior:"Jumps focus to the first/last item."},{key:"Typing a letter",behavior:"Jumps focus to the next item matching that text (typeahead)."},{key:"Enter / Space (on an item)",behavior:"Selects the focused item."},{key:"Escape",behavior:"Requests close (cancelable via escape-key-down), refocuses Trigger."},{key:"Alt+ArrowUp (inside the menu)",behavior:"Closes the menu and returns focus to Trigger, the mirror of the Alt+ArrowDown/ArrowDown that opened it. Unlike Escape it is not cancelable \u2014 it is a navigation key, not a dismissal \u2014 and the plain ArrowUp meaning above applies only without the modifier."},{key:"Tab",behavior:"Closes the menu and returns focus to Trigger; the key is not consumed, so the browser then continues the tab sequence from the Trigger \u2014 to the next tabbable element after it, or the previous one under Shift+Tab. Per the WAI-ARIA menu pattern, Tab moves focus out of a menu rather than being trapped by it."},{key:"ArrowRight (on a SubTrigger)",behavior:'Opens the submenu and moves focus to its first item. Mirrored to ArrowLeft under dir="rtl", in all five packages.'},{key:"ArrowLeft (inside a SubContent)",behavior:'Closes the submenu and returns focus to its SubTrigger, leaving the parent menu open. Mirrored to ArrowRight under dir="rtl", in all five packages.'},{key:"Escape (inside a SubContent)",behavior:"Closes only the submenu and returns focus to its SubTrigger."}],ariaAttributes:['aria-haspopup="menu", aria-expanded, and aria-controls on Trigger',`Under openOn="contextmenu" the Trigger carries tabindex="0", role="group", and \u2014 whenever the panel is mounted \u2014 aria-controls plus aria-owns naming it, and deliberately no aria-expanded and no aria-haspopup: role="group" supports neither. aria-expanded is absent from group's supported *and* inherited lists in ARIA 1.2 and in the 1.3 editor's draft alike, and aria-haspopup is inherited there only as "deprecated on this role in ARIA 1.2". aria-owns is the supported substitute \u2014 it places the open panel inside the region in the accessibility tree \u2014 and the open/closed state is announced a second way by focus moving into a role="menu" named after the region and back out again. Neither attribute is emitted while the panel is absent from the DOM: a dangling IDREF is a broken relationship rather than a weaker one. Where the closed panel stays mounted but hidden, the Trigger keeps aria-controls published throughout.`,'aria-haspopup="menu", aria-expanded, and aria-controls on SubTrigger, which is itself a role="menuitem" in the parent menu',`Content's id matches Trigger's aria-controls; aria-orientation="vertical" on Content`,`Content's aria-labelledby points back at Trigger's id, and SubContent's at its SubTrigger's id \u2014 a role="menu" takes no name from its own items, so without this every panel announces as a bare "menu". An author-supplied aria-label wins: the default is only emitted when none is set.`,"aria-checked on CheckboxItem/RadioItem reflecting checked state","aria-disabled and data-disabled on a disabled item, which stays reachable by the arrow keys and typeahead \u2014 APG keeps a disabled menu item focusable so it is discoverable \u2014 but cannot be selected",'aria-labelledby on Group and RadioGroup pointing at the id of the Label they contain, and emitted only while that Label is in the DOM \u2014 a role="group" takes no name from its own items, so an unnamed one announces as a bare "group". An author-supplied aria-label or aria-labelledby wins.'],focusManagement:`Roving DOM focus, not virtual, and a popup in front of a trigger does not change that: the collection-focus rule reaches for virtual focus only when a text input or a role="combobox" element has to keep DOM focus, and a menu trigger has neither obligation \u2014 APG's menu pattern moves real focus into the menu, so the item under the arrow keys is the element assistive technology reports as focused. Focus moves into the open menu \u2014 the first item, or the last when ArrowUp on the Trigger opened it \u2014 and returns to Trigger when closed via Escape/Tab/an item selection. Tab additionally leaves its default action intact, so focus continues out of the Trigger into the page tab sequence rather than resting on it. Under openOn='contextmenu' the entry gesture differs and the rest does not: right-click suppresses the native browser menu and opens Content at the pointer with focus on the first item, a 500ms touch long-press does the same at the pressed coordinates, and Shift+F10 or the Menu key on the focused Trigger region does it at the region's own box. Opening a submenu by keyboard or click moves focus to its first item; closing it returns focus to its SubTrigger. Hover-opening a submenu does not move focus, and pointer-leaving both SubTrigger and SubContent closes it after a short grace delay. While a submenu is hover-open and focus is still on its SubTrigger, the parent panel's own arrow keys move only among the parent's own items, never into the submenu. While modal (the default) everything outside the menu's portal container is inert and body scroll is locked for the menu's lifetime, so the page behind it is out of reach of pointer, keyboard and assistive technology alike; the inertness is lifted before focus is handed back, so Escape, Tab and selecting an item still land on the Trigger. An Item must not contain its own interactive elements \u2014 no button, link, checkbox or input inside a menuitem. The roving-focus layer moves DOM focus to the [role^=menuitem] elements and to nothing inside them, so a nested control is unreachable by the arrow keys and reachable by Tab only for the instant before Tab closes the menu; a screen reader meanwhile reads the control's own name as part of the item's. Where a row needs two actions, use two items.`},styling:{cssParts:["trigger","content","arrow","item","group","separator","label","checkbox-item","radio-group","radio-item","item-indicator","shortcut","sub-trigger","sub-content"],dataAttributes:[...p,"data-state","data-side","data-align","data-disabled","data-text-value","data-size",{name:"data-skdx-menu-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:h("menu")},publicMethods:[]};export{w as menuContract};
@@ -0,0 +1,3 @@
1
+ import { type ComponentContract } from './types.js';
2
+ /** The Menubar contract: an application-style row of triggers, each opening a WAI-ARIA menu positioned via floating-ui. */
3
+ export declare const menubarContract: ComponentContract;
@@ -0,0 +1 @@
1
+ import{changeDetail as a}from"./change-reason.js";import{arrowPart as n,closeAutoFocusEvent as r,dismissalEvents as o,forceMountProp as t,menuSubParts as i,openChangeCompleteEvent as s,popperContentProps as l,popperMeasurementProperties as d,portalPart as u,shortcutPart as c,textValueProp as e}from"./overlay-parts.js";import{ROOT_DATA_ATTRIBUTES as m}from"./styling-hooks.js";import{withoutScope as p}from"./types.js";var y={name:"Menubar",purpose:"A WAI-ARIA menu bar: triggers in roving-focus rows, each opening a floating-positioned menu. Switches between menus by hover/focus once one is open, matching native desktop menu bars.",props:[{name:"menu",type:"string",required:!1,description:"Controlled currently-open menu. Pair with menu-change. Named menu (not value) since menu state is not a selection and differs semantically from RadioGroup's value-change."},{name:"defaultMenu",type:"string",defaultValue:"''",required:!1,description:"Initially open menu's value, for uncontrolled usage."},{name:"orientation",type:"'horizontal' | 'vertical'",defaultValue:"'horizontal'",required:!1,description:"Axis triggers lay out on, reflected as aria-orientation. Horizontal roves with ArrowLeft/ArrowRight, vertical with ArrowUp/ArrowDown. Open menus stay vertical either way."},{name:"loop",type:"boolean",defaultValue:"true",required:!1,description:"Whether trigger focus wraps at the ends. Between-menu navigation always wraps."},{name:"menus",type:"{ label: string; items: MenuEntry[]; value?: string; disabled?: boolean }[]",required:!1,description:"Data array for derived anatomy: one Menu/Trigger/Portal/Content per entry. label is trigger text, value its identifier (defaults to index), disabled the Trigger's state."},{name:"renderItem",type:"(item: MenuEntry) => React.ReactNode",required:!1,frameworks:["react","svelte","angular"],exception:"render-prop",frameworksReason:`Vue uses a scoped #item slot, Web Components a light-DOM slot="item" child, Angular a TemplateRef input \u2014 each framework's idiomatic hook. When no slot is filled, it falls back to the plain label.`,description:"Customizes item content only, never the item's role/id/data attributes. Skipped for radio options, only used during derived anatomy render."},{name:"density",type:"'compact' | 'comfortable' | (string & {})",required:!1,description:"Vertical rhythm rung, written to data-density on the root; the data-density attribute may be set directly instead."},{name:"size",type:"'sm' | 'md' | 'lg' | (string & {})",required:!1,description:"Visual size rung, written to data-size on the root; the data-size attribute may be set directly instead."}],events:[{name:"menu-change",detail:"string",description:"Fired with the open menu value (or an empty string when closed), always. Distinct from RadioGroup value-change so listeners can tell the two apart."},...o("menu"),r("menu"),{name:"select",detail:"MenuEntry | null",description:"Fired when Item/CheckboxItem/RadioItem is activated; preventDefault keeps menu open. Radio picks report via RadioGroup.value-change instead. In derived anatomy, root re-fires with the MenuEntry."},{name:"item-select",frameworks:["webComponents"],exception:"event-shape",frameworksReason:"Other frameworks use select with different payloads causing ambiguity. <skdx-menubar> renames it to item-select to disambiguate.",description:"Recipe-level select \u2014 dispatched with MenuEntry for plain and checkbox entries only.",detail:"MenuEntry"},{name:"checked-change",detail:"boolean",description:"Fired by a CheckboxItem with the new checked state when selected."}],parts:[{name:"Menu",description:"One top-level entry: a Trigger paired with Portal/Content.",props:[{name:"value",type:"string",required:!0,description:"This menu's identifier. Required \u2014 the root addresses menus by value and needs a stable key."}],events:[s("menu")]},{name:"Trigger",description:"A top-level menu's button. Opens its menu on click, hover once any menu is open.",props:[{name:"disabled",type:"boolean",defaultValue:"false",required:!1,description:"Blocks menu opening, data-disabled reflection. React uses native passthrough; Vue/Svelte/Angular/Web Components declare it explicitly."}]},u,{name:"Content",description:'The floating menu panel (role="menu"): positioning, roving focus, dismissal.',props:[...l({align:"'start'"}),t,{name:"loop",type:"boolean",defaultValue:"true",required:!1,description:"Whether Up/Down navigation wraps at the ends."}]},n,{name:"Item",description:'An actionable menu entry (role="menuitem"): fires select, closes menu unless prevented.',props:[{name:"as",type:"PolymorphicTag",defaultValue:"'div'",required:!1,frameworks:["react","vue","svelte","webComponents"],exception:"as-directive",frameworksReason:"Angular has no `as` input. Its element-choice mechanism is an attribute directive the consumer puts on their own element \u2014 `<section skdx-ng-card>` \u2014 which is the same capability spelled the way Angular's template compiler already reads, and eleven such directives predate this one.",description:"Element name to render instead of the default <div>, from the closed allowlist in POLYMORPHIC_TAGS. A tag name only, never a component: the list has to be closed for Lit, which needs a static-html literal per tag and cannot build one from a runtime string. React additionally reaches this through asChild, which takes a component and wins when both are set."},{name:"disabled",type:"boolean",defaultValue:"false",required:!1,description:"Marks aria-disabled, blocks selection. Stays focusable in roving order for discoverability."},{name:"closeOnSelect",type:"boolean",defaultValue:"true",required:!1,description:"Whether selecting this item closes the menu. Independent of the select event's preventDefault, which keeps the menu open for one activation alone."},e]},{name:"CheckboxItem",description:'A toggleable item (role="menuitemcheckbox"): aria-checked/data-state mirror checked. Reports new state via checked-change; wrap ItemIndicator for checked glyph.',props:[{name:"checked",type:"boolean",defaultValue:"false",required:!1,description:"Externally controlled checked state. Item reports via checked-change, never toggles itself."},{name:"disabled",type:"boolean",defaultValue:"false",required:!1,description:"Marks aria-disabled, blocks selection. Stays focusable in roving order for discoverability."},e]},{name:"RadioGroup",description:"Mutually-exclusive RadioItems. Emits value-change \u2014 distinct from root's menu-change.",props:[{name:"value",type:"string",required:!1,description:"Selected RadioItem's value, externally controlled. Pair with this part's value-change."}],events:[{name:"value-change",description:"Fired with selected RadioItem's value.",detail:a("string")}]},{name:"RadioItem",description:'A RadioGroup option (role="menuitemradio"): aria-checked/data-state reflect group selection. Wrap ItemIndicator for selected glyph.',props:[{name:"value",type:"string",required:!0,description:"This option's value. Compared against group's value for checked state, reported via group's value-change when selected."},{name:"disabled",type:"boolean",defaultValue:"false",required:!1,description:"Marks aria-disabled, blocks selection. Stays focusable in roving order for discoverability."},e]},{name:"ItemIndicator",description:"Checked-state glyph in CheckboxItem or RadioItem, rendered only when checked.",props:[p(t)]},{name:"Group",description:'Groups related items (role="group"). Interior Label names it via aria-labelledby. Group generates id, gives to Label, points aria-labelledby at it. Consumer aria-label/aria-labelledby wins over generated link.'},{name:"Label",description:"Non-interactive heading for a Group or RadioGroup, providing their accessible name via aria-labelledby. Presentational text outside a group."},{name:"Separator",description:'A horizontal rule between item groups (role="separator", aria-orientation="horizontal").'},c,...i()],slots:[{name:"default",description:'Root content \u2014 one Menu per top-level entry (e.g. "File", "Edit").'}],appearance:[{attribute:"data-density",values:["compact","comfortable"],stylesheet:"menubar.css"},{attribute:"data-size",values:["sm","md","lg"],stylesheet:"menubar.css"}],states:["closed","open","checked","unchecked","disabled"],controlledUncontrolled:"Stateless by default (uncontrolled): starts at defaultMenu and manages which menu is open internally. Passing menu switches to controlled. CheckboxItem checked and RadioGroup value are always externally controlled.",formBehavior:'Not applicable \u2014 Menubar participates in no form; triggers are type="button".',validationBehavior:"Not applicable.",accessibility:{role:"menubar (root), menuitem (Trigger, Item), menuitemcheckbox (CheckboxItem), menuitemradio (RadioItem), menu (Content), group (Group/RadioGroup), separator (Separator)",keyboard:[{key:"ArrowLeft / ArrowRight",behavior:"Moves focus between triggers, wrapping unless loop is false, and switches the open menu if one is already open. ArrowUp/ArrowDown take this role instead when orientation is vertical."},{key:"Home / End",behavior:"Jumps focus to the first/last trigger."},{key:"Typing a letter",behavior:"Jumps focus to the next trigger matching that text (typeahead)."},{key:"Enter / Space / ArrowDown (on a trigger)",behavior:"Opens that trigger's menu and moves focus to its first item."},{key:"ArrowUp (on a trigger)",behavior:"Opens that trigger's menu and moves focus to its *last* item, APG's optional Up Arrow rule. In a vertical bar the key roves between triggers instead, and only Enter/Space/ArrowRight open a menu."},{key:"ArrowUp / ArrowDown (within an open menu)",behavior:"Moves focus between items, wrapping unless loop is false."},{key:"ArrowRight / ArrowLeft (on an item with no submenu)",behavior:`Closes the current menu and opens the adjacent one, wrapping: focus moves to that menu's trigger and then to its panel's first item. Mirrored under dir="rtl", where ArrowLeft moves to the next menu and ArrowRight to the previous. An item that *does* have a submenu keeps the submenu meaning below.`},{key:"Enter / Space (on an item)",behavior:"Selects the focused item."},{key:"Escape",behavior:"Requests close (cancelable via escape-key-down), refocuses the trigger."},{key:"Tab",behavior:"Closes every open menu and submenu and returns focus to the trigger, which restores the bar to its single tab stop; the key is not consumed, so focus continues out of the bar to the next element in the page tab sequence, per the WAI-ARIA menu pattern."},{key:"ArrowRight (on a SubTrigger)",behavior:'Opens the submenu and moves focus to its first item \u2014 it does not move to the next menubar trigger. Mirrored to ArrowLeft under dir="rtl", in all five packages.'},{key:"ArrowLeft (inside a SubContent)",behavior:'Closes the submenu and returns focus to its SubTrigger, leaving the parent menu open. Mirrored to ArrowRight under dir="rtl", in all five packages.'},{key:"Escape (inside a SubContent)",behavior:"Closes only the submenu and returns focus to its SubTrigger."}],ariaAttributes:['role="menubar" on the root','aria-orientation on the root, mirroring the orientation prop \u2014 "horizontal" by default, and the only way a vertical bar tells assistive technology which arrows move along it','aria-label or aria-labelledby on the root, supplied by the consumer \u2014 a menubar takes no name from its menuitem children, so an unnamed one announces as a bare "menu bar" and two on a page are indistinguishable. No prop is needed: passthrough already carries both.',"aria-labelledby on Content pointing at its Trigger's id, and on SubContent pointing at its SubTrigger's id \u2014 APG requires a menu to name itself after the control that opens it. An author-supplied aria-label wins: the default is only emitted when none is set.",'aria-haspopup="menu", aria-expanded, and aria-controls on SubTrigger, which is itself a role="menuitem" in the menu that contains it','aria-haspopup="menu", aria-expanded, and aria-controls on each Trigger',`a menu's Content id matches its Trigger's aria-controls; aria-orientation="vertical" on Content`,"aria-checked on CheckboxItem/RadioItem reflecting checked state","aria-disabled and data-disabled on a disabled item, which stays reachable by the arrow keys and typeahead \u2014 APG keeps a disabled menu item focusable so it is discoverable \u2014 but cannot be selected, and on a disabled Trigger, which is skipped by the bar's own roving focus and cannot open its menu",`aria-labelledby on Group and RadioGroup pointing at the id of the Label they contain, and emitted only while that Label is in the DOM \u2014 a role="group" takes no name from its own items, so an unnamed one announces as a bare "group". Identical wiring to Menu's, and an author-supplied aria-label or aria-labelledby wins over it.`],focusManagement:"Single tab stop into the menubar (roving tabindex across triggers). Opening a menu moves focus to its first item \u2014 to its *last* item when ArrowUp opened it from the trigger of a horizontal bar; closing via Escape/Tab/an item selection returns focus to that menu's trigger. Hovering or focusing a sibling trigger while any menu is open switches which one is open. Opening a submenu by keyboard or click moves focus to its first item; closing it returns focus to its SubTrigger. Hover-opening a submenu does not move focus, and pointer-leaving both SubTrigger and SubContent closes it after a short grace delay. While a submenu is hover-open and focus is still on its SubTrigger, the parent panel's own arrow keys move only among the parent's own items, never into the submenu. An Item must not contain its own interactive elements \u2014 no button, link, checkbox or input inside a menuitem. The roving-focus layer moves DOM focus to the [role^=menuitem] elements and to nothing inside them, so a nested control is unreachable by the arrow keys and reachable by Tab only for the instant before Tab closes the menu; a screen reader meanwhile reads the control's own name as part of the item's. Where a row needs two actions, use two items."},styling:{cssParts:["trigger","content","arrow","item","group","separator","root","label","checkbox-item","radio-group","radio-item","item-indicator","shortcut","sub-trigger","sub-content"],dataAttributes:[...m,"data-state","data-side","data-align","data-disabled","data-skdx-menubar-trigger","data-text-value","data-density","data-size",{name:"data-skdx-menubar-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:d("menubar")},publicMethods:[]};export{y as menubarContract};
@@ -0,0 +1,6 @@
1
+ import { type ComponentContract } from './types.js';
2
+ /**
3
+ * Hover/click-driven navigation menu with delayed open and instant sibling
4
+ * switching within a skip window.
5
+ */
6
+ export declare const navigationMenuContract: ComponentContract;
@@ -0,0 +1 @@
1
+ import{changeDetail as n}from"./change-reason.js";import{forceMountProp as e}from"./overlay-parts.js";import{ROOT_DATA_ATTRIBUTES as a}from"./styling-hooks.js";import{withoutScope as t}from"./types.js";var l={name:"NavigationMenu",purpose:"A hover/click-driven navigation menu. The root owns which item is open and hands hover-intent timers to its items.",props:[{name:"value",type:"string | null",defaultValue:"null",required:!1,description:"Value of the currently open item, for controlled usage. `null` means nothing is open."},{name:"defaultValue",type:"string | null",defaultValue:"null",required:!1,description:"Initially open item value, for uncontrolled usage. `null` (the default) starts closed."},{name:"delayDuration",type:"number",defaultValue:"200",required:!1,description:"Delay before hovering a trigger opens its content (ms)."},{name:"skipDelayDuration",type:"number",defaultValue:"300",required:!1,description:"Window after closing during which re-hovering a sibling trigger opens instantly (ms)."},{name:"closeDelayDuration",type:"number",defaultValue:"150",required:!1,description:"Grace period after pointer leaves trigger or panel before close (ms)."},{name:"closeOnSelect",type:"boolean",defaultValue:"true",required:!1,description:"Whether Link activation closes the panel."},{name:"orientation",type:"'horizontal' | 'vertical'",defaultValue:"'horizontal'",required:!1,description:"Axis the menu runs along. Sets data-orientation on the root and the list, and switches roving focus between Left/Right and Up/Down."},{name:"items",type:"NavigationMenuItem[]",required:!1,description:"Menu entries the root derives; omit to hand-compose."},{name:"renderItem",type:"(item: NavigationMenuItem) => React.ReactNode",required:!1,frameworks:["react","svelte","angular"],exception:"render-prop",frameworksReason:`Vue expresses the same customisation as a scoped #item slot and Web Components as a light-DOM slot="item" child keyed by data-value \u2014 each framework's own idiomatic mechanism for the hook, and neither a declared prop an extractor can see. Web Components additionally has no property-only equivalent, since an HTML attribute cannot carry a function; a Web Components entry with no matching slotted node falls back to its plain label, which is what the other ports render when their hook returns nothing. Angular ships the same name as a TemplateRef input.`,description:"Customize what renders inside derived entry (trigger body, link content)."}],events:[{name:"value-change",detail:n("string | null"),description:"Fires with the new open value whenever it changes, and with `null` when everything closes."}],parts:[{name:"List",description:"The top-level `<ul>` of triggers and links, and the roving-focus ring the arrow keys move within.",props:[{name:"loop",type:"boolean",defaultValue:"true",required:!1,description:"Whether the arrow keys wrap from the last top-level item back to the first, and vice versa."}]},{name:"Item",description:"One top-level entry, pairing a Trigger and Content (or a bare Link) under a shared value.",props:[{name:"value",type:"string",required:!0,description:"This item's identifier, handed down through context to its own Trigger and Content so the menu knows which panel the item owns."}]},{name:"Content",description:"The panel an Item's Trigger opens, holding the links and layout for that top-level entry.",props:[t(e)]},{name:"Indicator",description:"Optional arrow or highlight that tracks the open item along the List, rendered outside it.",props:[t(e)]},{name:"Link",description:"A plain navigation link inside the menu or an open content panel.",props:[{name:"active",type:"boolean",required:!1,description:'Marks the link as the current page: sets data-active and aria-current="page".'},{name:"href",frameworks:["vue","angular","webComponents"],exception:"attribute-passthrough",frameworksReason:"React and Svelte type their Link props on the anchor attribute set itself (AnchorHTMLAttributes, HTMLAnchorAttributes) and spread the rest onto the element, so href arrives as the native attribute with no named prop for an extractor to read. Vue, Angular and Web Components render the anchor from a template and must name it to bind it.",type:"string",required:!1,description:"The link's destination, written onto the anchor this part renders."},{name:"target",frameworks:["vue","angular","webComponents"],exception:"attribute-passthrough",frameworksReason:"React and Svelte take target off their anchor attribute types and spread it onto the element, so it reaches the anchor natively without a named prop. Vue, Angular and Web Components bind it from a template and name it to read it back for the rel guard.",type:"string",required:!1,description:"Native target attribute for the anchor, such as _blank to open a new browsing context."},{name:"rel",frameworks:["vue","angular","webComponents"],exception:"attribute-passthrough",frameworksReason:"React and Svelte take rel off their anchor attribute types rather than declaring it \u2014 Svelte still resolves it against target with the shared helper, React writes through whatever the caller passes. Vue, Angular and Web Components name it because their templates bind the resolved value rather than the raw one.",type:"string",required:!1,description:"Native rel attribute for the anchor; resolves to noopener noreferrer when target is _blank and no explicit value is given."}]}],slots:[{name:"default",description:"Root content \u2014 a NavigationMenuList and optional NavigationMenuIndicator."}],states:["closed","open"],controlledUncontrolled:"Supports both: `value` for controlled, `defaultValue` for uncontrolled. The closed sentinel is `null`.",formBehavior:"Not applicable \u2014 NavigationMenu does not participate in forms.",validationBehavior:"Not applicable \u2014 NavigationMenu carries no value and participates in no validation.",accessibility:{role:"nav (unnamed unless the consumer supplies aria-label \u2014 see the note below)",keyboard:[{key:"ArrowLeft/ArrowRight (horizontal) or ArrowUp/ArrowDown (vertical)",behavior:"Move focus between top-level triggers/links, wrapping at ends."},{key:"Enter/Space",behavior:"Toggle the focused trigger immediately, with no open delay: it opens a closed panel and closes the one it just opened. Trigger is a disclosure button carrying aria-expanded, which APG requires to toggle."},{key:"ArrowDown (on open trigger)",behavior:"Move focus into trigger content panel."},{key:"Escape",behavior:"Close open content and refocuses its trigger."},{key:"Home",behavior:"Move focus to first top-level trigger/link."},{key:"End",behavior:"Moves focus to the last top-level trigger or link. No state change and no event."}],ariaAttributes:["trigger's aria-expanded reflects whether its content is open","trigger's aria-controls points at its content's id","content's aria-labelledby points back at its trigger's id","aria-label on the root landmark is a **required authoring input** for any localised application and for any page carrying more than one navigation landmark, and the root emits no attribute at all when the consumer supplies none. An untranslated English default baked into a library is an i18n leak, and a generic name masks the WCAG failure instead of surfacing it \u2014 a footer or breadcrumb nav announced under a generic default is worse than an unnamed one, while a single nav landmark needs no accessible name to begin with. Unnamed is the honest default: it leaves the omission visible to an audit rather than papering over it.","`aria-label` and `href` on the Link part are host accommodations rather than canonical properties \u2014 a component host must declare any attribute it means to reflect \u2014 so they are excluded from the canonical property table."],focusManagement:"Natural tab order \u2014 every top-level trigger and link is its own tab stop, per the APG disclosure-navigation pattern. The axis arrows move focus between them without changing the tab order, and the ring is scoped to the list's direct `<li>` children so an open panel's own links stay out of it. ArrowDown on an open trigger is the keyboard route *into* that panel, landing on its first tabbable element; Escape is the route back out, returning focus to the trigger that owned the closed content. Moving focus out of an open panel, by Shift+Tab or otherwise, closes it."},styling:{cssParts:["root","list","item","trigger","content","link","indicator"],dataAttributes:[...a,"data-state","data-active","data-orientation","data-skdx-nav-trigger","data-value",{name:"data-skdx-navigation-menu-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-navigation-menu-indicator-offset","--skdx-navigation-menu-indicator-size"]},publicMethods:[]};export{l as navigationMenuContract};
@@ -0,0 +1,3 @@
1
+ import type { ComponentContract } from './types.js';
2
+ /** Contract for the NotificationCenter block: a list of notifications with read state and per-item actions. */
3
+ export declare const notificationCenterContract: ComponentContract;
@@ -0,0 +1 @@
1
+ import{ROOT_DATA_ATTRIBUTES as e}from"./styling-hooks.js";var t="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`.",n={name:"NotificationCenter",purpose:"A block listing notifications with read/unread state, timestamps, a leading visual and per-item and mark-all-read actions, composing Heading, Button, Time and Skeleton, with the EmptyState block for its empty state. Renders as panel content only, inside a Popover, Drawer, Dialog or page the block owns no overlay of its own. Ships in the blocks package of each framework, not the core package.",props:[{name:"notifications",type:"ReadonlyArray<NotificationCenterItem>",required:!0,description:"The notifications to list, in render order, each with an id, a title and read state."},{name:"title",type:"string",defaultValue:"'Notifications'",required:!1,description:"Heading text, rendered into a derived heading that names the section."},{name:"headingLevel",type:"1 | 2 | 3 | 4 | 5 | 6",defaultValue:"2",required:!1,description:"Outline level of the derived title heading inside the surrounding outline."},{name:"markAllReadLabel",type:"string",defaultValue:"'Mark all as read'",required:!1,description:"Text of the mark-all-read button, rendered only when onMarkAllRead is given."},{name:"markReadLabel",type:"string",defaultValue:"'Mark as read'",required:!1,description:"Text of a per-item toggle while that notification is unread."},{name:"markUnreadLabel",type:"string",defaultValue:"'Mark as unread'",required:!1,description:"Text of a per-item toggle while that notification is read."},{name:"emptyTitle",type:"string",defaultValue:"'No notifications'",required:!1,description:"Heading text of the derived EmptyState shown when the list is empty."},{name:"emptyDescription",type:"string",required:!1,description:"Supporting copy of the derived EmptyState shown when the list is empty."},{name:"loading",type:"boolean",defaultValue:"false",required:!1,description:"Swaps the list for a skeleton placeholder region while notifications load."},{name:"now",type:"Date | number",required:!1,description:"Reference instant every item timestamp measures its relative label from."},{name:"leading",type:"Snippet<[NotificationCenterItem]>",required:!1,frameworks:["svelte"],exception:"render-prop",frameworksReason:"Svelte spells a per-item render hook as a snippet prop, which is both a prop and a slot in that framework's own idiom; the other frameworks take it through renderLeading or the `leading` scoped slot.",description:"The Svelte snippet form of `renderLeading`, rendered once per item with that item as its argument."},{name:"itemActions",type:"Snippet<[NotificationCenterItem]>",required:!1,frameworks:["svelte"],exception:"render-prop",frameworksReason:"Svelte spells a per-item render hook as a snippet prop, which is both a prop and a slot in that framework's own idiom; the other frameworks take it through renderActions or the `item-actions` scoped slot.",description:"The Svelte snippet form of `renderActions`, rendered once per item with that item as its argument."},{name:"renderLeading",type:"(item: NotificationCenterItem) => unknown",required:!1,frameworks:["react","angular","webComponents"],exception:"render-prop",frameworksReason:"Vue takes this as a scoped slot and Svelte as a snippet of the same name rather than a prop, because a per-item render hook is a slot with slot props in their own idioms; React, Angular and Web Components take the function, since one markup slot cannot render once per item.",description:"Renders a decorative avatar or icon beside one notification, always aria-hidden. No leading region renders when omitted. A prop in React and Angular; Vue uses the `leading` scoped slot and Svelte the `leading` snippet; Web Components set the function as a property."},{name:"renderActions",type:"(item: NotificationCenterItem) => unknown",required:!1,frameworks:["react","angular","webComponents"],exception:"render-prop",frameworksReason:"Vue takes this as a scoped slot and Svelte as a snippet of the same name rather than a prop, because a per-item render hook is a slot with slot props in their own idioms; React, Angular and Web Components take the function, since one markup slot cannot render once per item.",description:"Renders extra controls beside one notification's read/unread toggle. A prop in React and Angular; Vue uses the `item-actions` scoped slot and Svelte the `itemActions` snippet; Web Components set the function as a property."},{name:"actions",type:"unknown",required:!1,frameworks:["react","svelte","angular"],exception:"render-prop",frameworksReason:t,description:"Header controls rendered beside the mark-all-read button. No extra header controls render when omitted. A prop in React, Svelte, and Angular; Vue and Web Components use the `actions` slot."}],events:[{name:"select",detail:"{ item: NotificationCenterItem }",description:"Fires when a notification's body is activated. The body renders as a button only while this event has a listener; otherwise it is a plain container."},{name:"read-change",detail:"{ item: NotificationCenterItem; read: boolean }",description:"Fires with the next read state when a notification's read/unread toggle is activated. No toggle renders while this has no listener."},{name:"mark-all-read",detail:"void",description:"Fires when the mark-all-read button is activated. No mark-all-read button renders while this has no listener."}],slots:[{name:"actions",description:"The actions prop's content \u2014 header controls beside the mark-all-read button."},{name:"leading",frameworks:["vue","svelte"],exception:"render-prop",frameworksReason:"Vue spells a per-item render hook as a scoped slot and Svelte as a snippet; React, Angular and Web Components take the equivalent function through the prop of the same purpose.",description:"The renderLeading prop's content \u2014 a decorative avatar or icon beside one notification."},{name:"item-actions",frameworks:["vue","svelte"],exception:"render-prop",frameworksReason:"Vue spells a per-item render hook as a scoped slot and Svelte as a snippet; React, Angular and Web Components take the equivalent function through the prop of the same purpose.",description:"The renderActions prop's content \u2014 extra controls beside one notification's read/unread toggle."}],states:["default"],controlledUncontrolled:"Stateless \u2014 the notification list, each item's read state, and loading are all controlled by the consumer through props. No data-state attribute is written: loading is conveyed by aria-busy and a skeleton region, and an empty list swaps in the composed EmptyState block instead.",formBehavior:"Not applicable \u2014 NotificationCenter participates in no form.",validationBehavior:"Not applicable \u2014 NotificationCenter carries no value and participates in no validation.",accessibility:{role:"region (native <section> named by its heading; the list is a <ul>; a notification body is a <button> only when select is handled; unread is conveyed by data-read and by the read-toggle visible label, not colour alone)",keyboard:[{key:"Tab",behavior:"Moves focus between notification bodies and their read/unread toggles."},{key:"Enter/Space",behavior:"Activates the focused notification body or toggle (native button activation)."}],ariaAttributes:["aria-labelledby on the <section> points at the derived heading, so the region is announced by its own title","aria-busy on the <section> mirrors the loading prop while the skeleton rows render","unread is conveyed by the data-read attribute and by the read-toggle button's visible label text, never by colour alone","the renderLeading output is wrapped in an aria-hidden container, since it is decorative"],focusManagement:"Focus stays where the user put it; nothing moves focus automatically. Each notification body and its read/unread toggle are separate Tab stops when their handlers are supplied."},styling:{cssParts:["notification-center","header","title","actions","mark-all-read","loading","empty","list","item","leading","body","item-title","description","time","item-actions","read-toggle"],dataAttributes:[...e,"data-read",{name:"data-skdx-notification-center-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 notificationCenterContract};
@@ -0,0 +1,5 @@
1
+ import type { ComponentContract } from './types.js';
2
+ /**
3
+ * A numeric stepper input with a clamped value shared across its parts.
4
+ */
5
+ export declare const numberFieldContract: ComponentContract;
@@ -0,0 +1 @@
1
+ import{changeDetail as e}from"./change-reason.js";import{constraintValidationMethods as t,setCustomValidityMethod as a}from"./form-validity.js";import{ROOT_DATA_ATTRIBUTES as n}from"./styling-hooks.js";var o={name:"NumberField",purpose:"A numeric stepper: owns the clamped value handed to its parts. Every published value is clamped to [min, max]; null means the field is empty.",props:[{name:"value",type:"number | null",required:!1,description:"Current value, for controlled usage. null is the empty field \u2014 the state an untouched number field starts in and the one an emptied input returns to. Without it a field could only ever submit a real number, so a quantity nobody filled in submitted 0."},{name:"defaultValue",type:"number | null",defaultValue:"null",required:!1,description:"Initial value, for uncontrolled usage. Clamped to min/max on mount. Defaults to null so an untouched field is empty rather than pre-filled with 0."},{name:"min",type:"number",defaultValue:"-Infinity",required:!1,description:"Lower bound the value is clamped to."},{name:"max",type:"number",defaultValue:"Infinity",required:!1,description:"Upper bound the value is clamped to."},{name:"step",type:"number",defaultValue:"1",required:!1,description:"Amount the increment/decrement buttons and Arrow Up/Down change the value by (Page Up/Down uses 10x this)."},{name:"disabled",type:"boolean",defaultValue:"false",required:!1,description:"Disables the field, its input, and both step buttons."},{name:"invalid",type:"boolean",defaultValue:"false",required:!1,description:"An author-supplied presentational flag set from the consumer's own validation result. Under clampBehavior: 'never' an out-of-range value also raises aria-invalid; under the default clampBehavior: 'blur' this flag is the whole of it."},{name:"readOnly",type:"boolean",defaultValue:"false",required:!1,description:"Makes the input read-only and makes the step buttons inert (focusable but no-op)."},{name:"name",type:"string",required:!1,description:"Form field name. Without it the field submits nothing."},{name:"required",type:"boolean",defaultValue:"false",required:!1,description:'Marks the field required: aria-required="true" on the spinbutton, and the constraint the mirrored native control enforces, so an empty field reports valueMissing through checkValidity()/reportValidity() and blocks submission. Only meaningful now that value can be null \u2014 with a total number there was no state for the constraint to catch.'},{name:"formatOptions",type:"Intl.NumberFormatOptions",required:!1,description:"Intl.NumberFormat options the displayed value is formatted with (currency, percent, unit, grouping); typed or pasted text is parsed back through the same options. min/max/step always operate on the numeric value, never the formatted string \u2014 with style: percent the value is the fraction, so 0.5 displays as 50%."},{name:"locale",type:"string",required:!1,description:"BCP-47 locale used for formatting and parsing, so the locale's decimal and group separators round-trip (de-DE reads and writes '1.234,5'). Defaults to the runtime locale, resolved once in the root with Intl.NumberFormat(locale).resolvedOptions().locale and handed to every format and parse call through context \u2014 so the whole field agrees on one locale string, and the one the server rendered is the one the client hydrates. Resolution only happens while formatting is on (locale or formatOptions given); without either, the value still round-trips through String/Number untouched."},{name:"clampBehavior",type:"'blur' | 'never'",defaultValue:"'blur'",required:!1,description:"When typed text is snapped into [min, max]. 'blur' clamps on every keystroke and again when the field settles, so a published value can never leave the bounds. 'never' publishes the typed number as it was typed and marks the input aria-invalid/data-invalid while it sits outside them \u2014 the consumer decides what an out-of-range entry means. Step interactions (the buttons, the arrow keys, Page Up/Down, Home/End) clamp under both: a stepper that walked past its own bound would have no bound."},{name:"allowWheel",type:"boolean",defaultValue:"false",required:!1,description:"Lets the mouse wheel step the value while the input has DOM focus. Opt-in, and focus-gated, because a wheel handler that fires on hover silently edits a field the user was only scrolling past \u2014 the focus requirement is what makes the gesture deliberate."},{name:"form",type:"string",required:!1,description:"Id of the <form> that owns this field, for a field rendered outside it \u2014 inside a Dialog's portal, for instance. React, Vue, Svelte and Angular forward it to the hidden input's form attribute and resolve the reset listener through it rather than through closest('form'); <skdx-number-field> takes the form content attribute, which is what ElementInternals associates on."},{name:"showControls",type:"boolean",defaultValue:"true",required:!1,description:"Renders the increment and decrement steppers."},{name:"incrementLabel",type:"string",defaultValue:"'Increment'",required:!1,description:"Accessible name for the derived increment stepper."},{name:"decrementLabel",type:"string",defaultValue:"'Decrement'",required:!1,description:"Accessible name for the derived decrement stepper."},{name:"size",type:"'md' | 'sm' | 'lg' | (string & {})",required:!1,description:"Visual size rung, written to data-size on the root; the data-size attribute may be set directly instead."}],events:[{name:"value-change",detail:e("number | null"),description:"Fires with the new value \u2014 clamped into [min, max] under the default clampBehavior: 'blur', or null when the field is emptied \u2014 whenever it changes, including once per keystroke while typing. An unclamped value (e.g. 999 from a field with max: 10) is reachable only when clampBehavior: 'never' is set deliberately, and only by typing \u2014 every step interaction clamps. The unclamped text is still what the user sees; it is the input element's own state, and a consumer that needs the in-progress text reads it from there."},{name:"value-commit",detail:"number | null",description:'Fires with the same payload as value-change once the value settles: on blur after typing, on Enter (before the form submission it triggers proceeds), and immediately after every arrow/page key, Home/End jump, or increment/decrement press. This is the event to hang an expensive effect on \u2014 typing "1234" emits four value-change events and one value-commit, so a consumer can mirror every keystroke without also making a network call per keystroke. A blur that follows no typing emits nothing.'}],parts:[{name:"Input",description:'The text field holding the formatted value (role="spinbutton"). Carries the aria-value* range and commits on blur or Enter.',props:[]},{name:"Increment",description:"The button that raises the value by one step. Disabled at max, inert (but focusable) while the field is read-only, and repeating while held. Its content is usually a bare '+', which announces as nothing useful \u2014 so it carries a name of its own.",props:[{name:"label",type:"string",defaultValue:"'Increment'",required:!1,description:"Accessible name of the button. Contracted rather than hardcoded because the name was an uncontracted English literal in three packages and an uncontracted property in the other two \u2014 the same concept named two ways, and untranslatable in three of them. Set it to translate the name, or to say what is being incremented ('Add one guest')."}]},{name:"Decrement",description:"The button that lowers the value by one step. Disabled at min, inert (but focusable) while the field is read-only, and repeating while held. Its content is usually a bare '-', which announces as nothing useful \u2014 so it carries a name of its own.",props:[{name:"label",type:"string",defaultValue:"'Decrement'",required:!1,description:"Accessible name of the button, for the same reason Increment's is contracted. Set it to translate the name, or to say what is being decremented ('Remove one guest')."}]}],slots:[{name:"default",description:"NumberFieldInput plus NumberFieldIncrement/Decrement."}],appearance:[{attribute:"data-size",values:["md","sm","lg"],stylesheet:"number-field.css"}],states:["default","disabled","invalid","readonly"],controlledUncontrolled:"Controlled via value + a change event, or uncontrolled via defaultValue.",formBehavior:"Form-associated: with a name, submits the committed number as a string, and the empty string while the value is null \u2014 an empty entry, the way a native text input submits one, never a fabricated 0. form associates the field with a <form> it is not nested inside, and is also what the reset listener resolves through, so a field submitting into a form elsewhere on the page answers that form's reset too. A form reset restores the declared default (firing value-change, but not value-commit, in the four framework packages, and silently in Web Components).",validationBehavior:"required is the only constraint the field itself enforces: a null value is valueMissing, reported through checkValidity()/reportValidity() identically in all five frameworks, so an empty required field blocks submission instead of silently passing. Under the default clampBehavior: 'blur' there is nothing else to violate \u2014 every published value is clamped into [min, max] by construction \u2014 and invalid is then a purely presentational flag. Under clampBehavior: 'never' an out-of-range value is reachable and the input carries aria-invalid/data-invalid for it, but it is still not a native constraint: the range is not handed to the browser, so checkValidity() keeps answering the required question alone and the consumer decides what to do with the out-of-range entry.",accessibility:{role:"spinbutton (on NumberFieldInput)",keyboard:[{key:"ArrowUp",behavior:"Increments the value by one step."},{key:"ArrowDown",behavior:"Decrements the value by one step."},{key:"PageUp",behavior:"Increments the value by ten steps."},{key:"PageDown",behavior:"Decrements the value by ten steps."},{key:"Shift+ArrowUp / Shift+ArrowDown",behavior:"The same ten-step tier as PageUp/PageDown. A second way to reach one tier rather than a new one: a compact keyboard has no PageUp/PageDown key, so the coarse step was unreachable there. No property configures it."},{key:"Home / End",behavior:"Jumps to min / max, when that bound is finite. APG spinbutton behaviour."},{key:"Enter",behavior:"Commits the typed text before the form submission it triggers proceeds, so the submission carries the settled number rather than the last keystroke's. Deliberately not preventDefault-ed."}],ariaAttributes:["aria-valuenow/aria-valuemin/aria-valuemax reflect value/min/max on NumberFieldInput, and aria-valuenow is absent entirely while the value is null \u2014 a spinbutton with no value must not claim one, and 0 is the wrong lie to tell",'aria-required="true" on NumberFieldInput while required is set; role="spinbutton" allows it, so it belongs on the input rather than the root',"aria-valuetext announces the Intl-formatted value on NumberFieldInput, and is only set when formatOptions or locale is given (otherwise aria-valuenow already reads correctly)",`aria-invalid="true" on NumberFieldInput while the value sits outside [min, max], which only clampBehavior: 'never' makes reachable \u2014 the same attribute the invalid prop raises, because to a screen reader the two are the same claim`],focusManagement:'Native input focus. A step button has two kinds of inertness and only one of them is the native `disabled` attribute: the *field* being disabled is a property of the control and takes the attribute, while being at the bound \u2014 or read-only \u2014 is a transient consequence of the current value and is published as `aria-disabled="true"` plus a no-op press. Both also carry `data-disabled` so the skin has one selector. Folding at-bound into `disabled` removed the button from the tab order and from the accessibility tree at exactly the moment a screen-reader user most needs to be told it exists, and disagreed with the read-only path in the same component.',namingRequirement:"The spinbutton needs an accessible name from aria-label, aria-labelledby, or an enclosing Field."},styling:{cssParts:["number-field","input","increment","decrement"],dataAttributes:[...n,"data-disabled","data-invalid","data-readonly","data-size",{name:"data-skdx-number-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:[...t,a]};export{o as numberFieldContract};
@@ -0,0 +1,3 @@
1
+ import type { ComponentContract } from './types.js';
2
+ /** Contract for the OnboardingChecklist block: a progress checklist of setup and launch tasks. */
3
+ export declare const onboardingChecklistContract: ComponentContract;
@@ -0,0 +1 @@
1
+ import{ROOT_DATA_ATTRIBUTES as e}from"./styling-hooks.js";var i={name:"OnboardingChecklist",purpose:"A progress checklist for setup, launch and configuration tasks, composing Heading, Text, Progress and Button. Each item carries its own completion state and an optional action; activating one reports through one action event. Ships in the blocks package of each framework, not the core package.",props:[{name:"title",type:"string",required:!0,description:"Heading text naming the checklist, rendered into a derived Heading."},{name:"description",type:"string",required:!1,description:"Supporting copy rendered below the title, explaining what the checklist covers. 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 outline."},{name:"items",type:"OnboardingChecklistItem[]",required:!0,description:"The tasks to complete, in render order, each with its own label, completion state, optional flag and action label."},{name:"getProgressLabel",type:"(complete: number, total: number) => string",defaultValue:"defaultGetProgressLabel",required:!1,description:`Formats the overall progress meter's readout from the completed and total item counts. The default reads "1/3".`},{name:"completeLabel",type:"string",defaultValue:"'Completed'",required:!1,description:"Visually hidden text appended after a completed item's title, announcing its completion."},{name:"optionalLabel",type:"string",defaultValue:"'Optional'",required:!1,description:"Text rendered beside an optional item's title."}],events:[{name:"action",detail:"{ id: string; label: string; description?: string; state?: OnboardingChecklistItemState; optional?: boolean; actionLabel?: string }",description:"Fires when an item's action button is activated, carrying the full item that was acted on."}],slots:[],states:["pending","active","complete","disabled"],controlledUncontrolled:"Stateless \u2014 OnboardingChecklist holds no internal state; every item's completion state is driven entirely by props.",formBehavior:"Not applicable \u2014 OnboardingChecklist participates in no form.",validationBehavior:"Not applicable \u2014 OnboardingChecklist carries no value and participates in no validation.",accessibility:{role:'region (native <section> named by its heading; the list is an <ol>, the active item carries aria-current="step", completion is spoken through the visually hidden completeLabel)',keyboard:[],ariaAttributes:["aria-labelledby on the <section> and the progress meter both point at the derived title heading",'aria-current="step" marks the active item as the current step',"the completed item's title carries a visually hidden node so its completion is announced"],focusManagement:"Focus stays where the user put it; each item's action button is the only focusable element the block adds."},styling:{cssParts:["onboarding-checklist","header","title","description","progress","list","item","indicator","body","item-title","optional","item-description","action"],dataAttributes:[...e,"data-state"],cssCustomProperties:[]},publicMethods:[]};export{i as onboardingChecklistContract};
@@ -0,0 +1,73 @@
1
+ import { type CssVar, type EventContract, type PartContract, type PropContract } from './types.js';
2
+ /**
3
+ * Shared parts for all floating overlays (Popover, Menu, Select, etc.).
4
+ */
5
+ /** Keeps a part mounted, rather than unmounted, in the DOM while the overlay is closed. */
6
+ export declare const forceMountProp: PropContract;
7
+ /** Where the overlay's Content is teleported to in the DOM. */
8
+ export declare const portalPart: PartContract;
9
+ /** Portal props for the families that narrow forceMount past the part's own framework list. */
10
+ export declare const portalPropsSansForceMount: PropContract[];
11
+ /** The Arrow part: a pointer from Content back at the anchor. */
12
+ export declare const arrowPart: PartContract;
13
+ /** The keyboard-hint part at a menu item's trailing edge, e.g. "Ctrl+S". */
14
+ export declare const shortcutPart: PartContract;
15
+ /** Sub/SubTrigger/SubContent parts for a nested submenu, shared across all menu families. */
16
+ export declare function menuSubParts(): PartContract[];
17
+ /** Options for {@link dismissalEvents}. */
18
+ export interface DismissalEventOptions {
19
+ /**
20
+ * Whether an un-prevented outside interaction actually closes the overlay.
21
+ * @defaultValue true
22
+ */
23
+ outsideDismisses?: boolean;
24
+ /** Extra sentence appended to the three outside-interaction events' descriptions. */
25
+ outsideNote?: string;
26
+ }
27
+ /**
28
+ * The four cancelable dismissal events every overlay's Content declares.
29
+ * @param noun - what the overlay is called in prose ("dialog", "menu", "popover").
30
+ */
31
+ export declare function dismissalEvents(noun: string, options?: DismissalEventOptions): EventContract[];
32
+ /**
33
+ * The two cancelable focus-management events an overlay that moves focus on
34
+ * its own declares (Dialog, Popover, and Drawer).
35
+ * @param noun - what the overlay is called in prose ("dialog", "popover").
36
+ */
37
+ export declare function autoFocusEvents(noun: string): EventContract[];
38
+ /**
39
+ * The close half of {@link autoFocusEvents}, on its own.
40
+ * @param noun - what the overlay is called in prose ("menu", "popover").
41
+ */
42
+ export declare function closeAutoFocusEvent(noun: string): EventContract;
43
+ /**
44
+ * `textValue`, identical on every menu item part that takes part in typeahead
45
+ * (Item, CheckboxItem, RadioItem, SubTrigger, in all three menu families).
46
+ */
47
+ export declare const textValueProp: PropContract;
48
+ /** Per-component overrides for the positioning defaults, where a component opens somewhere other than centred-below. */
49
+ export interface PopperDefaults {
50
+ /** Overrides the `side` default. @defaultValue `'bottom'` */
51
+ side?: string;
52
+ /** Overrides the `align` default. @defaultValue `'center'` */
53
+ align?: string;
54
+ /** Overrides the `sideOffset` default. @defaultValue `'4'` */
55
+ sideOffset?: string;
56
+ }
57
+ /**
58
+ * The floating-ui positioning props every popper-positioned Content part
59
+ * accepts.
60
+ */
61
+ export declare function popperContentProps(defaults?: PopperDefaults): PropContract[];
62
+ /**
63
+ * The measurement CSS custom properties every popper-positioned Content part
64
+ * sets on itself after each reposition.
65
+ * @param slug - the component's kebab-case name ("popover", "menu").
66
+ */
67
+ export declare function popperMeasurementProperties(slug: string): CssVar[];
68
+ /**
69
+ * The settled counterpart to `open-change`, fired once the change has
70
+ * actually finished on screen (after any enter/exit animation).
71
+ * @param noun - what the overlay is called in prose ("popover", "tooltip").
72
+ */
73
+ export declare function openChangeCompleteEvent(noun: string): EventContract;
@@ -0,0 +1 @@
1
+ import{withoutScope as s}from"./types.js";var i={name:"forceMount",type:"boolean",defaultValue:"false",required:!1,frameworks:["react","vue","svelte"],exception:"force-mount",frameworksReason:"A mount switch only means something on a part that unmounts. Web Components writes every part once in markup and hides it with the hidden attribute, and Angular hosts the part as the component itself, kept in the tree and toggled with [hidden] or rendered as an unconditional native <dialog> \u2014 neither can unmount its own host, so the prop would be a no-op with a name that promises behaviour. See divergence 1 above.",description:'Keep this part in the DOM while the overlay is closed instead of unmounting it, so an animation library can play an exit transition against data-state="closed".'},r=[{name:"container",type:"Element | DocumentFragment | null",defaultValue:"document.body",required:!1,description:"DOM node Content is rendered into instead of its natural position \u2014 e.g. a dedicated overlay root, or a shadow root when the overlay must stay inside a web component."},i],m={name:"Portal",frameworks:["react","vue","svelte","webComponents"],exception:"portal",frameworksReason:"Angular ships no Portal part on any overlay family: the supported way to portal there is the [skdxPortal] attribute directive, whose @Input() skdxPortal carries exactly this part's container capability, chosen so the portalled element stays the element you wrote. Giving one family a Portal part would break parity within Angular to fix it across frameworks. See divergence 2 above.",description:"Teleports Content out of its position in the tree so the overlay escapes clipping/overflow ancestors and ancestor stacking contexts. Renders no element of its own.",props:r},f=r.filter(e=>e!==i),g={name:"Arrow",description:"Optional pointer from Content back at the anchor. Rendered inside Content and positioned from the resolved side, so it takes no positioning props of its own."},b={name:"Shortcut",description:`The keyboard hint at the trailing edge of an Item \u2014 "\u2318K", "Ctrl+S". Renders a span with aria-hidden="true": a menuitem takes its accessible name from its contents, so an unhidden hint would be read as part of the command's name. Purely presentational; it binds nothing and listens to nothing.`};function v(){return[{name:"Sub",description:"Root of a nested submenu inside Content. Owns the submenu's own open state, independent of the parent menu's, and anchors SubContent to SubTrigger. Renders no element of its own.",props:[{name:"open",type:"boolean",required:!1,description:"Controlled open state of the submenu. Pair with the open-change event."},{name:"defaultOpen",type:"boolean",defaultValue:"false",required:!1,description:"Initial open state of the submenu, for uncontrolled usage."}],events:[{name:"open-change",description:"Fired with the submenu's new open state whenever it changes, controlled or not.",detail:"boolean"},c("submenu")]},{name:"SubTrigger",description:`The parent-menu item that opens a submenu (role="menuitem", aria-haspopup="menu", aria-expanded, aria-controls, data-state). Doubles as the anchor SubContent positions against. Opens on click, Enter, Space or ArrowRight \u2014 moving focus to the submenu's first item \u2014 and on hover, which leaves focus where it is. Selecting it never closes the parent menu.`,props:[{name:"disabled",type:"boolean",defaultValue:"false",required:!1,description:"Marks the trigger aria-disabled and blocks it from opening the submenu. It stays in the roving order and remains focusable, so it is discoverable rather than invisible."},p]},{name:"SubContent",description:`The submenu's floating panel (role="menu"), positioned against SubTrigger and defaulting to side="end" / align="start" \u2014 logical, so a submenu opens rightwards under LTR and leftwards under RTL. Owns its own roving focus and typeahead, which cover only the submenu's items \u2014 the submenu's items join the parent's typeahead pool no earlier than the submenu opening. ArrowLeft and Escape close the submenu and return focus to SubTrigger, leaving the parent menu open.`,props:[...u({side:"'end'",align:"'start'",sideOffset:"0"}),s(i),{name:"loop",type:"boolean",defaultValue:"true",required:!1,description:"Whether Up/Down navigation wraps from the submenu's last item back to its first."}]}]}var d="Event";function w(e,n={}){let{outsideDismisses:o=!0,outsideNote:t}=n,a=(o?`Preventing default keeps the ${e} open.`:`Notification only \u2014 an outside interaction never closes the ${e}. The payload's cancelability is inherited from the underlying DOM event and carries no meaning here: there is no dismissal behind it, so preventing default changes nothing.`)+(t?` ${t}`:"");return[{name:"escape-key-down",description:`Fired when Escape is pressed while open. Preventing default keeps the ${e} open.`,detail:d},{name:"pointer-down-outside",description:`Fired on a pointer-down that lands outside Content while open. ${a}`,detail:"Event"},{name:"focus-outside",description:`Fired when focus moves to an element outside Content while open. ${a} Carries a cancelable stand-in for the focusin event, which is not itself cancelable.`,detail:"Event"},{name:"interact-outside",description:`Fired for either kind of outside interaction \u2014 pointer-down or focus \u2014 immediately before the specific event, so one handler can veto both. ${a}`,detail:"Event"}]}function y(e){return[{name:"open-auto-focus",description:`Fired before focus is moved into Content on open. Preventing default leaves focus where it is, so the consumer can send it somewhere else (a specific input, the ${e} panel itself).`,detail:"void"},l(e)]}function l(e){return{name:"close-auto-focus",description:`Fired before focus is returned to whatever was focused before the ${e} opened. Preventing default suppresses that automatic return \u2014 the escape hatch for when the trigger has been removed from the DOM and focus must be placed by hand.`,detail:"void"}}var p={name:"textValue",type:"string",required:!1,description:"Text typeahead matches this item by, instead of its rendered text. Reflected to data-text-value, which every matcher reads ahead of textContent. Falls back to the item's rendered text when unset."};function u(e={}){let{side:n="'bottom'",align:o="'center'",sideOffset:t="4"}=e;return[{name:"side",type:"'top' | 'right' | 'bottom' | 'left' | 'start' | 'end'",defaultValue:n,required:!1,description:"Preferred edge of the anchor to render against. `start`/`end` are resolved against the writing direction. Resolved placement lands on data-side."},{name:"align",type:"'start' | 'center' | 'end'",defaultValue:o,required:!1,description:"Alignment along the chosen side. Resolved alignment lands on data-align."},{name:"sideOffset",type:"number",defaultValue:t,required:!1,description:"Gap in pixels between Content and the anchor, along side."},{name:"alignOffset",type:"number",defaultValue:"0",required:!1,description:"Shift in pixels along align, perpendicular to side."},{name:"avoidCollisions",type:"boolean",defaultValue:"true",required:!1,description:"Flip to the opposite side when the preferred side doesn't fit in the viewport."},{name:"collisionPadding",type:"number | Partial<Record<'top' | 'right' | 'bottom' | 'left', number>>",defaultValue:"8",required:!1,description:"Minimum distance in pixels kept from the collision boundary while avoiding collisions. A number applies to every side; an object sets only the sides it names, the rest falling back to 0."},{name:"collisionBoundary",type:"Element | Element[] | null",defaultValue:"null",required:!1,description:"Element (or elements) collisions are measured against instead of Content's clipping ancestors \u2014 the escape hatch for keeping an overlay inside a scroll container, a canvas, or one pane of a split layout rather than the whole viewport. Property-only in Web Components, declared as @property({ attribute: false }): an Element cannot cross an HTML attribute boundary, so there is no collision-boundary attribute and never can be. A parity report showing the attribute missing there is reporting that, not a gap."}]}function C(e){return[`--skdx-${e}-available-width`,`--skdx-${e}-available-height`,`--skdx-${e}-trigger-width`,`--skdx-${e}-transform-origin`]}function c(e){return{name:"open-change-complete",description:`Fired with the new open state after the ${e}'s enter or exit animation has finished \u2014 as soon as Content has settled, when it declares no animation at all. Not cancelable: the change has already happened.`,detail:"boolean"}}export{g as arrowPart,y as autoFocusEvents,l as closeAutoFocusEvent,w as dismissalEvents,i as forceMountProp,v as menuSubParts,c as openChangeCompleteEvent,u as popperContentProps,C as popperMeasurementProperties,m as portalPart,f as portalPropsSansForceMount,b as shortcutPart,p as textValueProp};
@@ -0,0 +1,3 @@
1
+ import type { ComponentContract } from './types.js';
2
+ /** Contract for the PageContainer block: breadcrumbs, a page heading and page-level actions above the content. */
3
+ export declare const pageContainerContract: ComponentContract;
@@ -0,0 +1 @@
1
+ import{ROOT_DATA_ATTRIBUTES as e}from"./styling-hooks.js";var t={name:"PageContainer",purpose:"A page-level block composing Breadcrumb, Heading and Toolbar above the page content. Renders a <section> named by its own heading. Ships in the blocks package of each framework, not the core package.",props:[{name:"title",type:"string",required:!0,description:"The page heading text, rendered into a derived Heading that also names the section through aria-labelledby."},{name:"headingLevel",type:"1 | 2 | 3 | 4 | 5 | 6",defaultValue:"1",required:!1,description:"Heading level of the derived title. A page container normally holds the page's only <h1>; lower it when the block sits inside a larger outline."},{name:"breadcrumbs",type:"ReadonlyArray<{ label: string; href?: string; current?: boolean }>",required:!1,description:"Trail rendered into a derived Breadcrumb above the heading. No breadcrumb region renders when omitted."},{name:"breadcrumbLabel",type:"string",defaultValue:"'Breadcrumb'",required:!1,description:"Accessible name of the derived breadcrumb <nav>."},{name:"actionsLabel",type:"string",defaultValue:"'Page actions'",required:!1,description:"Accessible name of the derived actions Toolbar."},{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 inside the derived Toolbar beside the heading. No toolbar renders when omitted. A prop in React, Svelte, and Angular; Vue and Web Components use the `actions` slot."}],events:[],slots:[{name:"default",description:"The page content below the header."},{name:"actions",description:"Controls placed in the toolbar beside the heading."}],states:["default"],controlledUncontrolled:"Stateless \u2014 PageContainer holds no internal state.",formBehavior:"Not applicable \u2014 PageContainer participates in no form.",validationBehavior:"Not applicable \u2014 PageContainer carries no value and participates in no validation.",accessibility:{role:"region (native <section> named by its heading through aria-labelledby)",keyboard:[{key:"ArrowLeft/ArrowRight",behavior:"Moves between the action controls inside the derived Toolbar, which is one Tab stop."}],ariaAttributes:["aria-labelledby on the <section> points at the derived heading, so the region is announced by the page title","the derived Breadcrumb is a <nav> named by breadcrumbLabel; the derived Toolbar is named by actionsLabel"],focusManagement:"Nothing inside the block is focusable except the breadcrumb links and the action controls the consumer supplies; the Toolbar applies its roving tabindex to them."},styling:{cssParts:["page-container","header","breadcrumbs","heading-row","title","actions","content"],dataAttributes:[...e,{name:"data-skdx-page-container-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{t as pageContainerContract};
@@ -0,0 +1,5 @@
1
+ import type { ComponentContract } from './types.js';
2
+ /**
3
+ * A page-number navigation control with roving-tabindex arrow-key navigation.
4
+ */
5
+ export declare const paginationContract: ComponentContract;
@@ -0,0 +1 @@
1
+ import{ROOT_DATA_ATTRIBUTES as e}from"./styling-hooks.js";var a={name:"Pagination",purpose:"A page-number navigation control that computes a collapsed model (siblings around current, boundaries at ends, ellipsis for collapsed runs) and hands it to page-link buttons via context. Also available standalone as getPaginationRange.",props:[{name:"pageCount",type:"number",required:!0,description:'Total number of pages, used to disable the "next" control on the last page.'},{name:"page",type:"number",required:!1,description:"Current page (1-based), for controlled usage."},{name:"defaultPage",type:"number",defaultValue:"1",required:!1,description:"Initial page (1-based), for uncontrolled usage."},{name:"labels",type:"{ root?: string; page?: (page: number) => string; currentPage?: (page: number) => string; first?: string; previous?: string; next?: string; last?: string }",required:!1,description:"Every string the strip speaks, each optional and falling back to its own English default. Object-valued, so a Web Components property, not attribute."},{name:"siblingCount",type:"number",defaultValue:"1",required:!1,description:"Pages shown either side of the current one in the computed page model."},{name:"boundaryCount",type:"number",defaultValue:"1",required:!1,description:"Pages always shown at each end of the computed page model, however far away the current page is."},{name:"disabled",type:"boolean",defaultValue:"false",required:!1,description:"Blocks navigation across the whole strip by ORing into every Page part's own disabled, so each item is natively disabled and drops out of the roving-focus list."},{name:"showFirstLast",type:"boolean",defaultValue:"false",required:!1,description:"Whether the derived List brackets Previous/Next with First and Last; ignored under hand composition."},{name:"showStatus",type:"boolean",defaultValue:"false",required:!1,description:"Whether the derived anatomy includes a Status live region after the List; ignored under hand composition."},{name:"density",type:"'comfortable' | (string & {})",required:!1,description:"Vertical rhythm rung, written to data-density on the root; the data-density attribute may be set directly instead."},{name:"size",type:"'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:[{name:"page-change",detail:"number",description:"Fires with the new page number whenever it changes; never fires for the already-current page, so a consumer fetching on this event is never told to refetch it."}],parts:[{name:"List",description:'The <ul> holding the page entries, with an explicit role="list" since Safari/VoiceOver drops list semantics once the skin removes markers.'},{name:"Item",description:"One <li> wrapper around a Page, a boundary control, or an Ellipsis."},{name:"Page",description:'One page button \u2014 a <button type="button"> (role="button" host in Web Components) carrying data-skdx-pagination-item, aria-current="page" and data-state="active" while current, and data-disabled when disabled.',props:[{name:"page",type:"number",required:!0,description:"The 1-based page this button asks for when activated."},{name:"isActive",type:"boolean",required:!1,description:`Marks this page as selected (aria-current="page", data-state="active"); derived from the root's current page unless overridden for a split list/detail view.`},{name:"disabled",type:"boolean",defaultValue:"false",required:!1,description:"Disables this one button, excluding it from click handling and the roving-focus candidate list; ORed with the root's own disabled."}]},{name:"Previous",description:'A Page preconfigured for page - 1, labelled "Go to previous page" and disabled on page 1.',props:[{name:"label",type:"string",required:!1,frameworks:["angular"],exception:"attribute-passthrough",frameworksReason:"React, Vue, Svelte and Web Components take `aria-label` on the element through attribute passthrough.",description:"Accessible name of the page link, since projected content is often a chevron."}]},{name:"Next",description:'A Page preconfigured for page + 1, labelled "Go to next page" and disabled on the last page.',props:[{name:"label",type:"string",required:!1,frameworks:["angular"],exception:"attribute-passthrough",frameworksReason:"React, Vue, Svelte and Web Components take `aria-label` on the element through attribute passthrough.",description:"Accessible name of the page link, since projected content is often a chevron."}]},{name:"Ellipsis",description:'A presentational placeholder for a run of collapsed pages (role="presentation", aria-hidden="true", defaulting to "\u2026"), deliberately not marked data-skdx-pagination-item so the roving-focus handler can rely on that attribute alone.'},{name:"Status",description:'An optional role="status" live region announcing the page change, opt-in rather than automatic since a strip whose activation also moves focus into new content already announces it.',props:[{name:"format",type:"(page: number, pageCount: number) => string",required:!1,description:"Builds the announcement from the root's current page and page count; ignored when the consumer supplies text directly as children/slot content."}]},{name:"First",description:'A page link preconfigured for page 1, labelled "Go to first page" and disabled while page 1 is already current.',props:[{name:"label",type:"string",required:!1,frameworks:["angular"],exception:"attribute-passthrough",frameworksReason:"React, Vue, Svelte and Web Components take `aria-label` on the element through attribute passthrough.",description:"Accessible name of the page link, since projected content is often a chevron."}]},{name:"Last",description:'A page link preconfigured for the last page, labelled "Go to last page" and disabled while the last page is already current.',props:[{name:"label",type:"string",required:!1,frameworks:["angular"],exception:"attribute-passthrough",frameworksReason:"React, Vue, Svelte and Web Components take `aria-label` on the element through attribute passthrough.",description:"Accessible name of the page link, since projected content is often a chevron."}]}],slots:[{name:"default",description:"Pagination items \u2014 page links, first/previous/next/last, ellipses."}],appearance:[{attribute:"data-density",values:["comfortable"],stylesheet:"pagination.css"},{attribute:"data-size",values:["md","lg"],stylesheet:"pagination.css"}],states:["default"],controlledUncontrolled:"Supports both: `page` for controlled, `defaultPage` for uncontrolled.",formBehavior:"Not applicable \u2014 Pagination does not participate in forms.",validationBehavior:"Not applicable \u2014 Pagination carries no value and participates in no validation.",accessibility:{role:'nav (labelled "Pagination" by default)',keyboard:[{key:"ArrowLeft/ArrowRight",behavior:'Moves focus between page items (no wrap). Clamped at the ends rather than ignored: the keystroke is always consumed inside the strip, so ArrowRight on the last page link does not fall through and scroll the document. Mirrored under dir="rtl".'},{key:"Enter / Space",behavior:'Activates the focused page item. A native <button> gets both keys from the platform; a role="button" host answers them itself and calls preventDefault() on Space, whose default action on a non-button is scrolling.'},{key:"Home",behavior:"Moves focus to the first page item in the strip. A collapsed strip can be long, and the two ends are the two pages a user asks for most; without this the only way back to page 1 is one arrow press per page."},{key:"End",behavior:"Moves focus to the last page item in the strip."}],ariaAttributes:['active page link sets aria-current="page"','role="list" on the List part, set explicitly because the skin removes the markers and a marker-less list loses its semantics in Safari/VoiceOver','aria-disabled="true" on a disabled link whose role="button" host never matches :disabled',`every Page carries an aria-label, defaulting to "Go to page {page}" and to "Page {page}, current page" while active \u2014 a page button's visible label is its own digit, which announces as a number and a widget and says nothing about navigating`],namingRequirement:'Every Page needs an accessible name that is not just its own digit. The packages default it to "Go to page {page}", or "Page {page}, current page" on the active one; a consumer-supplied aria-label replaces it, which is how the four boundary controls set their own names. The wording comes from the root labels object, so a whole strip is translated in one place rather than one aria-label at a time. assertPaginationPageContract in @skdx/shared/testing rejects a link whose accessible name is empty or is its bare visible number.',focusManagement:`Every enabled page item is a tab stop; arrow keys move focus within the strip without changing the page. Not a roving tabindex: nothing writes tabindex="-1" on the unfocused items. Home and End jump to the ends of the strip. A disabled item \u2014 its own disabled, or the root's \u2014 is out of the candidate list, so the arrows step over it.`},styling:{cssParts:["root","list","item","page","first","previous","next","last","ellipsis","status"],dataAttributes:[...e,"data-state","data-disabled","data-skdx-pagination-item","data-density","data-size",{name:"data-skdx-pagination-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-pagination-control-size","--skdx-pagination-font-size","--skdx-pagination-gap"]},publicMethods:[]};export{a as paginationContract};
@@ -0,0 +1,6 @@
1
+ import type { ComponentContract } from './types.js';
2
+ /**
3
+ * A TextField with a visibility layer: a toggle that flips `type` between
4
+ * password and text and reports its state through `aria-pressed`.
5
+ */
6
+ export declare const passwordInputContract: ComponentContract;