@kouji-ui/core 0.0.4 → 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 +7 -4
  2. package/CHANGELOG.md +169 -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 +11 -3
  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 +101 -42
  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 +166 -14
  472. package/src/toast/toast.strategy.ts +10 -0
  473. package/src/toast/toast.ts +177 -21
  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 -106
  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
@@ -0,0 +1,262 @@
1
+ import { render } from '@testing-library/angular';
2
+ import { describe, expect, it, vi, beforeEach, afterEach } from 'vitest';
3
+ import { KjSpinner } from './spinner';
4
+
5
+ /**
6
+ * Flush microtasks + the rAF that backs `afterNextRender` so the directive
7
+ * has a chance to read host attributes and the `prefers-reduced-motion`
8
+ * media query.
9
+ */
10
+ async function flushAfterNextRender(): Promise<void> {
11
+ await new Promise<void>((resolve) => setTimeout(resolve, 0));
12
+ await Promise.resolve();
13
+ await Promise.resolve();
14
+ }
15
+
16
+ /**
17
+ * Stub `window.matchMedia` for a deterministic `prefers-reduced-motion`
18
+ * value during a test. Returns the listener registered by the directive so
19
+ * the test can simulate a runtime change of the user preference.
20
+ */
21
+ function stubMatchMedia(initial: boolean): {
22
+ fire: (matches: boolean) => void;
23
+ restore: () => void;
24
+ } {
25
+ const original = window.matchMedia;
26
+ let listener: ((e: MediaQueryListEvent) => void) | null = null;
27
+ const mql: Partial<MediaQueryList> = {
28
+ matches: initial,
29
+ media: '(prefers-reduced-motion: reduce)',
30
+ addEventListener: ((_type: string, l: EventListener) => {
31
+ listener = l as (e: MediaQueryListEvent) => void;
32
+ }) as MediaQueryList['addEventListener'],
33
+ removeEventListener: (() => {
34
+ listener = null;
35
+ }) as MediaQueryList['removeEventListener'],
36
+ addListener: () => {},
37
+ removeListener: () => {},
38
+ onchange: null,
39
+ dispatchEvent: () => true,
40
+ };
41
+ (window as unknown as { matchMedia: (q: string) => MediaQueryList }).matchMedia = () =>
42
+ mql as MediaQueryList;
43
+ return {
44
+ fire: (matches: boolean) => {
45
+ (mql as { matches: boolean }).matches = matches;
46
+ listener?.({ matches } as MediaQueryListEvent);
47
+ },
48
+ restore: () => {
49
+ window.matchMedia = original;
50
+ },
51
+ };
52
+ }
53
+
54
+ describe('KjSpinner', () => {
55
+ let mm: ReturnType<typeof stubMatchMedia>;
56
+
57
+ beforeEach(() => {
58
+ mm = stubMatchMedia(false);
59
+ });
60
+
61
+ afterEach(() => {
62
+ mm.restore();
63
+ });
64
+
65
+ describe('a11y contract', () => {
66
+ it('sets role="status" on the host', async () => {
67
+ const { container } = await render(`<span kjSpinner></span>`, {
68
+ imports: [KjSpinner],
69
+ });
70
+ await flushAfterNextRender();
71
+ expect(container.querySelector('span')).toHaveAttribute('role', 'status');
72
+ });
73
+
74
+ it('sets aria-live="polite" and aria-atomic="true"', async () => {
75
+ const { container } = await render(`<span kjSpinner></span>`, {
76
+ imports: [KjSpinner],
77
+ });
78
+ await flushAfterNextRender();
79
+ const host = container.querySelector('span')!;
80
+ expect(host).toHaveAttribute('aria-live', 'polite');
81
+ expect(host).toHaveAttribute('aria-atomic', 'true');
82
+ });
83
+
84
+ it('applies default aria-label="Loading" when no consumer label is provided', async () => {
85
+ const { container } = await render(`<span kjSpinner></span>`, {
86
+ imports: [KjSpinner],
87
+ });
88
+ await flushAfterNextRender();
89
+ expect(container.querySelector('span')).toHaveAttribute('aria-label', 'Loading');
90
+ });
91
+
92
+ it('consumer kjAriaLabel input wins over the default', async () => {
93
+ const { container } = await render(
94
+ `<span kjSpinner kjAriaLabel="Sending"></span>`,
95
+ { imports: [KjSpinner] },
96
+ );
97
+ await flushAfterNextRender();
98
+ expect(container.querySelector('span')).toHaveAttribute('aria-label', 'Sending');
99
+ });
100
+
101
+ it('does not override a consumer-authored aria-label attribute on the host', async () => {
102
+ const { container } = await render(
103
+ `<span kjSpinner aria-label="Saving draft"></span>`,
104
+ { imports: [KjSpinner] },
105
+ );
106
+ await flushAfterNextRender();
107
+ expect(container.querySelector('span')).toHaveAttribute('aria-label', 'Saving draft');
108
+ });
109
+
110
+ it('does not set aria-label when host carries aria-labelledby', async () => {
111
+ const { container } = await render(
112
+ `<span id="lbl">Loading users</span>
113
+ <span kjSpinner aria-labelledby="lbl"></span>`,
114
+ { imports: [KjSpinner] },
115
+ );
116
+ await flushAfterNextRender();
117
+ const host = container.querySelector('span[kjSpinner]')!;
118
+ expect(host).not.toHaveAttribute('aria-label');
119
+ expect(host).toHaveAttribute('aria-labelledby', 'lbl');
120
+ });
121
+ });
122
+
123
+ describe('data-animation reflection', () => {
124
+ it('defaults to data-animation="spin"', async () => {
125
+ const { container } = await render(`<span kjSpinner></span>`, {
126
+ imports: [KjSpinner],
127
+ });
128
+ await flushAfterNextRender();
129
+ expect(container.querySelector('span')).toHaveAttribute('data-animation', 'spin');
130
+ });
131
+
132
+ it('reflects kjAnimation="dots"', async () => {
133
+ const { container } = await render(
134
+ `<span kjSpinner kjAnimation="dots"></span>`,
135
+ { imports: [KjSpinner] },
136
+ );
137
+ await flushAfterNextRender();
138
+ expect(container.querySelector('span')).toHaveAttribute('data-animation', 'dots');
139
+ });
140
+
141
+ it('reflects kjAnimation="pulse"', async () => {
142
+ const { container } = await render(
143
+ `<span kjSpinner kjAnimation="pulse"></span>`,
144
+ { imports: [KjSpinner] },
145
+ );
146
+ await flushAfterNextRender();
147
+ expect(container.querySelector('span')).toHaveAttribute('data-animation', 'pulse');
148
+ });
149
+
150
+ it('reflects kjAnimation="bars"', async () => {
151
+ const { container } = await render(
152
+ `<span kjSpinner kjAnimation="bars"></span>`,
153
+ { imports: [KjSpinner] },
154
+ );
155
+ await flushAfterNextRender();
156
+ expect(container.querySelector('span')).toHaveAttribute('data-animation', 'bars');
157
+ });
158
+ });
159
+
160
+ describe('data-reduced-motion mirrors prefers-reduced-motion', () => {
161
+ it('omits data-reduced-motion when the user preference is not set', async () => {
162
+ const { container } = await render(`<span kjSpinner></span>`, {
163
+ imports: [KjSpinner],
164
+ });
165
+ await flushAfterNextRender();
166
+ expect(container.querySelector('span')).not.toHaveAttribute('data-reduced-motion');
167
+ });
168
+
169
+ it('reflects data-reduced-motion="true" when the media query matches at mount', async () => {
170
+ mm.restore();
171
+ mm = stubMatchMedia(true);
172
+ const { container } = await render(`<span kjSpinner></span>`, {
173
+ imports: [KjSpinner],
174
+ });
175
+ await flushAfterNextRender();
176
+ expect(container.querySelector('span')).toHaveAttribute('data-reduced-motion', 'true');
177
+ });
178
+
179
+ it('updates data-reduced-motion when the media query changes at runtime', async () => {
180
+ const { container, fixture } = await render(`<span kjSpinner></span>`, {
181
+ imports: [KjSpinner],
182
+ });
183
+ await flushAfterNextRender();
184
+ const host = container.querySelector('span')!;
185
+ expect(host).not.toHaveAttribute('data-reduced-motion');
186
+
187
+ mm.fire(true);
188
+ fixture.detectChanges();
189
+ expect(host).toHaveAttribute('data-reduced-motion', 'true');
190
+
191
+ mm.fire(false);
192
+ fixture.detectChanges();
193
+ expect(host).not.toHaveAttribute('data-reduced-motion');
194
+ });
195
+
196
+ it('does not throw when window.matchMedia is unavailable (SSR-style)', async () => {
197
+ mm.restore();
198
+ const original = window.matchMedia;
199
+ // Simulate non-browser env at the time afterNextRender runs.
200
+ (window as unknown as { matchMedia: undefined }).matchMedia = undefined;
201
+ try {
202
+ const { container } = await render(`<span kjSpinner></span>`, {
203
+ imports: [KjSpinner],
204
+ });
205
+ await flushAfterNextRender();
206
+ expect(container.querySelector('span')).not.toHaveAttribute('data-reduced-motion');
207
+ } finally {
208
+ window.matchMedia = original;
209
+ mm = stubMatchMedia(false);
210
+ }
211
+ });
212
+ });
213
+
214
+ describe('KjVariant + KjSize composition', () => {
215
+ it('reflects default data-variant="neutral" from KJ_SPINNER_DEFAULTS', async () => {
216
+ const { container } = await render(`<span kjSpinner></span>`, {
217
+ imports: [KjSpinner],
218
+ });
219
+ await flushAfterNextRender();
220
+ expect(container.querySelector('span')).toHaveAttribute('data-variant', 'neutral');
221
+ });
222
+
223
+ it('reflects default data-size="md" from KJ_SPINNER_DEFAULTS', async () => {
224
+ const { container } = await render(`<span kjSpinner></span>`, {
225
+ imports: [KjSpinner],
226
+ });
227
+ await flushAfterNextRender();
228
+ expect(container.querySelector('span')).toHaveAttribute('data-size', 'md');
229
+ });
230
+
231
+ it('forwards kjVariant input to data-variant (composed via hostDirectives)', async () => {
232
+ const { container } = await render(
233
+ `<span kjSpinner kjVariant="primary"></span>`,
234
+ { imports: [KjSpinner] },
235
+ );
236
+ await flushAfterNextRender();
237
+ expect(container.querySelector('span')).toHaveAttribute('data-variant', 'primary');
238
+ });
239
+
240
+ it('forwards kjSize input to data-size (composed via hostDirectives)', async () => {
241
+ const { container } = await render(
242
+ `<span kjSpinner kjSize="xs"></span>`,
243
+ { imports: [KjSpinner] },
244
+ );
245
+ await flushAfterNextRender();
246
+ expect(container.querySelector('span')).toHaveAttribute('data-size', 'xs');
247
+ });
248
+
249
+ it('warns on unknown variant in dev mode', async () => {
250
+ const warn = vi.spyOn(console, 'warn').mockImplementation(() => {});
251
+ try {
252
+ await render(`<span kjSpinner kjVariant="bogus"></span>`, {
253
+ imports: [KjSpinner],
254
+ });
255
+ await flushAfterNextRender();
256
+ expect(warn).toHaveBeenCalled();
257
+ } finally {
258
+ warn.mockRestore();
259
+ }
260
+ });
261
+ });
262
+ });
@@ -0,0 +1,129 @@
1
+ import {
2
+ DestroyRef,
3
+ Directive,
4
+ ElementRef,
5
+ afterNextRender,
6
+ computed,
7
+ inject,
8
+ input,
9
+ signal,
10
+ } from '@angular/core';
11
+ import { KjSize, KjVariant, bindPresets } from '../presets';
12
+ import { KJ_SPINNER_CONFIG, KjSpinnerAnimation } from './config';
13
+
14
+ /**
15
+ * Marks an element as a kouji indeterminate spinner. Owns the small
16
+ * accessibility contract (`role="status"`, default `aria-label="Loading"`,
17
+ * `prefers-reduced-motion` reflection) and reflects `data-animation`,
18
+ * `data-variant`, and `data-size` for the theme to render the visual glyph.
19
+ *
20
+ * The host element is consumer-supplied — usually a `<span kjSpinner>`. The
21
+ * directive itself emits no markup; the surrounding wrapper / template is
22
+ * responsible for the visually-hidden label fallback when no consumer label
23
+ * is provided. The directive does set `aria-label` to the default when
24
+ * neither `aria-label` nor `aria-labelledby` is already on the host.
25
+ *
26
+ * **Indeterminate-only.** A determinate "x of y" indicator is a Progress
27
+ * Bar — different role, different ARIA contract; do not bend Spinner to fit.
28
+ *
29
+ * @example
30
+ * ```html
31
+ * <span kjSpinner></span>
32
+ * <span kjSpinner kjAnimation="dots" kjAriaLabel="Sending"></span>
33
+ * ```
34
+ * @doc-category Core/Feedback
35
+ * @doc
36
+ * @doc-name spinner
37
+ * @doc-description Marks an element as an indeterminate loading indicator with the right accessibility role and label.
38
+ * @doc-is-main
39
+ */
40
+ @Directive({
41
+ selector: '[kjSpinner]',
42
+ standalone: true,
43
+ exportAs: 'kjSpinner',
44
+ hostDirectives: [
45
+ { directive: KjVariant, inputs: ['kjVariant'] },
46
+ { directive: KjSize, inputs: ['kjSize'] },
47
+ ],
48
+ providers: [...bindPresets(KJ_SPINNER_CONFIG)],
49
+ host: {
50
+ role: 'status',
51
+ 'aria-live': 'polite',
52
+ 'aria-atomic': 'true',
53
+ '[attr.data-animation]': 'kjAnimation()',
54
+ '[attr.data-reduced-motion]': 'reducedMotion() ? "true" : null',
55
+ '[attr.aria-label]': 'ariaLabelAttr()',
56
+ },
57
+ })
58
+ export class KjSpinner {
59
+ private readonly el = inject<ElementRef<HTMLElement>>(ElementRef);
60
+ private readonly config = inject(KJ_SPINNER_CONFIG);
61
+
62
+ /**
63
+ * Animation shape preset. Reflects `data-animation`. Default `'spin'`.
64
+ * Themes own the keyframes for each value.
65
+ */
66
+ readonly kjAnimation = input<KjSpinnerAnimation>(
67
+ (this.config.defaults.animation as KjSpinnerAnimation) ?? 'spin',
68
+ );
69
+
70
+ /**
71
+ * Accessible name announced by AT. Bound to `aria-label` when the host has
72
+ * no `aria-label` attribute and no `aria-labelledby` attribute already set
73
+ * (so a consumer-authored `aria-labelledby` wins, and a consumer-authored
74
+ * `aria-label` is not double-bound).
75
+ */
76
+ readonly kjAriaLabel = input<string>(this.config.defaults.ariaLabel ?? 'Loading');
77
+
78
+ /** True when the host had a consumer-authored `aria-labelledby` at mount. */
79
+ protected readonly hasAriaLabelledBy: boolean;
80
+
81
+ /**
82
+ * Captured value of the consumer-authored `aria-label` HTML attribute at
83
+ * mount, or `null` if none was set. We re-emit it through the host
84
+ * binding so Angular doesn't strip the original (a host `[attr.aria-label]`
85
+ * binding always wins over the static attribute, so leaving the binding
86
+ * unconditional but echoing the captured value preserves the consumer
87
+ * intent).
88
+ */
89
+ protected readonly nativeAriaLabel: string | null;
90
+
91
+ /**
92
+ * Reflects the user's `prefers-reduced-motion` preference. The directive
93
+ * does not animate anything itself — it mirrors the boolean as
94
+ * `data-reduced-motion="true"` and themes own the alternate keyframe.
95
+ */
96
+ protected readonly reducedMotion = signal<boolean>(false);
97
+
98
+ protected readonly ariaLabelAttr = computed(() => {
99
+ if (this.hasAriaLabelledBy) return null;
100
+ if (this.nativeAriaLabel !== null) return this.nativeAriaLabel;
101
+ return this.kjAriaLabel();
102
+ });
103
+
104
+ constructor() {
105
+ const destroyRef = inject(DestroyRef);
106
+
107
+ // Read consumer-authored aria attributes synchronously in the
108
+ // constructor — by the time `afterNextRender` runs, Angular's host
109
+ // binding for `[attr.aria-label]` has already overwritten the original
110
+ // attribute with the computed default, which would make the detection
111
+ // see kouji's own value and ignore the consumer's.
112
+ const host = this.el.nativeElement;
113
+ this.hasAriaLabelledBy = host.hasAttribute('aria-labelledby');
114
+ this.nativeAriaLabel = host.getAttribute('aria-label');
115
+
116
+ afterNextRender(() => {
117
+ // SSR-safe: matchMedia is only present in a real browser. The
118
+ // server-rendered HTML carries no `data-reduced-motion`; the post-
119
+ // hydrate read sets it on the client when the preference is active.
120
+ if (typeof window !== 'undefined' && typeof window.matchMedia === 'function') {
121
+ const mql = window.matchMedia('(prefers-reduced-motion: reduce)');
122
+ this.reducedMotion.set(mql.matches);
123
+ const onChange = (e: MediaQueryListEvent) => this.reducedMotion.set(e.matches);
124
+ mql.addEventListener('change', onChange);
125
+ destroyRef.onDestroy(() => mql.removeEventListener('change', onChange));
126
+ }
127
+ });
128
+ }
129
+ }
@@ -0,0 +1,15 @@
1
+ export {
2
+ KjStepper,
3
+ KjStep,
4
+ KjStepLabel,
5
+ KjStepContent,
6
+ KjStepperNext,
7
+ KjStepperPrevious,
8
+ KjStepperReset,
9
+ } from './stepper';
10
+ export {
11
+ KJ_STEPPER,
12
+ KJ_STEP,
13
+ type KjStepperContext,
14
+ type KjStepContext,
15
+ } from './stepper.context';
@@ -0,0 +1,63 @@
1
+ import { InjectionToken, Signal } from '@angular/core';
2
+
3
+ /** Per-step context exposed to `KjStepLabel` and `KjStepContent`. */
4
+ export interface KjStepContext {
5
+ /** 0-based index in the parent stepper's step set. */
6
+ readonly index: Signal<number>;
7
+ /** True when this step is the active one. */
8
+ readonly active: Signal<boolean>;
9
+ /** True when this step has been completed (consumer-set via `kjStepCompleted`). */
10
+ readonly completed: Signal<boolean>;
11
+ /** True when this step is in an error state (consumer-set via `kjStepError`). */
12
+ readonly error: Signal<boolean>;
13
+ /** True when this step is optional (does not gate linear advancement). */
14
+ readonly optional: Signal<boolean>;
15
+ /** True when this step is reachable in the current mode. */
16
+ readonly reachable: Signal<boolean>;
17
+ /** True when this step is explicitly disabled by the consumer. */
18
+ readonly disabled: Signal<boolean>;
19
+ /** Optional consumer-supplied semantic key, used by `goToKey()`. */
20
+ readonly key: Signal<string | undefined>;
21
+ /** Stable id for `aria-labelledby` wiring. */
22
+ readonly labelId: Signal<string>;
23
+ /** Stable id for the content region. */
24
+ readonly contentId: Signal<string>;
25
+ /** Activate this step (subject to linear-mode gating). */
26
+ activate(): void;
27
+ }
28
+
29
+ /** Stepper-root context exposed to step / label / content / command directives. */
30
+ export interface KjStepperContext {
31
+ /** Active step index (0-based). */
32
+ readonly activeStep: Signal<number>;
33
+ /** Total number of registered steps. */
34
+ readonly totalSteps: Signal<number>;
35
+ /** @internal — read-only view of registered steps in registration order. */
36
+ readonly steps: Signal<readonly KjStepContext[]>;
37
+ /** Linear-mode flag. */
38
+ readonly linear: Signal<boolean>;
39
+ /** Orientation. */
40
+ readonly orientation: Signal<'horizontal' | 'vertical'>;
41
+ /** True when `next()` will succeed. */
42
+ readonly canAdvance: Signal<boolean>;
43
+ /** True when `previous()` will succeed. */
44
+ readonly canRetreat: Signal<boolean>;
45
+ /** Imperative navigation. */
46
+ next(): void;
47
+ previous(): void;
48
+ goTo(index: number): void;
49
+ goToKey(key: string): void;
50
+ reset(): void;
51
+ /** @internal — `KjStep` registers / unregisters here. */
52
+ register(step: KjStepContext): void;
53
+ /** @internal */
54
+ unregister(step: KjStepContext): void;
55
+ /** @internal — `KjStep` reports its reachability under linear gating. */
56
+ isReachable(index: number): boolean;
57
+ }
58
+
59
+ /** Injection token for the root stepper directive. */
60
+ export const KJ_STEPPER = new InjectionToken<KjStepperContext>('KjStepper');
61
+
62
+ /** Injection token for an individual step directive. */
63
+ export const KJ_STEP = new InjectionToken<KjStepContext>('KjStep');