@kouji-ui/core 0.0.3 → 0.1.1

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 (534) hide show
  1. package/.turbo/turbo-build.log +6 -3
  2. package/CHANGELOG.md +177 -0
  3. package/ng-package.json +5 -1
  4. package/package.json +18 -6
  5. package/src/a11y/aria-describedby.ts +7 -3
  6. package/src/a11y/aria-labelledby.spec.ts +55 -0
  7. package/src/a11y/aria-labelledby.ts +38 -0
  8. package/src/a11y/focus-trap.ts +4 -2
  9. package/src/a11y/index.ts +1 -0
  10. package/src/a11y/live-region.ts +4 -2
  11. package/src/a11y/roving-tabindex.spec.ts +139 -0
  12. package/src/a11y/roving-tabindex.ts +56 -7
  13. package/src/a11y/visually-hidden.ts +4 -2
  14. package/src/accordion/accordion.context.ts +22 -0
  15. package/src/accordion/accordion.spec.ts +233 -23
  16. package/src/accordion/accordion.ts +311 -39
  17. package/src/accordion/index.ts +8 -2
  18. package/src/alert/alert.context.ts +28 -0
  19. package/src/alert/alert.spec.ts +217 -0
  20. package/src/alert/alert.ts +417 -0
  21. package/src/alert/config.ts +46 -0
  22. package/src/alert/index.ts +19 -0
  23. package/src/avatar/avatar-group.context.ts +45 -0
  24. package/src/avatar/avatar-group.spec.ts +358 -0
  25. package/src/avatar/avatar-group.ts +259 -0
  26. package/src/avatar/avatar.ts +17 -4
  27. package/src/avatar/index.ts +11 -1
  28. package/src/badge/badge.spec.ts +8 -0
  29. package/src/badge/badge.ts +24 -3
  30. package/src/breadcrumb/breadcrumb-current.ts +38 -0
  31. package/src/breadcrumb/breadcrumb-ellipsis.ts +71 -0
  32. package/src/breadcrumb/breadcrumb-item.ts +41 -0
  33. package/src/breadcrumb/breadcrumb-link.ts +44 -0
  34. package/src/breadcrumb/breadcrumb-list.ts +42 -0
  35. package/src/breadcrumb/breadcrumb-separator.ts +45 -0
  36. package/src/breadcrumb/breadcrumb.context.ts +45 -0
  37. package/src/breadcrumb/breadcrumb.spec.ts +354 -0
  38. package/src/breadcrumb/breadcrumb.ts +239 -0
  39. package/src/breadcrumb/config.ts +84 -0
  40. package/src/breadcrumb/index.ts +18 -0
  41. package/src/button/_examples/button.example.ts +71 -0
  42. package/src/button/_examples/button.finance.example.ts +83 -0
  43. package/src/button/_examples/button.retro.example.ts +91 -0
  44. package/src/button/_examples/button.sizes.example.ts +60 -0
  45. package/src/button/_examples/index.ts +6 -0
  46. package/src/button/button.spec.ts +139 -8
  47. package/src/button/button.ts +114 -16
  48. package/src/button/config.spec.ts +33 -0
  49. package/src/button/config.ts +45 -0
  50. package/src/button/index.ts +2 -1
  51. package/src/button-group/button-group.context.ts +28 -0
  52. package/src/button-group/button-group.spec.ts +99 -0
  53. package/src/button-group/button-group.ts +99 -0
  54. package/src/button-group/index.ts +2 -0
  55. package/src/calendar/calendar-day.ts +102 -0
  56. package/src/calendar/calendar-grid.ts +90 -0
  57. package/src/calendar/calendar-header.ts +65 -0
  58. package/src/calendar/calendar.context.ts +53 -0
  59. package/src/calendar/calendar.spec.ts +225 -0
  60. package/src/calendar/calendar.ts +233 -0
  61. package/src/calendar/date-utils.ts +225 -0
  62. package/src/calendar/index.ts +28 -0
  63. package/src/carousel/carousel.context.ts +81 -0
  64. package/src/carousel/carousel.spec.ts +337 -0
  65. package/src/carousel/carousel.ts +919 -0
  66. package/src/carousel/index.ts +22 -0
  67. package/src/cascade-select/cascade-select-option.ts +205 -0
  68. package/src/cascade-select/cascade-select-panel.ts +106 -0
  69. package/src/cascade-select/cascade-select-root.ts +265 -0
  70. package/src/cascade-select/cascade-select-sub-panel.ts +168 -0
  71. package/src/cascade-select/cascade-select-trigger.ts +44 -0
  72. package/src/cascade-select/cascade-select.context.ts +71 -0
  73. package/src/cascade-select/cascade-select.spec.ts +241 -0
  74. package/src/cascade-select/cascade-select.ts +5 -0
  75. package/src/cascade-select/index.ts +11 -0
  76. package/src/chart/chart.ts +6 -2
  77. package/src/chat/chat-avatar.ts +31 -0
  78. package/src/chat/chat-bubble.ts +49 -0
  79. package/src/chat/chat-footer.ts +67 -0
  80. package/src/chat/chat-header.ts +41 -0
  81. package/src/chat/chat-log.ts +43 -0
  82. package/src/chat/chat.context.ts +64 -0
  83. package/src/chat/chat.spec.ts +341 -0
  84. package/src/chat/chat.ts +191 -0
  85. package/src/chat/config.ts +53 -0
  86. package/src/chat/index.ts +21 -0
  87. package/src/checkbox/checkbox.ts +9 -2
  88. package/src/color-picker/color-picker.context.ts +74 -0
  89. package/src/color-picker/color-picker.spec.ts +241 -0
  90. package/src/color-picker/color-picker.ts +698 -0
  91. package/src/color-picker/color-picker.utils.ts +140 -0
  92. package/src/color-picker/index.ts +28 -0
  93. package/src/combobox/combobox-input.ts +143 -0
  94. package/src/combobox/combobox-listbox.ts +49 -0
  95. package/src/combobox/combobox-option.ts +43 -0
  96. package/src/combobox/combobox-root.ts +281 -0
  97. package/src/combobox/combobox.spec.ts +75 -0
  98. package/src/combobox/combobox.ts +4 -0
  99. package/src/combobox/index.ts +4 -0
  100. package/src/command-palette/command-empty.ts +36 -0
  101. package/src/command-palette/command-group.ts +21 -0
  102. package/src/command-palette/command-input.ts +70 -0
  103. package/src/command-palette/command-item.ts +60 -0
  104. package/src/command-palette/command-list.ts +25 -0
  105. package/src/command-palette/command-palette-dialog.ts +74 -0
  106. package/src/command-palette/command-palette-trigger.ts +64 -0
  107. package/src/command-palette/command-palette.filters.ts +53 -0
  108. package/src/command-palette/command-palette.spec.ts +349 -0
  109. package/src/command-palette/command-palette.ts +204 -0
  110. package/src/command-palette/command-separator.ts +18 -0
  111. package/src/command-palette/index.ts +15 -0
  112. package/src/confirm-popup/confirm-popup-action.ts +39 -0
  113. package/src/confirm-popup/confirm-popup-cancel.ts +38 -0
  114. package/src/confirm-popup/confirm-popup-content.ts +113 -0
  115. package/src/confirm-popup/confirm-popup-message.ts +36 -0
  116. package/src/confirm-popup/confirm-popup-trigger.ts +31 -0
  117. package/src/confirm-popup/confirm-popup.context.ts +41 -0
  118. package/src/confirm-popup/confirm-popup.spec.ts +337 -0
  119. package/src/confirm-popup/confirm-popup.ts +109 -0
  120. package/src/confirm-popup/index.ts +12 -0
  121. package/src/date-picker/date-picker-calendar.ts +65 -0
  122. package/src/date-picker/date-picker-trigger.ts +215 -0
  123. package/src/date-picker/date-picker.context.ts +50 -0
  124. package/src/date-picker/date-picker.spec.ts +117 -0
  125. package/src/date-picker/date-picker.ts +127 -0
  126. package/src/date-picker/index.ts +7 -0
  127. package/src/dialog/_examples/dialog.confirm.example.ts +145 -0
  128. package/src/dialog/_examples/dialog.example.ts +106 -0
  129. package/src/dialog/_examples/dialog.finance.example.ts +121 -0
  130. package/src/dialog/_examples/dialog.retro.example.ts +126 -0
  131. package/src/dialog/_examples/index.ts +6 -0
  132. package/src/dialog/dialog.ref.ts +42 -0
  133. package/src/dialog/dialog.service.ts +57 -167
  134. package/src/dialog/dialog.spec.ts +35 -120
  135. package/src/dialog/dialog.ts +17 -192
  136. package/src/dialog/index.ts +3 -9
  137. package/src/divider/divider.spec.ts +223 -0
  138. package/src/divider/divider.ts +137 -0
  139. package/src/divider/index.ts +5 -0
  140. package/src/drawer/drawer.ref.ts +63 -0
  141. package/src/drawer/drawer.service.ts +106 -0
  142. package/src/drawer/drawer.spec.ts +117 -0
  143. package/src/drawer/drawer.ts +122 -0
  144. package/src/drawer/index.ts +10 -0
  145. package/src/dropdown-menu/dropdown-menu-content.ts +258 -0
  146. package/src/dropdown-menu/dropdown-menu-group.ts +31 -0
  147. package/src/dropdown-menu/dropdown-menu-item.ts +51 -0
  148. package/src/dropdown-menu/dropdown-menu-label.ts +41 -0
  149. package/src/dropdown-menu/dropdown-menu-separator.ts +27 -0
  150. package/src/dropdown-menu/dropdown-menu-trigger.ts +140 -0
  151. package/src/dropdown-menu/dropdown-menu.spec.ts +265 -0
  152. package/src/dropdown-menu/dropdown-menu.ts +60 -0
  153. package/src/dropdown-menu/index.ts +15 -0
  154. package/src/example-components.ts +39 -30
  155. package/src/field/field-error.ts +49 -0
  156. package/src/field/field-group.ts +39 -0
  157. package/src/field/field-help.ts +47 -0
  158. package/src/field/field-label.ts +30 -0
  159. package/src/field/field.context.ts +28 -0
  160. package/src/field/field.spec.ts +179 -0
  161. package/src/field/field.ts +121 -0
  162. package/src/field/index.ts +6 -0
  163. package/src/file-upload/file-upload.context.ts +89 -0
  164. package/src/file-upload/file-upload.spec.ts +290 -0
  165. package/src/file-upload/file-upload.ts +639 -0
  166. package/src/file-upload/file-upload.types.ts +59 -0
  167. package/src/file-upload/index.ts +23 -0
  168. package/src/form/form-error-summary.ts +87 -0
  169. package/src/form/form-field.context.ts +3 -0
  170. package/src/form/form-field.spec.ts +25 -0
  171. package/src/form/form-field.ts +52 -0
  172. package/src/form/form.context.ts +52 -2
  173. package/src/form/form.spec.ts +155 -18
  174. package/src/form/form.ts +315 -35
  175. package/src/form/index.ts +11 -2
  176. package/src/icon/E2E.md +14 -0
  177. package/src/icon/icon.css +40 -0
  178. package/src/icon/icon.directive.spec.ts +198 -0
  179. package/src/icon/icon.directive.ts +113 -0
  180. package/src/icon/icon.mode.spec.ts +29 -0
  181. package/src/icon/icon.mode.ts +23 -0
  182. package/src/icon/icon.providers.spec.ts +63 -0
  183. package/src/icon/icon.providers.ts +47 -0
  184. package/src/icon/icon.resolver.spec.ts +96 -0
  185. package/src/icon/icon.resolver.ts +49 -0
  186. package/src/icon/icon.tokens.ts +88 -0
  187. package/src/icon/icon.types.ts +48 -0
  188. package/src/icon/index.ts +21 -0
  189. package/src/input/input.ts +12 -3
  190. package/src/input-group/index.ts +3 -0
  191. package/src/input-group/input-group-addon.ts +92 -0
  192. package/src/input-group/input-group.context.ts +27 -0
  193. package/src/input-group/input-group.spec.ts +186 -0
  194. package/src/input-group/input-group.ts +136 -0
  195. package/src/input-mask/index.ts +11 -0
  196. package/src/input-mask/input-mask.compile.ts +69 -0
  197. package/src/input-mask/input-mask.engine.ts +376 -0
  198. package/src/input-mask/input-mask.presets.ts +24 -0
  199. package/src/input-mask/input-mask.spec.ts +304 -0
  200. package/src/input-mask/input-mask.tokens.ts +49 -0
  201. package/src/input-mask/input-mask.ts +280 -0
  202. package/src/input-otp/index.ts +2 -0
  203. package/src/input-otp/input-otp.context.ts +41 -0
  204. package/src/input-otp/input-otp.spec.ts +308 -0
  205. package/src/input-otp/input-otp.ts +470 -0
  206. package/src/kbd/index.ts +1 -0
  207. package/src/kbd/kbd.spec.ts +127 -0
  208. package/src/kbd/kbd.ts +132 -0
  209. package/src/link/config.ts +44 -0
  210. package/src/link/index.ts +2 -0
  211. package/src/link/link.spec.ts +246 -0
  212. package/src/link/link.ts +226 -0
  213. package/src/list/index.ts +11 -0
  214. package/src/list/list.spec.ts +237 -0
  215. package/src/list/list.ts +277 -0
  216. package/src/menubar/index.ts +7 -0
  217. package/src/menubar/menubar-item.ts +204 -0
  218. package/src/menubar/menubar.context.ts +43 -0
  219. package/src/menubar/menubar.spec.ts +433 -0
  220. package/src/menubar/menubar.ts +309 -0
  221. package/src/number-input/index.ts +4 -0
  222. package/src/number-input/number-input-group.ts +64 -0
  223. package/src/number-input/number-input.context.ts +31 -0
  224. package/src/number-input/number-input.format.ts +148 -0
  225. package/src/number-input/number-input.spec.ts +170 -0
  226. package/src/number-input/number-input.ts +457 -0
  227. package/src/number-input/number-stepper.ts +193 -0
  228. package/src/overlay-badge/index.ts +7 -0
  229. package/src/overlay-badge/overlay-badge-content.ts +73 -0
  230. package/src/overlay-badge/overlay-badge.context.ts +37 -0
  231. package/src/overlay-badge/overlay-badge.spec.ts +220 -0
  232. package/src/overlay-badge/overlay-badge.ts +128 -0
  233. package/src/pagination/config.ts +82 -0
  234. package/src/pagination/index.ts +19 -0
  235. package/src/pagination/page-tokens.ts +78 -0
  236. package/src/pagination/pagination-ellipsis.ts +69 -0
  237. package/src/pagination/pagination-first.ts +84 -0
  238. package/src/pagination/pagination-info.ts +70 -0
  239. package/src/pagination/pagination-item.ts +81 -0
  240. package/src/pagination/pagination-last.ts +85 -0
  241. package/src/pagination/pagination-next.ts +86 -0
  242. package/src/pagination/pagination-previous.ts +90 -0
  243. package/src/pagination/pagination.context.ts +52 -0
  244. package/src/pagination/pagination.spec.ts +388 -0
  245. package/src/pagination/pagination.ts +288 -0
  246. package/src/password-input/index.ts +15 -0
  247. package/src/password-input/password-input.context.ts +65 -0
  248. package/src/password-input/password-input.scorer.ts +34 -0
  249. package/src/password-input/password-input.spec.ts +274 -0
  250. package/src/password-input/password-input.ts +488 -0
  251. package/src/popover/_examples/index.ts +5 -0
  252. package/src/popover/_examples/popover.example.ts +92 -0
  253. package/src/popover/_examples/popover.finance.example.ts +106 -0
  254. package/src/popover/_examples/popover.retro.example.ts +103 -0
  255. package/src/popover/index.ts +5 -12
  256. package/src/popover/popover-arrow.ts +30 -0
  257. package/src/popover/popover-close.ts +36 -0
  258. package/src/popover/popover-content.ts +41 -0
  259. package/src/popover/popover-title.ts +39 -0
  260. package/src/popover/popover-trigger.ts +40 -0
  261. package/src/popover/popover.spec.ts +51 -44
  262. package/src/popover/popover.ts +5 -124
  263. package/src/presets/bind-presets.spec.ts +50 -0
  264. package/src/presets/bind-presets.ts +43 -0
  265. package/src/presets/index.ts +3 -0
  266. package/src/presets/size.spec.ts +67 -0
  267. package/src/presets/size.ts +59 -0
  268. package/src/presets/variant.spec.ts +72 -0
  269. package/src/presets/variant.ts +62 -0
  270. package/src/primitives/directionality/directionality.spec.ts +112 -0
  271. package/src/primitives/directionality/directionality.ts +89 -0
  272. package/src/primitives/directionality/index.ts +1 -0
  273. package/src/primitives/forms/form-control.spec.ts +14 -6
  274. package/src/primitives/forms/form-control.ts +6 -2
  275. package/src/primitives/index.ts +3 -0
  276. package/src/primitives/interaction/disabled.ts +12 -5
  277. package/src/primitives/interaction/focus-ring.ts +4 -2
  278. package/src/primitives/list/filterable-list.spec.ts +114 -0
  279. package/src/primitives/list/filterable-list.ts +126 -0
  280. package/src/primitives/list/group.spec.ts +99 -0
  281. package/src/primitives/list/group.ts +139 -0
  282. package/src/primitives/list/index.ts +8 -0
  283. package/src/primitives/list/inject-helpers.ts +8 -0
  284. package/src/primitives/list/item.spec.ts +173 -0
  285. package/src/primitives/list/item.ts +222 -0
  286. package/src/primitives/list/navigator.spec.ts +286 -0
  287. package/src/primitives/list/navigator.ts +238 -0
  288. package/src/primitives/list/selection.spec.ts +214 -0
  289. package/src/primitives/list/selection.ts +339 -0
  290. package/src/primitives/list/tokens.ts +106 -0
  291. package/src/primitives/list/type-ahead.spec.ts +58 -0
  292. package/src/primitives/list/type-ahead.ts +46 -0
  293. package/src/primitives/overlay/backdrop.spec.ts +54 -0
  294. package/src/primitives/overlay/backdrop.ts +31 -0
  295. package/src/primitives/overlay/builder.spec.ts +38 -0
  296. package/src/primitives/overlay/builder.ts +151 -0
  297. package/src/primitives/overlay/container.ts +42 -0
  298. package/src/primitives/overlay/context.ts +14 -0
  299. package/src/primitives/overlay/controller.spec.ts +86 -0
  300. package/src/primitives/overlay/controller.ts +190 -0
  301. package/src/primitives/overlay/id.spec.ts +24 -0
  302. package/src/primitives/overlay/id.ts +17 -0
  303. package/src/primitives/overlay/index.ts +18 -1
  304. package/src/primitives/overlay/overlay.css +42 -0
  305. package/src/primitives/overlay/panel.spec.ts +52 -0
  306. package/src/primitives/overlay/panel.ts +102 -0
  307. package/src/primitives/overlay/stack.spec.ts +55 -0
  308. package/src/primitives/overlay/stack.ts +113 -0
  309. package/src/primitives/overlay/strategies/backdrop/blurred.spec.ts +11 -0
  310. package/src/primitives/overlay/strategies/backdrop/blurred.ts +5 -0
  311. package/src/primitives/overlay/strategies/backdrop/none.spec.ts +10 -0
  312. package/src/primitives/overlay/strategies/backdrop/none.ts +9 -0
  313. package/src/primitives/overlay/strategies/backdrop/solid.spec.ts +18 -0
  314. package/src/primitives/overlay/strategies/backdrop/solid.ts +23 -0
  315. package/src/primitives/overlay/strategies/focus-trap/inert-based.spec.ts +28 -0
  316. package/src/primitives/overlay/strategies/focus-trap/inert-based.ts +38 -0
  317. package/src/primitives/overlay/strategies/focus-trap/no-trap.spec.ts +9 -0
  318. package/src/primitives/overlay/strategies/focus-trap/no-trap.ts +8 -0
  319. package/src/primitives/overlay/strategies/focus-trap/tab-cycle.spec.ts +49 -0
  320. package/src/primitives/overlay/strategies/focus-trap/tab-cycle.ts +85 -0
  321. package/src/primitives/overlay/strategies/index.ts +34 -0
  322. package/src/primitives/overlay/strategies/live-announcer/_announce.ts +35 -0
  323. package/src/primitives/overlay/strategies/live-announcer/assertive.spec.ts +21 -0
  324. package/src/primitives/overlay/strategies/live-announcer/assertive.ts +11 -0
  325. package/src/primitives/overlay/strategies/live-announcer/polite.spec.ts +21 -0
  326. package/src/primitives/overlay/strategies/live-announcer/polite.ts +11 -0
  327. package/src/primitives/overlay/strategies/live-announcer/silent.spec.ts +12 -0
  328. package/src/primitives/overlay/strategies/live-announcer/silent.ts +5 -0
  329. package/src/primitives/overlay/strategies/mount/body-portal.spec.ts +40 -0
  330. package/src/primitives/overlay/strategies/mount/body-portal.ts +91 -0
  331. package/src/primitives/overlay/strategies/mount/in-container.spec.ts +43 -0
  332. package/src/primitives/overlay/strategies/mount/in-container.ts +39 -0
  333. package/src/primitives/overlay/strategies/mount/in-place.spec.ts +40 -0
  334. package/src/primitives/overlay/strategies/mount/in-place.ts +20 -0
  335. package/src/primitives/overlay/strategies/position/anchored-to.spec.ts +56 -0
  336. package/src/primitives/overlay/strategies/position/anchored-to.ts +248 -0
  337. package/src/primitives/overlay/strategies/position/corner.spec.ts +36 -0
  338. package/src/primitives/overlay/strategies/position/corner.ts +33 -0
  339. package/src/primitives/overlay/strategies/position/edge-sheet.spec.ts +32 -0
  340. package/src/primitives/overlay/strategies/position/edge-sheet.ts +36 -0
  341. package/src/primitives/overlay/strategies/position/in-place-sibling.spec.ts +25 -0
  342. package/src/primitives/overlay/strategies/position/in-place-sibling.ts +13 -0
  343. package/src/primitives/overlay/strategies/position/point-at.spec.ts +40 -0
  344. package/src/primitives/overlay/strategies/position/point-at.ts +34 -0
  345. package/src/primitives/overlay/strategies/position/viewport-centered.spec.ts +31 -0
  346. package/src/primitives/overlay/strategies/position/viewport-centered.ts +31 -0
  347. package/src/primitives/overlay/strategies/scroll-lock/css-clip.spec.ts +15 -0
  348. package/src/primitives/overlay/strategies/scroll-lock/css-clip.ts +39 -0
  349. package/src/primitives/overlay/strategies/scroll-lock/html-overflow.spec.ts +21 -0
  350. package/src/primitives/overlay/strategies/scroll-lock/html-overflow.ts +44 -0
  351. package/src/primitives/overlay/strategies/scroll-lock/none.spec.ts +9 -0
  352. package/src/primitives/overlay/strategies/scroll-lock/none.ts +5 -0
  353. package/src/primitives/overlay/strategies/trigger-event/on-click.spec.ts +32 -0
  354. package/src/primitives/overlay/strategies/trigger-event/on-click.ts +28 -0
  355. package/src/primitives/overlay/strategies/trigger-event/on-context-menu.spec.ts +45 -0
  356. package/src/primitives/overlay/strategies/trigger-event/on-context-menu.ts +70 -0
  357. package/src/primitives/overlay/strategies/trigger-event/on-focus-or-input.spec.ts +35 -0
  358. package/src/primitives/overlay/strategies/trigger-event/on-focus-or-input.ts +34 -0
  359. package/src/primitives/overlay/strategies/trigger-event/on-focus.spec.ts +64 -0
  360. package/src/primitives/overlay/strategies/trigger-event/on-focus.ts +37 -0
  361. package/src/primitives/overlay/strategies/trigger-event/on-hotkey.spec.ts +37 -0
  362. package/src/primitives/overlay/strategies/trigger-event/on-hotkey.ts +59 -0
  363. package/src/primitives/overlay/strategies/trigger-event/on-hover.spec.ts +34 -0
  364. package/src/primitives/overlay/strategies/trigger-event/on-hover.ts +86 -0
  365. package/src/primitives/overlay/strategies/trigger-event/programmatic.spec.ts +16 -0
  366. package/src/primitives/overlay/strategies/trigger-event/programmatic.ts +12 -0
  367. package/src/primitives/overlay/tokens.ts +54 -0
  368. package/src/primitives/overlay/trigger.spec.ts +103 -0
  369. package/src/primitives/overlay/trigger.ts +75 -0
  370. package/src/primitives/overlay/types.ts +24 -0
  371. package/src/primitives/overlay/wrapper.ts +50 -0
  372. package/src/primitives/signals/deep-signal.ts +109 -0
  373. package/src/primitives/signals/index.ts +1 -0
  374. package/src/progress-bar/config.ts +48 -0
  375. package/src/progress-bar/index.ts +12 -0
  376. package/src/progress-bar/progress-bar-fill.ts +37 -0
  377. package/src/progress-bar/progress-bar.context.ts +34 -0
  378. package/src/progress-bar/progress-bar.spec.ts +423 -0
  379. package/src/progress-bar/progress-bar.ts +217 -0
  380. package/src/public-api.ts +58 -9
  381. package/src/radio/radio.ts +14 -3
  382. package/src/select/index.ts +4 -2
  383. package/src/select/select-content.ts +69 -0
  384. package/src/select/select-option.ts +35 -0
  385. package/src/select/select-root.ts +129 -0
  386. package/src/select/select-trigger.ts +93 -0
  387. package/src/select/select.spec.ts +133 -140
  388. package/src/select/select.ts +4 -250
  389. package/src/skeleton/index.ts +5 -0
  390. package/src/skeleton/skeleton.spec.ts +115 -0
  391. package/src/skeleton/skeleton.ts +56 -0
  392. package/src/slider/index.ts +10 -0
  393. package/src/slider/slider-range.ts +49 -0
  394. package/src/slider/slider-thumb.ts +335 -0
  395. package/src/slider/slider-track.ts +70 -0
  396. package/src/slider/slider.context.ts +79 -0
  397. package/src/slider/slider.geometry.ts +73 -0
  398. package/src/slider/slider.spec.ts +216 -0
  399. package/src/slider/slider.ts +443 -0
  400. package/src/speed-dial/index.ts +10 -0
  401. package/src/speed-dial/speed-dial-action.ts +40 -0
  402. package/src/speed-dial/speed-dial-actions.ts +31 -0
  403. package/src/speed-dial/speed-dial-trigger.ts +55 -0
  404. package/src/speed-dial/speed-dial.context.ts +36 -0
  405. package/src/speed-dial/speed-dial.spec.ts +143 -0
  406. package/src/speed-dial/speed-dial.ts +127 -0
  407. package/src/spinner/config.ts +48 -0
  408. package/src/spinner/index.ts +8 -0
  409. package/src/spinner/spinner.spec.ts +262 -0
  410. package/src/spinner/spinner.ts +129 -0
  411. package/src/stepper/index.ts +15 -0
  412. package/src/stepper/stepper.context.ts +63 -0
  413. package/src/stepper/stepper.spec.ts +403 -0
  414. package/src/stepper/stepper.ts +544 -0
  415. package/src/styles.css +17 -0
  416. package/src/table/column-helpers.spec.ts +74 -0
  417. package/src/table/column-helpers.ts +68 -0
  418. package/src/table/filter-fns.ts +230 -0
  419. package/src/table/filter-models.spec.ts +240 -0
  420. package/src/table/filter-models.ts +124 -0
  421. package/src/table/filter-params.ts +90 -0
  422. package/src/table/grid-api-impl.ts +321 -0
  423. package/src/table/grid-api.spec.ts +178 -0
  424. package/src/table/grid-api.ts +285 -0
  425. package/src/table/index.ts +73 -1
  426. package/src/table/table-cell.spec.ts +43 -0
  427. package/src/table/table-cell.ts +38 -0
  428. package/src/table/table-filter-outlet.ts +120 -0
  429. package/src/table/table-header.spec.ts +54 -0
  430. package/src/table/table-header.ts +63 -0
  431. package/src/table/table-keyboard.spec.ts +68 -0
  432. package/src/table/table-keyboard.ts +107 -0
  433. package/src/table/table-resource.spec.ts +37 -0
  434. package/src/table/table-resource.ts +36 -0
  435. package/src/table/table-row.spec.ts +54 -0
  436. package/src/table/table-row.ts +31 -0
  437. package/src/table/table-storage.spec.ts +67 -0
  438. package/src/table/table-storage.ts +76 -0
  439. package/src/table/table.spec.ts +102 -43
  440. package/src/table/table.ts +228 -73
  441. package/src/table/table.types.ts +83 -0
  442. package/src/tabs/index.ts +7 -2
  443. package/src/tabs/tabs.context.ts +27 -4
  444. package/src/tabs/tabs.spec.ts +336 -24
  445. package/src/tabs/tabs.ts +313 -79
  446. package/src/tag/config.ts +53 -0
  447. package/src/tag/index.ts +7 -0
  448. package/src/tag/tag-list.ts +76 -0
  449. package/src/tag/tag-remove.ts +61 -0
  450. package/src/tag/tag.context.ts +36 -0
  451. package/src/tag/tag.spec.ts +240 -0
  452. package/src/tag/tag.ts +203 -0
  453. package/src/textarea/config.ts +42 -0
  454. package/src/textarea/index.ts +8 -0
  455. package/src/textarea/textarea.spec.ts +176 -0
  456. package/src/textarea/textarea.ts +235 -0
  457. package/src/time-picker/index.ts +15 -0
  458. package/src/time-picker/time-picker-meridiem.ts +123 -0
  459. package/src/time-picker/time-picker-segment.ts +318 -0
  460. package/src/time-picker/time-picker.context.ts +38 -0
  461. package/src/time-picker/time-picker.format.ts +181 -0
  462. package/src/time-picker/time-picker.spec.ts +189 -0
  463. package/src/time-picker/time-picker.ts +274 -0
  464. package/src/toast/_examples/index.ts +5 -0
  465. package/src/toast/_examples/toast.example.ts +282 -0
  466. package/src/toast/_examples/toast.finance.example.ts +180 -0
  467. package/src/toast/_examples/toast.retro.example.ts +161 -0
  468. package/src/toast/index.ts +8 -1
  469. package/src/toast/toast.ref.ts +26 -0
  470. package/src/toast/toast.service.ts +227 -41
  471. package/src/toast/toast.spec.ts +178 -25
  472. package/src/toast/toast.strategy.ts +10 -0
  473. package/src/toast/toast.ts +178 -22
  474. package/src/toggle/toggle.ts +10 -2
  475. package/src/tooltip/_examples/index.ts +6 -0
  476. package/src/tooltip/_examples/tooltip.example.ts +82 -0
  477. package/src/tooltip/_examples/tooltip.finance.example.ts +97 -0
  478. package/src/tooltip/_examples/tooltip.placements.example.ts +83 -0
  479. package/src/tooltip/_examples/tooltip.retro.example.ts +107 -0
  480. package/src/tooltip/index.ts +4 -5
  481. package/src/tooltip/tooltip-arrow.ts +31 -0
  482. package/src/tooltip/tooltip-content.ts +38 -0
  483. package/src/tooltip/tooltip-group.ts +32 -0
  484. package/src/tooltip/tooltip-trigger.ts +47 -0
  485. package/src/tooltip/tooltip.spec.ts +38 -102
  486. package/src/tooltip/tooltip.ts +5 -129
  487. package/src/tree-select/index.ts +12 -0
  488. package/src/tree-select/tree-select-content.ts +199 -0
  489. package/src/tree-select/tree-select-node.ts +132 -0
  490. package/src/tree-select/tree-select-root.ts +272 -0
  491. package/src/tree-select/tree-select-trigger.ts +90 -0
  492. package/src/tree-select/tree-select.context.ts +63 -0
  493. package/src/tree-select/tree-select.spec.ts +433 -0
  494. package/src/tree-select/tree-select.ts +2 -0
  495. package/src/typography/blockquote.ts +57 -0
  496. package/src/typography/code.ts +53 -0
  497. package/src/typography/index.ts +22 -0
  498. package/src/typography/lead.ts +49 -0
  499. package/src/typography/muted.ts +29 -0
  500. package/src/typography/prose.css +312 -0
  501. package/src/typography/truncate.ts +99 -0
  502. package/src/typography/typography.spec.ts +203 -0
  503. package/tsconfig.lib.json +9 -1
  504. package/tsconfig.lib.prod.json +7 -1
  505. package/tsconfig.spec.json +9 -1
  506. package/vite.config.ts +8 -0
  507. package/src/button/button.example.ts +0 -30
  508. package/src/button/button.finance.example.ts +0 -37
  509. package/src/button/button.retro.example.ts +0 -47
  510. package/src/button/button.sizes.example.ts +0 -25
  511. package/src/dialog/dialog.confirm.example.ts +0 -57
  512. package/src/dialog/dialog.context.ts +0 -11
  513. package/src/dialog/dialog.example.ts +0 -40
  514. package/src/dialog/dialog.finance.example.ts +0 -47
  515. package/src/dialog/dialog.retro.example.ts +0 -46
  516. package/src/menu/index.ts +0 -2
  517. package/src/menu/menu.context.ts +0 -10
  518. package/src/menu/menu.example.ts +0 -39
  519. package/src/menu/menu.spec.ts +0 -168
  520. package/src/menu/menu.ts +0 -176
  521. package/src/popover/popover.context.ts +0 -18
  522. package/src/popover/popover.example.ts +0 -50
  523. package/src/popover/popover.finance.example.ts +0 -52
  524. package/src/popover/popover.retro.example.ts +0 -53
  525. package/src/primitives/overlay/overlay.spec.ts +0 -90
  526. package/src/primitives/overlay/overlay.ts +0 -102
  527. package/src/select/select.context.ts +0 -3
  528. package/src/toast/toast.example.ts +0 -134
  529. package/src/toast/toast.finance.example.ts +0 -68
  530. package/src/toast/toast.retro.example.ts +0 -69
  531. package/src/tooltip/tooltip.example.ts +0 -46
  532. package/src/tooltip/tooltip.finance.example.ts +0 -54
  533. package/src/tooltip/tooltip.placements.example.ts +0 -56
  534. package/src/tooltip/tooltip.retro.example.ts +0 -65
@@ -1,126 +1,398 @@
1
- import { Directive, computed, inject, input, signal } from '@angular/core';
2
- import { KJ_ACCORDION, KJ_ACCORDION_ITEM } from './accordion.context';
1
+ import {
2
+ Directive,
3
+ ElementRef,
4
+ OnDestroy,
5
+ OnInit,
6
+ Signal,
7
+ booleanAttribute,
8
+ computed,
9
+ effect,
10
+ inject,
11
+ input,
12
+ model,
13
+ signal,
14
+ untracked,
15
+ } from '@angular/core';
16
+ import {
17
+ KJ_ACCORDION,
18
+ KJ_ACCORDION_ITEM,
19
+ KjAccordionContext,
20
+ KjAccordionItemContext,
21
+ KjAccordionType,
22
+ } from './accordion.context';
23
+
24
+ let kjAccordionSeedCounter = 0;
25
+ function nextSeed(): string {
26
+ // Try crypto.randomUUID where available (browser, jsdom 22+, node 19+).
27
+ // Fall back to a counter so SSR / older environments still produce a stable string.
28
+ const cryptoLike = (globalThis as { crypto?: { randomUUID?: () => string } }).crypto;
29
+ if (cryptoLike?.randomUUID) return cryptoLike.randomUUID().slice(0, 8);
30
+ return `kj${(++kjAccordionSeedCounter).toString(36)}`;
31
+ }
3
32
 
4
33
  /**
5
34
  * Root accordion container. Manages open/close state for accordion items.
6
35
  * Supports `'single'` (only one item open) or `'multiple'` (any number open).
7
36
  *
37
+ * Two-way bound `kjValue` mirrors the open set as a string (single mode) or
38
+ * `string[]` (multiple mode). Internally the directive keeps a single
39
+ * `ReadonlySet<string>` so single ↔ multiple flips don't lose state.
40
+ *
41
+ * Arrow-key roving navigation is opt-in via `kjArrowNavigation`; when enabled
42
+ * the root listens for ArrowUp/ArrowDown/Home/End on registered triggers and
43
+ * moves focus between them. When disabled (the default) each trigger is a
44
+ * plain button in the page tab sequence — the WAI-ARIA APG-recommended
45
+ * arrangement for FAQ-style content.
46
+ *
8
47
  * @example
9
48
  * ```html
10
- * <div kjAccordion [kjAccordionType]="'multiple'">
11
- * <div kjAccordionItem [kjItemValue]="'item-1'">...</div>
49
+ * <div kjAccordion [(kjValue)]="open" kjType="multiple">
50
+ * <div kjAccordionItem kjItemValue="billing">
51
+ * <button kjAccordionTrigger>Billing</button>
52
+ * <div kjAccordionContent>...</div>
53
+ * </div>
12
54
  * </div>
13
55
  * ```
14
- * @category Core/Navigation
56
+ * @doc-category Core/Data display
57
+ * @doc
58
+ * @doc-name accordion
59
+ * @doc-description Unstyled accordion root that manages expand/collapse state across child accordion items.
60
+ * @doc-is-main
15
61
  */
16
62
  @Directive({
17
63
  selector: '[kjAccordion]',
18
64
  standalone: true,
19
65
  providers: [{ provide: KJ_ACCORDION, useExisting: KjAccordion }],
66
+ host: {
67
+ '[attr.data-orientation]': '"vertical"',
68
+ },
20
69
  })
21
- export class KjAccordion {
22
- /** Whether multiple items can be open simultaneously. Defaults to `'single'`. */
23
- readonly kjAccordionType = input<'single' | 'multiple'>('single');
70
+ export class KjAccordion implements KjAccordionContext {
71
+ /** Mode: `'single'` (one open at a time) or `'multiple'` (any number open). */
72
+ readonly kjType = input<KjAccordionType>('single');
73
+
74
+ /**
75
+ * Two-way bound open value. In `'single'` mode it is a string (the open
76
+ * item's value, or `''` when nothing is open); in `'multiple'` mode it is a
77
+ * `string[]` (open item values, in insertion order).
78
+ */
79
+ readonly kjValue = model<string | string[]>('');
80
+
81
+ /**
82
+ * Opt-in roving tabindex on triggers. When `true`, ArrowUp/ArrowDown/Home/End
83
+ * move focus between triggers and the group becomes a single tab stop.
84
+ * When `false` (default), each trigger is a plain button in the page tab
85
+ * sequence — the simpler arrangement for FAQ-style content where Tab also
86
+ * needs to reach links and form fields inside an open panel.
87
+ */
88
+ readonly kjArrowNavigation = input(false, { transform: booleanAttribute });
24
89
 
25
90
  private readonly _openIds = signal<ReadonlySet<string>>(new Set());
26
91
  /** Set of currently open item values. */
27
92
  readonly openIds = this._openIds.asReadonly();
28
93
 
29
- /** Toggles an item open or closed. In single mode, closes all others first. */
30
- toggle(id: string): void {
31
- this._openIds.update(ids => {
32
- const next = new Set(ids);
33
- if (next.has(id)) {
34
- next.delete(id);
35
- } else {
36
- if (this.kjAccordionType() === 'single') next.clear();
37
- next.add(id);
94
+ /** Read-only view of `kjType` for context consumers. */
95
+ readonly type: Signal<KjAccordionType> = this.kjType;
96
+
97
+ /** Read-only view of `kjArrowNavigation` for context consumers. */
98
+ readonly arrowNavigation: Signal<boolean> = this.kjArrowNavigation;
99
+
100
+ /** @internal Registered triggers in document order — for arrow-key roving. */
101
+ private readonly _triggers = signal<readonly KjAccordionTrigger[]>([]);
102
+
103
+ /** Public read-only registration list, in document order. */
104
+ readonly triggers = this._triggers.asReadonly();
105
+
106
+ constructor() {
107
+ // Reconcile incoming kjValue → internal _openIds (controlled binding).
108
+ effect(() => {
109
+ const v = this.kjValue();
110
+ const next = new Set<string>();
111
+ if (typeof v === 'string') {
112
+ if (v) next.add(v);
113
+ } else if (Array.isArray(v)) {
114
+ for (const id of v) if (id) next.add(id);
38
115
  }
39
- return next;
116
+ // In single mode, only first wins.
117
+ if (this.kjType() === 'single' && next.size > 1) {
118
+ const [first] = next;
119
+ next.clear();
120
+ next.add(first);
121
+ }
122
+ // Avoid set-equal write loops with the toggle path.
123
+ const current = untracked(this._openIds);
124
+ if (!setsEqual(current, next)) this._openIds.set(next);
40
125
  });
41
126
  }
42
127
 
128
+ /** Toggles an item open or closed. In single mode, closes all others first. */
129
+ toggle(id: string): void {
130
+ const next = new Set(this._openIds());
131
+ if (next.has(id)) {
132
+ next.delete(id);
133
+ } else {
134
+ if (this.kjType() === 'single') next.clear();
135
+ next.add(id);
136
+ }
137
+ this._openIds.set(next);
138
+ this.syncModelFromSet(next);
139
+ }
140
+
43
141
  /** Returns whether the given item value is currently open. */
44
142
  isOpen(id: string): boolean {
45
143
  return this._openIds().has(id);
46
144
  }
145
+
146
+ /** @internal Trigger registration — called from `KjAccordionTrigger.ngOnInit`. */
147
+ registerTrigger(t: KjAccordionTrigger): void {
148
+ this._triggers.update((list) => (list.includes(t) ? list : [...list, t]));
149
+ }
150
+
151
+ /** @internal Trigger un-registration — called from `KjAccordionTrigger.ngOnDestroy`. */
152
+ unregisterTrigger(t: KjAccordionTrigger): void {
153
+ this._triggers.update((list) => list.filter((x) => x !== t));
154
+ }
155
+
156
+ /** @internal Move focus by delta among non-disabled triggers. */
157
+ focusTrigger(delta: number, fromIndex: number): void {
158
+ const list = this._triggers();
159
+ if (!list.length) return;
160
+ const len = list.length;
161
+ let i = fromIndex;
162
+ for (let step = 0; step < len; step++) {
163
+ i = (i + delta + len) % len;
164
+ const t = list[i];
165
+ if (!t.item.disabled()) {
166
+ t.el.nativeElement.focus();
167
+ return;
168
+ }
169
+ }
170
+ }
171
+
172
+ /** @internal Focus first / last non-disabled trigger. */
173
+ focusEdge(edge: 'first' | 'last'): void {
174
+ const list = this._triggers();
175
+ if (!list.length) return;
176
+ const range = edge === 'first' ? list : [...list].reverse();
177
+ for (const t of range) {
178
+ if (!t.item.disabled()) {
179
+ t.el.nativeElement.focus();
180
+ return;
181
+ }
182
+ }
183
+ }
184
+
185
+ private syncModelFromSet(set: ReadonlySet<string>): void {
186
+ if (this.kjType() === 'single') {
187
+ const first = set.values().next().value ?? '';
188
+ const current = this.kjValue();
189
+ if (typeof current === 'string') {
190
+ if (current !== first) this.kjValue.set(first);
191
+ } else {
192
+ this.kjValue.set(first);
193
+ }
194
+ } else {
195
+ const arr = Array.from(set);
196
+ const current = this.kjValue();
197
+ if (Array.isArray(current) && arraysEqual(current, arr)) return;
198
+ this.kjValue.set(arr);
199
+ }
200
+ }
201
+ }
202
+
203
+ function setsEqual(a: ReadonlySet<string>, b: ReadonlySet<string>): boolean {
204
+ if (a.size !== b.size) return false;
205
+ for (const v of a) if (!b.has(v)) return false;
206
+ return true;
207
+ }
208
+
209
+ function arraysEqual(a: readonly string[], b: readonly string[]): boolean {
210
+ if (a.length !== b.length) return false;
211
+ for (let i = 0; i < a.length; i++) if (a[i] !== b[i]) return false;
212
+ return true;
47
213
  }
48
214
 
49
215
  /**
50
- * Individual accordion item. Manages its own expanded state via the parent accordion context.
216
+ * Individual accordion item. Owns the per-item `value`, `expanded` state, and
217
+ * the stable `headerId` / `contentId` pair the trigger and content use to wire
218
+ * `aria-controls` / `aria-labelledby`.
51
219
  *
52
220
  * @example
53
221
  * ```html
54
- * <div kjAccordionItem [kjItemValue]="'section-1'">
222
+ * <div kjAccordionItem kjItemValue="section-1">
55
223
  * <button kjAccordionTrigger>Section 1</button>
56
224
  * <div kjAccordionContent>Content</div>
57
225
  * </div>
58
226
  * ```
59
- * @category Core/Navigation
227
+ * @doc-category Core/Data display
228
+ * @doc
229
+ * @doc-name accordion
60
230
  */
61
231
  @Directive({
62
232
  selector: '[kjAccordionItem]',
63
233
  standalone: true,
64
234
  providers: [{ provide: KJ_ACCORDION_ITEM, useExisting: KjAccordionItem }],
235
+ host: {
236
+ '[attr.data-state]': 'expanded() ? "open" : "closed"',
237
+ '[attr.data-disabled]': 'kjItemDisabled() ? "" : null',
238
+ },
65
239
  })
66
- export class KjAccordionItem {
240
+ export class KjAccordionItem implements KjAccordionItemContext {
67
241
  private readonly accordion = inject(KJ_ACCORDION) as KjAccordion;
68
242
 
69
243
  /** The unique value identifying this item within the accordion. */
70
244
  readonly kjItemValue = input.required<string>();
71
245
 
246
+ /**
247
+ * Whether this item is disabled. Gates `toggle`/`open`/`close`, drives
248
+ * `aria-disabled` on the trigger and `data-disabled` on the item host.
249
+ */
250
+ readonly kjItemDisabled = input(false, { transform: booleanAttribute });
251
+
252
+ private readonly idSeed = nextSeed();
253
+
254
+ /** Stable id for the trigger element. */
255
+ readonly headerId = computed(() => `kj-accordion-trigger-${this.kjItemValue()}-${this.idSeed}`);
256
+
257
+ /** Stable id for the content region element. */
258
+ readonly contentId = computed(() => `kj-accordion-content-${this.kjItemValue()}-${this.idSeed}`);
259
+
260
+ /** Read-only mirror of the item value for context consumers. */
261
+ readonly value: Signal<string> = this.kjItemValue;
262
+
263
+ /** Read-only mirror of the disabled flag for context consumers. */
264
+ readonly disabled: Signal<boolean> = this.kjItemDisabled;
265
+
72
266
  /** Whether this item is currently expanded. */
73
267
  readonly expanded = computed(() => this.accordion.isOpen(this.kjItemValue()));
74
268
 
75
- /** Toggles this item's expanded state. */
76
- toggle(): void { this.accordion.toggle(this.kjItemValue()); }
269
+ /** Toggles this item's expanded state. No-op when disabled. */
270
+ toggle(): void {
271
+ if (this.kjItemDisabled()) return;
272
+ this.accordion.toggle(this.kjItemValue());
273
+ }
77
274
 
78
- /** Opens this item. */
79
- open(): void { if (!this.expanded()) this.toggle(); }
275
+ /** Opens this item. No-op when disabled. */
276
+ open(): void {
277
+ if (this.kjItemDisabled()) return;
278
+ if (!this.expanded()) this.accordion.toggle(this.kjItemValue());
279
+ }
80
280
 
81
- /** Closes this item. */
82
- close(): void { if (this.expanded()) this.toggle(); }
281
+ /** Closes this item. No-op when disabled. */
282
+ close(): void {
283
+ if (this.kjItemDisabled()) return;
284
+ if (this.expanded()) this.accordion.toggle(this.kjItemValue());
285
+ }
83
286
  }
84
287
 
85
288
  /**
86
- * Trigger button for an accordion item. Controls expand/collapse.
87
- * Sets `aria-expanded` and `data-open` attributes based on the item's expanded state.
289
+ * Trigger button for an accordion item. Wires `aria-expanded`, `aria-controls`,
290
+ * `aria-disabled`, and the click toggle. Also provides Enter / Space / arrow
291
+ * key handling — arrow keys are gated on the root's `kjArrowNavigation` flag.
292
+ *
293
+ * The host element should be a `<button>` per WAI-ARIA APG so Enter / Space
294
+ * activation, focus, and disabled semantics work without extra wiring.
88
295
  *
89
296
  * @example
90
297
  * ```html
91
298
  * <button kjAccordionTrigger>Section title</button>
92
299
  * ```
93
- * @category Core/Navigation
300
+ * @doc-category Core/Data display
301
+ * @doc
302
+ * @doc-name accordion
94
303
  */
95
304
  @Directive({
96
305
  selector: '[kjAccordionTrigger]',
97
306
  standalone: true,
98
307
  host: {
99
- '[attr.aria-expanded]': 'item.expanded().toString()',
308
+ '[attr.id]': 'item.headerId()',
309
+ '[attr.aria-expanded]': 'item.expanded() ? "true" : "false"',
310
+ '[attr.aria-controls]': 'item.contentId()',
311
+ '[attr.aria-disabled]': 'item.disabled() ? "true" : null',
312
+ '[attr.data-state]': 'item.expanded() ? "open" : "closed"',
100
313
  '[attr.data-open]': 'item.expanded() ? "" : null',
101
- '(click)': 'item.toggle()',
314
+ '[attr.data-disabled]': 'item.disabled() ? "" : null',
315
+ '(click)': 'onClick()',
316
+ '(keydown)': 'onKeydown($event)',
102
317
  },
103
318
  })
104
- export class KjAccordionTrigger {
319
+ export class KjAccordionTrigger implements OnInit, OnDestroy {
105
320
  /** The parent accordion item context. */
106
- readonly item = inject(KJ_ACCORDION_ITEM);
321
+ readonly item = inject(KJ_ACCORDION_ITEM) as KjAccordionItem;
322
+ private readonly accordion = inject(KJ_ACCORDION) as KjAccordion;
323
+ /** @internal Native host element. */
324
+ readonly el = inject<ElementRef<HTMLElement>>(ElementRef);
325
+
326
+ ngOnInit(): void {
327
+ this.accordion.registerTrigger(this);
328
+ }
329
+
330
+ ngOnDestroy(): void {
331
+ this.accordion.unregisterTrigger(this);
332
+ }
333
+
334
+ /** @internal Click handler. */
335
+ onClick(): void {
336
+ if (this.item.disabled()) return;
337
+ this.item.toggle();
338
+ }
339
+
340
+ /** @internal Keydown handler — arrow-nav opt-in via `kjArrowNavigation` on the root. */
341
+ onKeydown(event: KeyboardEvent): void {
342
+ if (!this.accordion.arrowNavigation()) return;
343
+ const list = this.accordion.triggers();
344
+ const idx = list.indexOf(this);
345
+ if (idx === -1) return;
346
+ switch (event.key) {
347
+ case 'ArrowDown':
348
+ event.preventDefault();
349
+ this.accordion.focusTrigger(1, idx);
350
+ return;
351
+ case 'ArrowUp':
352
+ event.preventDefault();
353
+ this.accordion.focusTrigger(-1, idx);
354
+ return;
355
+ case 'Home':
356
+ event.preventDefault();
357
+ this.accordion.focusEdge('first');
358
+ return;
359
+ case 'End':
360
+ event.preventDefault();
361
+ this.accordion.focusEdge('last');
362
+ return;
363
+ }
364
+ }
107
365
  }
108
366
 
109
367
  /**
110
- * Accordion content panel. Hidden when the parent item is collapsed.
111
- * Uses the `hidden` attribute for accessibility-compliant visibility.
368
+ * Accordion content panel. Hosts `role="region"` + `aria-labelledby` to the
369
+ * trigger's id. Visibility is signalled via `[data-state]` (`"open"` /
370
+ * `"closed"`) so consumers can CSS-animate the open/close transition. While
371
+ * closed, `aria-hidden="true"` and `inert` keep the panel out of the AT tree
372
+ * and tab sequence — the element stays in the DOM rather than being removed
373
+ * with `hidden`, which would interrupt the animation.
112
374
  *
113
375
  * @example
114
376
  * ```html
115
377
  * <div kjAccordionContent>Panel content</div>
116
378
  * ```
117
- * @category Core/Navigation
379
+ * @doc-category Core/Data display
380
+ * @doc
381
+ * @doc-name accordion
118
382
  */
119
383
  @Directive({
120
384
  selector: '[kjAccordionContent]',
121
385
  standalone: true,
122
386
  host: {
123
- '[attr.hidden]': '!item.expanded() ? "" : null',
387
+ '[attr.role]': '"region"',
388
+ '[attr.id]': 'item.contentId()',
389
+ '[attr.aria-labelledby]': 'item.headerId()',
390
+ '[attr.data-state]': 'item.expanded() ? "open" : "closed"',
391
+ // `aria-hidden` keeps the closed panel out of the AT tree while leaving
392
+ // the element in the DOM so CSS can animate its open/close transition
393
+ // (driven by [data-state]). The visual hide is owned by the component CSS.
394
+ '[attr.aria-hidden]': '!item.expanded() ? "true" : null',
395
+ '[attr.inert]': '!item.expanded() ? "" : null',
124
396
  },
125
397
  })
126
398
  export class KjAccordionContent {
@@ -1,2 +1,8 @@
1
- export { KjAccordion, KjAccordionItem, KjAccordionTrigger, KjAccordionContent } from './accordion';
2
- export { KJ_ACCORDION, KJ_ACCORDION_ITEM } from './accordion.context';
1
+ export { KjAccordion, KjAccordionItem, KjAccordionTrigger, KjAccordionContent } from './accordion';
2
+ export {
3
+ KJ_ACCORDION,
4
+ KJ_ACCORDION_ITEM,
5
+ type KjAccordionContext,
6
+ type KjAccordionItemContext,
7
+ type KjAccordionType,
8
+ } from './accordion.context';
@@ -0,0 +1,28 @@
1
+ import { InjectionToken, Signal } from '@angular/core';
2
+
3
+ /**
4
+ * Resolved alert mode after applying the matrix. See `alert.md` for the
5
+ * full role/aria-live mapping.
6
+ */
7
+ export type KjAlertMode = 'assertive' | 'polite' | 'static' | 'off';
8
+
9
+ /**
10
+ * Context exposed by `KjAlert` to its descendant directives via the
11
+ * `KJ_ALERT` injection token. Title/description register their generated
12
+ * ids so the root can reflect `aria-labelledby` / `aria-describedby`.
13
+ */
14
+ export interface KjAlertContext {
15
+ readonly alertId: Signal<string>;
16
+ readonly variant: Signal<string>;
17
+ readonly mode: Signal<KjAlertMode>;
18
+ readonly titleId: Signal<string | null>;
19
+ readonly descriptionId: Signal<string | null>;
20
+ registerTitle(id: string): void;
21
+ unregisterTitle(id: string): void;
22
+ registerDescription(id: string): void;
23
+ unregisterDescription(id: string): void;
24
+ dismiss(): void;
25
+ }
26
+
27
+ /** DI token for the alert context — provided by `KjAlert`. */
28
+ export const KJ_ALERT = new InjectionToken<KjAlertContext>('KjAlert');