@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,40 @@
1
+ import { Directive, booleanAttribute, inject, input } from '@angular/core';
2
+ import { KJ_SPEED_DIAL, type KjSpeedDialContext } from './speed-dial.context';
3
+
4
+ /**
5
+ * One action button in a Speed Dial cluster.
6
+ *
7
+ * Apply alongside `kjButton` on a native `<button>` to inherit the button
8
+ * presets. This directive contributes `role="menuitem"` and closes the parent
9
+ * dial after the consumer's click handler runs (controllable via
10
+ * `kjCloseOnActivate`).
11
+ *
12
+ * @example
13
+ * ```html
14
+ * <button kjButton kjSpeedDialAction aria-label="Edit" (click)="edit()">E</button>
15
+ * ```
16
+ *
17
+ * @doc-category Core/Actions
18
+ * @doc
19
+ * @doc-name speed-dial
20
+ */
21
+ @Directive({
22
+ selector: '[kjSpeedDialAction]',
23
+ standalone: true,
24
+ exportAs: 'kjSpeedDialAction',
25
+ host: {
26
+ role: 'menuitem',
27
+ '(click)': 'onClick()',
28
+ },
29
+ })
30
+ export class KjSpeedDialAction {
31
+ private readonly ctx = inject<KjSpeedDialContext>(KJ_SPEED_DIAL);
32
+
33
+ /** Whether activating this action should close the dial. Default `true`. */
34
+ readonly kjCloseOnActivate = input(true, { transform: booleanAttribute });
35
+
36
+ protected onClick(): void {
37
+ if (!this.kjCloseOnActivate()) return;
38
+ this.ctx.close();
39
+ }
40
+ }
@@ -0,0 +1,31 @@
1
+ import { Directive, inject } from '@angular/core';
2
+ import { KJ_SPEED_DIAL, type KjSpeedDialContext } from './speed-dial.context';
3
+
4
+ /**
5
+ * Action cluster container for a Speed Dial.
6
+ *
7
+ * Holds `role="menu"` and is hidden from the AT tree (and from layout via the
8
+ * styled wrapper's CSS) when the dial is collapsed. Reflects `id`,
9
+ * `data-direction`, `data-expanded` and `aria-hidden` for the wrapper to key
10
+ * its layout / animation off of.
11
+ *
12
+ * @doc-category Core/Actions
13
+ * @doc
14
+ * @doc-name speed-dial
15
+ */
16
+ @Directive({
17
+ selector: '[kjSpeedDialActions]',
18
+ standalone: true,
19
+ exportAs: 'kjSpeedDialActions',
20
+ host: {
21
+ role: 'menu',
22
+ '[id]': 'ctx.contentId',
23
+ '[attr.data-direction]': 'ctx.direction()',
24
+ '[attr.data-expanded]': 'ctx.expanded() ? "" : null',
25
+ '[attr.aria-hidden]': 'ctx.expanded() ? null : "true"',
26
+ },
27
+ })
28
+ export class KjSpeedDialActions {
29
+ /** @internal */
30
+ readonly ctx = inject<KjSpeedDialContext>(KJ_SPEED_DIAL);
31
+ }
@@ -0,0 +1,55 @@
1
+ import { Directive, inject } from '@angular/core';
2
+ import { KJ_SPEED_DIAL, type KjSpeedDialContext } from './speed-dial.context';
3
+
4
+ /**
5
+ * The floating action button that toggles the Speed Dial open/closed.
6
+ *
7
+ * Apply alongside `kjButton` on a native `<button>` so the trigger inherits
8
+ * the button presets (variant, size, focus ring, capture-phase disabled
9
+ * suppression). The trigger itself contributes the menu-button ARIA wiring
10
+ * (`aria-haspopup="menu"`, `aria-expanded`, `aria-controls`) and the click
11
+ * toggle semantics that drive the parent `[kjSpeedDial]`.
12
+ *
13
+ * @example
14
+ * ```html
15
+ * <div kjSpeedDial>
16
+ * <button kjButton kjSpeedDialTrigger aria-label="Open actions">+</button>
17
+ * …
18
+ * </div>
19
+ * ```
20
+ *
21
+ * @doc-category Core/Actions
22
+ * @doc
23
+ * @doc-name speed-dial
24
+ */
25
+ @Directive({
26
+ selector: '[kjSpeedDialTrigger]',
27
+ standalone: true,
28
+ exportAs: 'kjSpeedDialTrigger',
29
+ host: {
30
+ type: 'button',
31
+ '[attr.aria-haspopup]': '"menu"',
32
+ '[attr.aria-expanded]': 'ctx.expanded() ? "true" : "false"',
33
+ '[attr.aria-controls]': 'ctx.contentId',
34
+ '[attr.data-state]': 'ctx.expanded() ? "open" : "closed"',
35
+ '(click)': 'onClick($event)',
36
+ '(keydown.escape)': 'onEscape($event)',
37
+ },
38
+ })
39
+ export class KjSpeedDialTrigger {
40
+ /** @internal */
41
+ readonly ctx = inject<KjSpeedDialContext>(KJ_SPEED_DIAL);
42
+
43
+ protected onClick(event: MouseEvent): void {
44
+ if (this.ctx.disabled()) return;
45
+ event.stopPropagation();
46
+ this.ctx.toggle();
47
+ }
48
+
49
+ protected onEscape(event: Event): void {
50
+ if (!this.ctx.expanded()) return;
51
+ event.preventDefault();
52
+ event.stopPropagation();
53
+ this.ctx.close();
54
+ }
55
+ }
@@ -0,0 +1,36 @@
1
+ import { InjectionToken, type Signal } from '@angular/core';
2
+
3
+ /** Direction the action cluster fans out from the trigger. */
4
+ export type KjSpeedDialDirection = 'up' | 'down' | 'left' | 'right';
5
+
6
+ /**
7
+ * Shared state surface exposed by `[kjSpeedDial]` to its trigger, container
8
+ * and action descendants. Injected via {@link KJ_SPEED_DIAL}.
9
+ */
10
+ export interface KjSpeedDialContext {
11
+ /** Whether the action cluster is currently expanded. */
12
+ readonly expanded: Signal<boolean>;
13
+ /** Disabled state — when true, opening is suppressed. */
14
+ readonly disabled: Signal<boolean>;
15
+ /** Direction the cluster fans out from the trigger. */
16
+ readonly direction: Signal<KjSpeedDialDirection>;
17
+ /** Auto-generated id for the action container, used by `aria-controls`. */
18
+ readonly contentId: string;
19
+ /** Open the cluster. */
20
+ open(): void;
21
+ /** Close the cluster. */
22
+ close(): void;
23
+ /** Toggle the cluster. */
24
+ toggle(): void;
25
+ }
26
+
27
+ /** DI token for the shared speed-dial state. */
28
+ export const KJ_SPEED_DIAL = new InjectionToken<KjSpeedDialContext>('KJ_SPEED_DIAL');
29
+
30
+ let nextSpeedDialId = 0;
31
+
32
+ /** @internal Generates a unique id for each speed-dial instance. */
33
+ export function nextKjSpeedDialId(): string {
34
+ nextSpeedDialId += 1;
35
+ return `kj-speed-dial-${nextSpeedDialId}`;
36
+ }
@@ -0,0 +1,143 @@
1
+ import { render, fireEvent } from '@testing-library/angular';
2
+ import { axe, toHaveNoViolations } from 'jest-axe';
3
+ import { KjButton } from '../button/button';
4
+ import {
5
+ KjSpeedDial,
6
+ KjSpeedDialAction,
7
+ KjSpeedDialActions,
8
+ KjSpeedDialTrigger,
9
+ } from './index';
10
+
11
+ expect.extend(toHaveNoViolations);
12
+
13
+ const imports = [
14
+ KjButton,
15
+ KjSpeedDial,
16
+ KjSpeedDialTrigger,
17
+ KjSpeedDialActions,
18
+ KjSpeedDialAction,
19
+ ];
20
+
21
+ const TEMPLATE = `
22
+ <div kjSpeedDial>
23
+ <button kjButton kjSpeedDialTrigger aria-label="Open">+</button>
24
+ <div kjSpeedDialActions>
25
+ <button kjButton kjSpeedDialAction aria-label="Edit">E</button>
26
+ <button kjButton kjSpeedDialAction aria-label="Share">S</button>
27
+ </div>
28
+ </div>
29
+ `;
30
+
31
+ describe('KjSpeedDial', () => {
32
+ it('starts collapsed and reflects ARIA on the trigger', async () => {
33
+ const { getByLabelText, container } = await render(TEMPLATE, { imports });
34
+ const trigger = getByLabelText('Open');
35
+ expect(trigger).toHaveAttribute('aria-haspopup', 'menu');
36
+ expect(trigger).toHaveAttribute('aria-expanded', 'false');
37
+ expect(trigger.getAttribute('aria-controls')).toMatch(/^kj-speed-dial-\d+$/);
38
+
39
+ const actions = container.querySelector('[kjSpeedDialActions]') as HTMLElement;
40
+ expect(actions).toHaveAttribute('aria-hidden', 'true');
41
+ expect(actions.id).toMatch(/^kj-speed-dial-\d+$/);
42
+ expect(trigger.getAttribute('aria-controls')).toBe(actions.id);
43
+ });
44
+
45
+ it('reflects kjDirection as data-direction on root and actions container', async () => {
46
+ const { container } = await render(
47
+ `
48
+ <div kjSpeedDial kjDirection="left">
49
+ <button kjButton kjSpeedDialTrigger aria-label="Open">+</button>
50
+ <div kjSpeedDialActions>
51
+ <button kjButton kjSpeedDialAction aria-label="A">A</button>
52
+ </div>
53
+ </div>
54
+ `,
55
+ { imports },
56
+ );
57
+
58
+ const root = container.querySelector('[kjSpeedDial]') as HTMLElement;
59
+ const actions = container.querySelector('[kjSpeedDialActions]') as HTMLElement;
60
+ expect(root).toHaveAttribute('data-direction', 'left');
61
+ expect(actions).toHaveAttribute('data-direction', 'left');
62
+ });
63
+
64
+ it('toggles open on trigger click and expands the cluster', async () => {
65
+ const { getByLabelText, container } = await render(TEMPLATE, { imports });
66
+ const trigger = getByLabelText('Open');
67
+ const actions = container.querySelector('[kjSpeedDialActions]') as HTMLElement;
68
+ const root = container.querySelector('[kjSpeedDial]') as HTMLElement;
69
+
70
+ fireEvent.click(trigger);
71
+ expect(trigger).toHaveAttribute('aria-expanded', 'true');
72
+ expect(trigger).toHaveAttribute('data-state', 'open');
73
+ expect(actions).not.toHaveAttribute('aria-hidden');
74
+ expect(actions).toHaveAttribute('data-expanded', '');
75
+ expect(root).toHaveAttribute('data-expanded', '');
76
+
77
+ fireEvent.click(trigger);
78
+ expect(trigger).toHaveAttribute('aria-expanded', 'false');
79
+ expect(actions).toHaveAttribute('aria-hidden', 'true');
80
+ });
81
+
82
+ it('closes when an action is activated (default kjCloseOnActivate=true)', async () => {
83
+ const { getByLabelText } = await render(TEMPLATE, { imports });
84
+ fireEvent.click(getByLabelText('Open'));
85
+ expect(getByLabelText('Open')).toHaveAttribute('aria-expanded', 'true');
86
+
87
+ fireEvent.click(getByLabelText('Edit'));
88
+ expect(getByLabelText('Open')).toHaveAttribute('aria-expanded', 'false');
89
+ });
90
+
91
+ it('keeps the dial open when kjCloseOnActivate=false', async () => {
92
+ const { getByLabelText } = await render(
93
+ `
94
+ <div kjSpeedDial>
95
+ <button kjButton kjSpeedDialTrigger aria-label="Open">+</button>
96
+ <div kjSpeedDialActions>
97
+ <button kjButton kjSpeedDialAction [kjCloseOnActivate]="false" aria-label="Stay">S</button>
98
+ </div>
99
+ </div>
100
+ `,
101
+ { imports },
102
+ );
103
+ fireEvent.click(getByLabelText('Open'));
104
+ fireEvent.click(getByLabelText('Stay'));
105
+ expect(getByLabelText('Open')).toHaveAttribute('aria-expanded', 'true');
106
+ });
107
+
108
+ it('closes when Escape is pressed on the trigger', async () => {
109
+ const { getByLabelText } = await render(TEMPLATE, { imports });
110
+ fireEvent.click(getByLabelText('Open'));
111
+ expect(getByLabelText('Open')).toHaveAttribute('aria-expanded', 'true');
112
+
113
+ fireEvent.keyDown(getByLabelText('Open'), { key: 'Escape' });
114
+ expect(getByLabelText('Open')).toHaveAttribute('aria-expanded', 'false');
115
+ });
116
+
117
+ it('does not open when kjDisabled', async () => {
118
+ const { getByLabelText } = await render(
119
+ `
120
+ <div kjSpeedDial [kjDisabled]="true">
121
+ <button kjButton kjSpeedDialTrigger aria-label="Open">+</button>
122
+ <div kjSpeedDialActions>
123
+ <button kjButton kjSpeedDialAction aria-label="A">A</button>
124
+ </div>
125
+ </div>
126
+ `,
127
+ { imports },
128
+ );
129
+ fireEvent.click(getByLabelText('Open'));
130
+ expect(getByLabelText('Open')).toHaveAttribute('aria-expanded', 'false');
131
+ });
132
+
133
+ it('passes axe audit when collapsed', async () => {
134
+ const { container } = await render(TEMPLATE, { imports });
135
+ expect(await axe(container)).toHaveNoViolations();
136
+ });
137
+
138
+ it('passes axe audit when expanded', async () => {
139
+ const { getByLabelText, container } = await render(TEMPLATE, { imports });
140
+ fireEvent.click(getByLabelText('Open'));
141
+ expect(await axe(container)).toHaveNoViolations();
142
+ });
143
+ });
@@ -0,0 +1,127 @@
1
+ import {
2
+ Directive,
3
+ booleanAttribute,
4
+ computed,
5
+ input,
6
+ linkedSignal,
7
+ output,
8
+ signal,
9
+ } from '@angular/core';
10
+ import {
11
+ KJ_SPEED_DIAL,
12
+ type KjSpeedDialContext,
13
+ type KjSpeedDialDirection,
14
+ nextKjSpeedDialId,
15
+ } from './speed-dial.context';
16
+
17
+ /**
18
+ * Root container for a Speed Dial / FAB.
19
+ *
20
+ * A Speed Dial is a viewport-anchored floating action button that, when
21
+ * activated, fans out a cluster of secondary action buttons. This directive
22
+ * owns the open/closed state and exposes it to descendant trigger, container
23
+ * and action directives via the {@link KJ_SPEED_DIAL} injection token.
24
+ *
25
+ * Reflects `data-direction`, `data-expanded` and `data-disabled` host
26
+ * attributes for the styled wrapper to drive its layout and animation.
27
+ *
28
+ * @example
29
+ * ```html
30
+ * <div kjSpeedDial kjDirection="up">
31
+ * <button kjButton kjSpeedDialTrigger aria-label="Open menu">+</button>
32
+ * <div kjSpeedDialActions>
33
+ * <button kjButton kjSpeedDialAction aria-label="Edit">E</button>
34
+ * <button kjButton kjSpeedDialAction aria-label="Share">S</button>
35
+ * </div>
36
+ * </div>
37
+ * ```
38
+ *
39
+ * @doc-category Core/Actions
40
+ * @doc
41
+ * @doc-name speed-dial
42
+ * @doc-description Unstyled speed dial root that owns open state and fan-out direction for trigger and action children.
43
+ * @doc-is-main
44
+ */
45
+ @Directive({
46
+ selector: '[kjSpeedDial]',
47
+ standalone: true,
48
+ exportAs: 'kjSpeedDial',
49
+ providers: [{ provide: KJ_SPEED_DIAL, useExisting: KjSpeedDial }],
50
+ host: {
51
+ '[attr.data-direction]': 'kjDirection()',
52
+ '[attr.data-expanded]': 'expanded() ? "" : null',
53
+ '[attr.data-disabled]': 'kjDisabled() ? "" : null',
54
+ '(mouseenter)': 'onPointerEnter()',
55
+ '(mouseleave)': 'onPointerLeave()',
56
+ },
57
+ })
58
+ export class KjSpeedDial implements KjSpeedDialContext {
59
+ /** Direction the action cluster fans out from the trigger. */
60
+ readonly kjDirection = input<KjSpeedDialDirection>('up');
61
+
62
+ /** Two-way bindable expanded state. */
63
+ // eslint-disable-next-line @angular-eslint/no-input-rename -- alias keeps the public `kjOpen` name distinct from this internal linkedSignal-backed property
64
+ readonly kjOpenInput = input<boolean>(false, { alias: 'kjOpen' });
65
+ readonly kjOpen = linkedSignal(this.kjOpenInput);
66
+
67
+ /** Disables opening; if open, closes. */
68
+ readonly kjDisabled = input(false, { transform: booleanAttribute });
69
+
70
+ /** Open on hover (desktop only — coarse pointers always click-to-open). */
71
+ readonly kjOpenOnHover = input(false, { transform: booleanAttribute });
72
+
73
+ /** Convenience output paired with the `kjOpen` input, deduplicated against internal writes. */
74
+ readonly kjOpenChange = output<boolean>();
75
+
76
+ // ── KjSpeedDialContext fields ────────────────────────────────────────
77
+
78
+ readonly contentId: string = nextKjSpeedDialId();
79
+ readonly expanded = computed(() => this.kjOpen() && !this.kjDisabled());
80
+ readonly disabled = computed(() => this.kjDisabled());
81
+ readonly direction = computed(() => this.kjDirection());
82
+
83
+ // Track the last value emitted to consumers so we don't double-emit when
84
+ // an internal close is followed by the model effect.
85
+ private readonly lastEmitted = signal<boolean>(false);
86
+
87
+ // ── Mutations ────────────────────────────────────────────────────────
88
+
89
+ open(): void {
90
+ if (this.kjDisabled()) return;
91
+ if (this.kjOpen()) return;
92
+ this.kjOpen.set(true);
93
+ if (this.lastEmitted() !== true) {
94
+ this.lastEmitted.set(true);
95
+ this.kjOpenChange.emit(true);
96
+ }
97
+ }
98
+
99
+ close(): void {
100
+ if (!this.kjOpen()) return;
101
+ this.kjOpen.set(false);
102
+ if (this.lastEmitted() !== false) {
103
+ this.lastEmitted.set(false);
104
+ this.kjOpenChange.emit(false);
105
+ }
106
+ }
107
+
108
+ toggle(): void {
109
+ if (this.kjOpen()) this.close();
110
+ else this.open();
111
+ }
112
+
113
+ protected onPointerEnter(): void {
114
+ if (!this.kjOpenOnHover()) return;
115
+ if (this.kjDisabled()) return;
116
+ if (typeof window !== 'undefined' && window.matchMedia?.('(pointer: coarse)').matches) {
117
+ return;
118
+ }
119
+ this.open();
120
+ }
121
+
122
+ protected onPointerLeave(): void {
123
+ if (!this.kjOpenOnHover()) return;
124
+ if (this.kjDisabled()) return;
125
+ this.close();
126
+ }
127
+ }
@@ -0,0 +1,48 @@
1
+ import { InjectionToken, Provider } from '@angular/core';
2
+
3
+ /**
4
+ * Animation shape preset for `KjSpinner`. Reflected to `data-animation`;
5
+ * themes own the keyframes.
6
+ */
7
+ export type KjSpinnerAnimation = 'spin' | 'dots' | 'pulse' | 'bars';
8
+
9
+ export interface KjSpinnerConfig {
10
+ variants: string[];
11
+ sizes: string[];
12
+ animations: string[];
13
+ defaults: { variant: string; size: string; animation: string; ariaLabel: string };
14
+ }
15
+
16
+ /**
17
+ * Default Spinner presets shipped by kouji-ui. Exported so consumers can
18
+ * spread them when extending: `[...KJ_SPINNER_DEFAULTS.animations, 'ring']`.
19
+ */
20
+ export const KJ_SPINNER_DEFAULTS: KjSpinnerConfig = {
21
+ variants: ['neutral', 'primary', 'secondary', 'success', 'warning', 'error', 'info'],
22
+ sizes: ['xs', 'sm', 'md', 'lg'],
23
+ animations: ['spin', 'dots', 'pulse', 'bars'],
24
+ defaults: { variant: 'neutral', size: 'md', animation: 'spin', ariaLabel: 'Loading' },
25
+ };
26
+
27
+ /**
28
+ * DI token for the active Spinner presets. Default factory yields
29
+ * `KJ_SPINNER_DEFAULTS`. Override via `provideKjSpinner(…)` at the
30
+ * application scope or at a component scope.
31
+ */
32
+ export const KJ_SPINNER_CONFIG = new InjectionToken<KjSpinnerConfig>('kj.spinner.config', {
33
+ factory: () => KJ_SPINNER_DEFAULTS,
34
+ });
35
+
36
+ /**
37
+ * Configures the Spinner presets for the enclosing injector. Replaces (does
38
+ * not merge) `variants`, `sizes`, and `animations`; spread
39
+ * `KJ_SPINNER_DEFAULTS.*` to extend.
40
+ */
41
+ export function provideKjSpinner(config: Partial<KjSpinnerConfig>): Provider[] {
42
+ return [
43
+ {
44
+ provide: KJ_SPINNER_CONFIG,
45
+ useValue: { ...KJ_SPINNER_DEFAULTS, ...config },
46
+ },
47
+ ];
48
+ }
@@ -0,0 +1,8 @@
1
+ export { KjSpinner } from './spinner';
2
+ export {
3
+ KJ_SPINNER_CONFIG,
4
+ KJ_SPINNER_DEFAULTS,
5
+ provideKjSpinner,
6
+ type KjSpinnerAnimation,
7
+ type KjSpinnerConfig,
8
+ } from './config';