@kouji-ui/core 0.0.3 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (534) hide show
  1. package/.turbo/turbo-build.log +6 -3
  2. package/CHANGELOG.md +177 -0
  3. package/ng-package.json +5 -1
  4. package/package.json +18 -6
  5. package/src/a11y/aria-describedby.ts +7 -3
  6. package/src/a11y/aria-labelledby.spec.ts +55 -0
  7. package/src/a11y/aria-labelledby.ts +38 -0
  8. package/src/a11y/focus-trap.ts +4 -2
  9. package/src/a11y/index.ts +1 -0
  10. package/src/a11y/live-region.ts +4 -2
  11. package/src/a11y/roving-tabindex.spec.ts +139 -0
  12. package/src/a11y/roving-tabindex.ts +56 -7
  13. package/src/a11y/visually-hidden.ts +4 -2
  14. package/src/accordion/accordion.context.ts +22 -0
  15. package/src/accordion/accordion.spec.ts +233 -23
  16. package/src/accordion/accordion.ts +311 -39
  17. package/src/accordion/index.ts +8 -2
  18. package/src/alert/alert.context.ts +28 -0
  19. package/src/alert/alert.spec.ts +217 -0
  20. package/src/alert/alert.ts +417 -0
  21. package/src/alert/config.ts +46 -0
  22. package/src/alert/index.ts +19 -0
  23. package/src/avatar/avatar-group.context.ts +45 -0
  24. package/src/avatar/avatar-group.spec.ts +358 -0
  25. package/src/avatar/avatar-group.ts +259 -0
  26. package/src/avatar/avatar.ts +17 -4
  27. package/src/avatar/index.ts +11 -1
  28. package/src/badge/badge.spec.ts +8 -0
  29. package/src/badge/badge.ts +24 -3
  30. package/src/breadcrumb/breadcrumb-current.ts +38 -0
  31. package/src/breadcrumb/breadcrumb-ellipsis.ts +71 -0
  32. package/src/breadcrumb/breadcrumb-item.ts +41 -0
  33. package/src/breadcrumb/breadcrumb-link.ts +44 -0
  34. package/src/breadcrumb/breadcrumb-list.ts +42 -0
  35. package/src/breadcrumb/breadcrumb-separator.ts +45 -0
  36. package/src/breadcrumb/breadcrumb.context.ts +45 -0
  37. package/src/breadcrumb/breadcrumb.spec.ts +354 -0
  38. package/src/breadcrumb/breadcrumb.ts +239 -0
  39. package/src/breadcrumb/config.ts +84 -0
  40. package/src/breadcrumb/index.ts +18 -0
  41. package/src/button/_examples/button.example.ts +71 -0
  42. package/src/button/_examples/button.finance.example.ts +83 -0
  43. package/src/button/_examples/button.retro.example.ts +91 -0
  44. package/src/button/_examples/button.sizes.example.ts +60 -0
  45. package/src/button/_examples/index.ts +6 -0
  46. package/src/button/button.spec.ts +139 -8
  47. package/src/button/button.ts +114 -16
  48. package/src/button/config.spec.ts +33 -0
  49. package/src/button/config.ts +45 -0
  50. package/src/button/index.ts +2 -1
  51. package/src/button-group/button-group.context.ts +28 -0
  52. package/src/button-group/button-group.spec.ts +99 -0
  53. package/src/button-group/button-group.ts +99 -0
  54. package/src/button-group/index.ts +2 -0
  55. package/src/calendar/calendar-day.ts +102 -0
  56. package/src/calendar/calendar-grid.ts +90 -0
  57. package/src/calendar/calendar-header.ts +65 -0
  58. package/src/calendar/calendar.context.ts +53 -0
  59. package/src/calendar/calendar.spec.ts +225 -0
  60. package/src/calendar/calendar.ts +233 -0
  61. package/src/calendar/date-utils.ts +225 -0
  62. package/src/calendar/index.ts +28 -0
  63. package/src/carousel/carousel.context.ts +81 -0
  64. package/src/carousel/carousel.spec.ts +337 -0
  65. package/src/carousel/carousel.ts +919 -0
  66. package/src/carousel/index.ts +22 -0
  67. package/src/cascade-select/cascade-select-option.ts +205 -0
  68. package/src/cascade-select/cascade-select-panel.ts +106 -0
  69. package/src/cascade-select/cascade-select-root.ts +265 -0
  70. package/src/cascade-select/cascade-select-sub-panel.ts +168 -0
  71. package/src/cascade-select/cascade-select-trigger.ts +44 -0
  72. package/src/cascade-select/cascade-select.context.ts +71 -0
  73. package/src/cascade-select/cascade-select.spec.ts +241 -0
  74. package/src/cascade-select/cascade-select.ts +5 -0
  75. package/src/cascade-select/index.ts +11 -0
  76. package/src/chart/chart.ts +6 -2
  77. package/src/chat/chat-avatar.ts +31 -0
  78. package/src/chat/chat-bubble.ts +49 -0
  79. package/src/chat/chat-footer.ts +67 -0
  80. package/src/chat/chat-header.ts +41 -0
  81. package/src/chat/chat-log.ts +43 -0
  82. package/src/chat/chat.context.ts +64 -0
  83. package/src/chat/chat.spec.ts +341 -0
  84. package/src/chat/chat.ts +191 -0
  85. package/src/chat/config.ts +53 -0
  86. package/src/chat/index.ts +21 -0
  87. package/src/checkbox/checkbox.ts +9 -2
  88. package/src/color-picker/color-picker.context.ts +74 -0
  89. package/src/color-picker/color-picker.spec.ts +241 -0
  90. package/src/color-picker/color-picker.ts +698 -0
  91. package/src/color-picker/color-picker.utils.ts +140 -0
  92. package/src/color-picker/index.ts +28 -0
  93. package/src/combobox/combobox-input.ts +143 -0
  94. package/src/combobox/combobox-listbox.ts +49 -0
  95. package/src/combobox/combobox-option.ts +43 -0
  96. package/src/combobox/combobox-root.ts +281 -0
  97. package/src/combobox/combobox.spec.ts +75 -0
  98. package/src/combobox/combobox.ts +4 -0
  99. package/src/combobox/index.ts +4 -0
  100. package/src/command-palette/command-empty.ts +36 -0
  101. package/src/command-palette/command-group.ts +21 -0
  102. package/src/command-palette/command-input.ts +70 -0
  103. package/src/command-palette/command-item.ts +60 -0
  104. package/src/command-palette/command-list.ts +25 -0
  105. package/src/command-palette/command-palette-dialog.ts +74 -0
  106. package/src/command-palette/command-palette-trigger.ts +64 -0
  107. package/src/command-palette/command-palette.filters.ts +53 -0
  108. package/src/command-palette/command-palette.spec.ts +349 -0
  109. package/src/command-palette/command-palette.ts +204 -0
  110. package/src/command-palette/command-separator.ts +18 -0
  111. package/src/command-palette/index.ts +15 -0
  112. package/src/confirm-popup/confirm-popup-action.ts +39 -0
  113. package/src/confirm-popup/confirm-popup-cancel.ts +38 -0
  114. package/src/confirm-popup/confirm-popup-content.ts +113 -0
  115. package/src/confirm-popup/confirm-popup-message.ts +36 -0
  116. package/src/confirm-popup/confirm-popup-trigger.ts +31 -0
  117. package/src/confirm-popup/confirm-popup.context.ts +41 -0
  118. package/src/confirm-popup/confirm-popup.spec.ts +337 -0
  119. package/src/confirm-popup/confirm-popup.ts +109 -0
  120. package/src/confirm-popup/index.ts +12 -0
  121. package/src/date-picker/date-picker-calendar.ts +65 -0
  122. package/src/date-picker/date-picker-trigger.ts +215 -0
  123. package/src/date-picker/date-picker.context.ts +50 -0
  124. package/src/date-picker/date-picker.spec.ts +117 -0
  125. package/src/date-picker/date-picker.ts +127 -0
  126. package/src/date-picker/index.ts +7 -0
  127. package/src/dialog/_examples/dialog.confirm.example.ts +145 -0
  128. package/src/dialog/_examples/dialog.example.ts +106 -0
  129. package/src/dialog/_examples/dialog.finance.example.ts +121 -0
  130. package/src/dialog/_examples/dialog.retro.example.ts +126 -0
  131. package/src/dialog/_examples/index.ts +6 -0
  132. package/src/dialog/dialog.ref.ts +42 -0
  133. package/src/dialog/dialog.service.ts +57 -167
  134. package/src/dialog/dialog.spec.ts +35 -120
  135. package/src/dialog/dialog.ts +17 -192
  136. package/src/dialog/index.ts +3 -9
  137. package/src/divider/divider.spec.ts +223 -0
  138. package/src/divider/divider.ts +137 -0
  139. package/src/divider/index.ts +5 -0
  140. package/src/drawer/drawer.ref.ts +63 -0
  141. package/src/drawer/drawer.service.ts +106 -0
  142. package/src/drawer/drawer.spec.ts +117 -0
  143. package/src/drawer/drawer.ts +122 -0
  144. package/src/drawer/index.ts +10 -0
  145. package/src/dropdown-menu/dropdown-menu-content.ts +258 -0
  146. package/src/dropdown-menu/dropdown-menu-group.ts +31 -0
  147. package/src/dropdown-menu/dropdown-menu-item.ts +51 -0
  148. package/src/dropdown-menu/dropdown-menu-label.ts +41 -0
  149. package/src/dropdown-menu/dropdown-menu-separator.ts +27 -0
  150. package/src/dropdown-menu/dropdown-menu-trigger.ts +140 -0
  151. package/src/dropdown-menu/dropdown-menu.spec.ts +265 -0
  152. package/src/dropdown-menu/dropdown-menu.ts +60 -0
  153. package/src/dropdown-menu/index.ts +15 -0
  154. package/src/example-components.ts +39 -30
  155. package/src/field/field-error.ts +49 -0
  156. package/src/field/field-group.ts +39 -0
  157. package/src/field/field-help.ts +47 -0
  158. package/src/field/field-label.ts +30 -0
  159. package/src/field/field.context.ts +28 -0
  160. package/src/field/field.spec.ts +179 -0
  161. package/src/field/field.ts +121 -0
  162. package/src/field/index.ts +6 -0
  163. package/src/file-upload/file-upload.context.ts +89 -0
  164. package/src/file-upload/file-upload.spec.ts +290 -0
  165. package/src/file-upload/file-upload.ts +639 -0
  166. package/src/file-upload/file-upload.types.ts +59 -0
  167. package/src/file-upload/index.ts +23 -0
  168. package/src/form/form-error-summary.ts +87 -0
  169. package/src/form/form-field.context.ts +3 -0
  170. package/src/form/form-field.spec.ts +25 -0
  171. package/src/form/form-field.ts +52 -0
  172. package/src/form/form.context.ts +52 -2
  173. package/src/form/form.spec.ts +155 -18
  174. package/src/form/form.ts +315 -35
  175. package/src/form/index.ts +11 -2
  176. package/src/icon/E2E.md +14 -0
  177. package/src/icon/icon.css +40 -0
  178. package/src/icon/icon.directive.spec.ts +198 -0
  179. package/src/icon/icon.directive.ts +113 -0
  180. package/src/icon/icon.mode.spec.ts +29 -0
  181. package/src/icon/icon.mode.ts +23 -0
  182. package/src/icon/icon.providers.spec.ts +63 -0
  183. package/src/icon/icon.providers.ts +47 -0
  184. package/src/icon/icon.resolver.spec.ts +96 -0
  185. package/src/icon/icon.resolver.ts +49 -0
  186. package/src/icon/icon.tokens.ts +88 -0
  187. package/src/icon/icon.types.ts +48 -0
  188. package/src/icon/index.ts +21 -0
  189. package/src/input/input.ts +12 -3
  190. package/src/input-group/index.ts +3 -0
  191. package/src/input-group/input-group-addon.ts +92 -0
  192. package/src/input-group/input-group.context.ts +27 -0
  193. package/src/input-group/input-group.spec.ts +186 -0
  194. package/src/input-group/input-group.ts +136 -0
  195. package/src/input-mask/index.ts +11 -0
  196. package/src/input-mask/input-mask.compile.ts +69 -0
  197. package/src/input-mask/input-mask.engine.ts +376 -0
  198. package/src/input-mask/input-mask.presets.ts +24 -0
  199. package/src/input-mask/input-mask.spec.ts +304 -0
  200. package/src/input-mask/input-mask.tokens.ts +49 -0
  201. package/src/input-mask/input-mask.ts +280 -0
  202. package/src/input-otp/index.ts +2 -0
  203. package/src/input-otp/input-otp.context.ts +41 -0
  204. package/src/input-otp/input-otp.spec.ts +308 -0
  205. package/src/input-otp/input-otp.ts +470 -0
  206. package/src/kbd/index.ts +1 -0
  207. package/src/kbd/kbd.spec.ts +127 -0
  208. package/src/kbd/kbd.ts +132 -0
  209. package/src/link/config.ts +44 -0
  210. package/src/link/index.ts +2 -0
  211. package/src/link/link.spec.ts +246 -0
  212. package/src/link/link.ts +226 -0
  213. package/src/list/index.ts +11 -0
  214. package/src/list/list.spec.ts +237 -0
  215. package/src/list/list.ts +277 -0
  216. package/src/menubar/index.ts +7 -0
  217. package/src/menubar/menubar-item.ts +204 -0
  218. package/src/menubar/menubar.context.ts +43 -0
  219. package/src/menubar/menubar.spec.ts +433 -0
  220. package/src/menubar/menubar.ts +309 -0
  221. package/src/number-input/index.ts +4 -0
  222. package/src/number-input/number-input-group.ts +64 -0
  223. package/src/number-input/number-input.context.ts +31 -0
  224. package/src/number-input/number-input.format.ts +148 -0
  225. package/src/number-input/number-input.spec.ts +170 -0
  226. package/src/number-input/number-input.ts +457 -0
  227. package/src/number-input/number-stepper.ts +193 -0
  228. package/src/overlay-badge/index.ts +7 -0
  229. package/src/overlay-badge/overlay-badge-content.ts +73 -0
  230. package/src/overlay-badge/overlay-badge.context.ts +37 -0
  231. package/src/overlay-badge/overlay-badge.spec.ts +220 -0
  232. package/src/overlay-badge/overlay-badge.ts +128 -0
  233. package/src/pagination/config.ts +82 -0
  234. package/src/pagination/index.ts +19 -0
  235. package/src/pagination/page-tokens.ts +78 -0
  236. package/src/pagination/pagination-ellipsis.ts +69 -0
  237. package/src/pagination/pagination-first.ts +84 -0
  238. package/src/pagination/pagination-info.ts +70 -0
  239. package/src/pagination/pagination-item.ts +81 -0
  240. package/src/pagination/pagination-last.ts +85 -0
  241. package/src/pagination/pagination-next.ts +86 -0
  242. package/src/pagination/pagination-previous.ts +90 -0
  243. package/src/pagination/pagination.context.ts +52 -0
  244. package/src/pagination/pagination.spec.ts +388 -0
  245. package/src/pagination/pagination.ts +288 -0
  246. package/src/password-input/index.ts +15 -0
  247. package/src/password-input/password-input.context.ts +65 -0
  248. package/src/password-input/password-input.scorer.ts +34 -0
  249. package/src/password-input/password-input.spec.ts +274 -0
  250. package/src/password-input/password-input.ts +488 -0
  251. package/src/popover/_examples/index.ts +5 -0
  252. package/src/popover/_examples/popover.example.ts +92 -0
  253. package/src/popover/_examples/popover.finance.example.ts +106 -0
  254. package/src/popover/_examples/popover.retro.example.ts +103 -0
  255. package/src/popover/index.ts +5 -12
  256. package/src/popover/popover-arrow.ts +30 -0
  257. package/src/popover/popover-close.ts +36 -0
  258. package/src/popover/popover-content.ts +41 -0
  259. package/src/popover/popover-title.ts +39 -0
  260. package/src/popover/popover-trigger.ts +40 -0
  261. package/src/popover/popover.spec.ts +51 -44
  262. package/src/popover/popover.ts +5 -124
  263. package/src/presets/bind-presets.spec.ts +50 -0
  264. package/src/presets/bind-presets.ts +43 -0
  265. package/src/presets/index.ts +3 -0
  266. package/src/presets/size.spec.ts +67 -0
  267. package/src/presets/size.ts +59 -0
  268. package/src/presets/variant.spec.ts +72 -0
  269. package/src/presets/variant.ts +62 -0
  270. package/src/primitives/directionality/directionality.spec.ts +112 -0
  271. package/src/primitives/directionality/directionality.ts +89 -0
  272. package/src/primitives/directionality/index.ts +1 -0
  273. package/src/primitives/forms/form-control.spec.ts +14 -6
  274. package/src/primitives/forms/form-control.ts +6 -2
  275. package/src/primitives/index.ts +3 -0
  276. package/src/primitives/interaction/disabled.ts +12 -5
  277. package/src/primitives/interaction/focus-ring.ts +4 -2
  278. package/src/primitives/list/filterable-list.spec.ts +114 -0
  279. package/src/primitives/list/filterable-list.ts +126 -0
  280. package/src/primitives/list/group.spec.ts +99 -0
  281. package/src/primitives/list/group.ts +139 -0
  282. package/src/primitives/list/index.ts +8 -0
  283. package/src/primitives/list/inject-helpers.ts +8 -0
  284. package/src/primitives/list/item.spec.ts +173 -0
  285. package/src/primitives/list/item.ts +222 -0
  286. package/src/primitives/list/navigator.spec.ts +286 -0
  287. package/src/primitives/list/navigator.ts +238 -0
  288. package/src/primitives/list/selection.spec.ts +214 -0
  289. package/src/primitives/list/selection.ts +339 -0
  290. package/src/primitives/list/tokens.ts +106 -0
  291. package/src/primitives/list/type-ahead.spec.ts +58 -0
  292. package/src/primitives/list/type-ahead.ts +46 -0
  293. package/src/primitives/overlay/backdrop.spec.ts +54 -0
  294. package/src/primitives/overlay/backdrop.ts +31 -0
  295. package/src/primitives/overlay/builder.spec.ts +38 -0
  296. package/src/primitives/overlay/builder.ts +151 -0
  297. package/src/primitives/overlay/container.ts +42 -0
  298. package/src/primitives/overlay/context.ts +14 -0
  299. package/src/primitives/overlay/controller.spec.ts +86 -0
  300. package/src/primitives/overlay/controller.ts +190 -0
  301. package/src/primitives/overlay/id.spec.ts +24 -0
  302. package/src/primitives/overlay/id.ts +17 -0
  303. package/src/primitives/overlay/index.ts +18 -1
  304. package/src/primitives/overlay/overlay.css +42 -0
  305. package/src/primitives/overlay/panel.spec.ts +52 -0
  306. package/src/primitives/overlay/panel.ts +102 -0
  307. package/src/primitives/overlay/stack.spec.ts +55 -0
  308. package/src/primitives/overlay/stack.ts +113 -0
  309. package/src/primitives/overlay/strategies/backdrop/blurred.spec.ts +11 -0
  310. package/src/primitives/overlay/strategies/backdrop/blurred.ts +5 -0
  311. package/src/primitives/overlay/strategies/backdrop/none.spec.ts +10 -0
  312. package/src/primitives/overlay/strategies/backdrop/none.ts +9 -0
  313. package/src/primitives/overlay/strategies/backdrop/solid.spec.ts +18 -0
  314. package/src/primitives/overlay/strategies/backdrop/solid.ts +23 -0
  315. package/src/primitives/overlay/strategies/focus-trap/inert-based.spec.ts +28 -0
  316. package/src/primitives/overlay/strategies/focus-trap/inert-based.ts +38 -0
  317. package/src/primitives/overlay/strategies/focus-trap/no-trap.spec.ts +9 -0
  318. package/src/primitives/overlay/strategies/focus-trap/no-trap.ts +8 -0
  319. package/src/primitives/overlay/strategies/focus-trap/tab-cycle.spec.ts +49 -0
  320. package/src/primitives/overlay/strategies/focus-trap/tab-cycle.ts +85 -0
  321. package/src/primitives/overlay/strategies/index.ts +34 -0
  322. package/src/primitives/overlay/strategies/live-announcer/_announce.ts +35 -0
  323. package/src/primitives/overlay/strategies/live-announcer/assertive.spec.ts +21 -0
  324. package/src/primitives/overlay/strategies/live-announcer/assertive.ts +11 -0
  325. package/src/primitives/overlay/strategies/live-announcer/polite.spec.ts +21 -0
  326. package/src/primitives/overlay/strategies/live-announcer/polite.ts +11 -0
  327. package/src/primitives/overlay/strategies/live-announcer/silent.spec.ts +12 -0
  328. package/src/primitives/overlay/strategies/live-announcer/silent.ts +5 -0
  329. package/src/primitives/overlay/strategies/mount/body-portal.spec.ts +40 -0
  330. package/src/primitives/overlay/strategies/mount/body-portal.ts +91 -0
  331. package/src/primitives/overlay/strategies/mount/in-container.spec.ts +43 -0
  332. package/src/primitives/overlay/strategies/mount/in-container.ts +39 -0
  333. package/src/primitives/overlay/strategies/mount/in-place.spec.ts +40 -0
  334. package/src/primitives/overlay/strategies/mount/in-place.ts +20 -0
  335. package/src/primitives/overlay/strategies/position/anchored-to.spec.ts +56 -0
  336. package/src/primitives/overlay/strategies/position/anchored-to.ts +248 -0
  337. package/src/primitives/overlay/strategies/position/corner.spec.ts +36 -0
  338. package/src/primitives/overlay/strategies/position/corner.ts +33 -0
  339. package/src/primitives/overlay/strategies/position/edge-sheet.spec.ts +32 -0
  340. package/src/primitives/overlay/strategies/position/edge-sheet.ts +36 -0
  341. package/src/primitives/overlay/strategies/position/in-place-sibling.spec.ts +25 -0
  342. package/src/primitives/overlay/strategies/position/in-place-sibling.ts +13 -0
  343. package/src/primitives/overlay/strategies/position/point-at.spec.ts +40 -0
  344. package/src/primitives/overlay/strategies/position/point-at.ts +34 -0
  345. package/src/primitives/overlay/strategies/position/viewport-centered.spec.ts +31 -0
  346. package/src/primitives/overlay/strategies/position/viewport-centered.ts +31 -0
  347. package/src/primitives/overlay/strategies/scroll-lock/css-clip.spec.ts +15 -0
  348. package/src/primitives/overlay/strategies/scroll-lock/css-clip.ts +39 -0
  349. package/src/primitives/overlay/strategies/scroll-lock/html-overflow.spec.ts +21 -0
  350. package/src/primitives/overlay/strategies/scroll-lock/html-overflow.ts +44 -0
  351. package/src/primitives/overlay/strategies/scroll-lock/none.spec.ts +9 -0
  352. package/src/primitives/overlay/strategies/scroll-lock/none.ts +5 -0
  353. package/src/primitives/overlay/strategies/trigger-event/on-click.spec.ts +32 -0
  354. package/src/primitives/overlay/strategies/trigger-event/on-click.ts +28 -0
  355. package/src/primitives/overlay/strategies/trigger-event/on-context-menu.spec.ts +45 -0
  356. package/src/primitives/overlay/strategies/trigger-event/on-context-menu.ts +70 -0
  357. package/src/primitives/overlay/strategies/trigger-event/on-focus-or-input.spec.ts +35 -0
  358. package/src/primitives/overlay/strategies/trigger-event/on-focus-or-input.ts +34 -0
  359. package/src/primitives/overlay/strategies/trigger-event/on-focus.spec.ts +64 -0
  360. package/src/primitives/overlay/strategies/trigger-event/on-focus.ts +37 -0
  361. package/src/primitives/overlay/strategies/trigger-event/on-hotkey.spec.ts +37 -0
  362. package/src/primitives/overlay/strategies/trigger-event/on-hotkey.ts +59 -0
  363. package/src/primitives/overlay/strategies/trigger-event/on-hover.spec.ts +34 -0
  364. package/src/primitives/overlay/strategies/trigger-event/on-hover.ts +86 -0
  365. package/src/primitives/overlay/strategies/trigger-event/programmatic.spec.ts +16 -0
  366. package/src/primitives/overlay/strategies/trigger-event/programmatic.ts +12 -0
  367. package/src/primitives/overlay/tokens.ts +54 -0
  368. package/src/primitives/overlay/trigger.spec.ts +103 -0
  369. package/src/primitives/overlay/trigger.ts +75 -0
  370. package/src/primitives/overlay/types.ts +24 -0
  371. package/src/primitives/overlay/wrapper.ts +50 -0
  372. package/src/primitives/signals/deep-signal.ts +109 -0
  373. package/src/primitives/signals/index.ts +1 -0
  374. package/src/progress-bar/config.ts +48 -0
  375. package/src/progress-bar/index.ts +12 -0
  376. package/src/progress-bar/progress-bar-fill.ts +37 -0
  377. package/src/progress-bar/progress-bar.context.ts +34 -0
  378. package/src/progress-bar/progress-bar.spec.ts +423 -0
  379. package/src/progress-bar/progress-bar.ts +217 -0
  380. package/src/public-api.ts +58 -9
  381. package/src/radio/radio.ts +14 -3
  382. package/src/select/index.ts +4 -2
  383. package/src/select/select-content.ts +69 -0
  384. package/src/select/select-option.ts +35 -0
  385. package/src/select/select-root.ts +129 -0
  386. package/src/select/select-trigger.ts +93 -0
  387. package/src/select/select.spec.ts +133 -140
  388. package/src/select/select.ts +4 -250
  389. package/src/skeleton/index.ts +5 -0
  390. package/src/skeleton/skeleton.spec.ts +115 -0
  391. package/src/skeleton/skeleton.ts +56 -0
  392. package/src/slider/index.ts +10 -0
  393. package/src/slider/slider-range.ts +49 -0
  394. package/src/slider/slider-thumb.ts +335 -0
  395. package/src/slider/slider-track.ts +70 -0
  396. package/src/slider/slider.context.ts +79 -0
  397. package/src/slider/slider.geometry.ts +73 -0
  398. package/src/slider/slider.spec.ts +216 -0
  399. package/src/slider/slider.ts +443 -0
  400. package/src/speed-dial/index.ts +10 -0
  401. package/src/speed-dial/speed-dial-action.ts +40 -0
  402. package/src/speed-dial/speed-dial-actions.ts +31 -0
  403. package/src/speed-dial/speed-dial-trigger.ts +55 -0
  404. package/src/speed-dial/speed-dial.context.ts +36 -0
  405. package/src/speed-dial/speed-dial.spec.ts +143 -0
  406. package/src/speed-dial/speed-dial.ts +127 -0
  407. package/src/spinner/config.ts +48 -0
  408. package/src/spinner/index.ts +8 -0
  409. package/src/spinner/spinner.spec.ts +262 -0
  410. package/src/spinner/spinner.ts +129 -0
  411. package/src/stepper/index.ts +15 -0
  412. package/src/stepper/stepper.context.ts +63 -0
  413. package/src/stepper/stepper.spec.ts +403 -0
  414. package/src/stepper/stepper.ts +544 -0
  415. package/src/styles.css +17 -0
  416. package/src/table/column-helpers.spec.ts +74 -0
  417. package/src/table/column-helpers.ts +68 -0
  418. package/src/table/filter-fns.ts +230 -0
  419. package/src/table/filter-models.spec.ts +240 -0
  420. package/src/table/filter-models.ts +124 -0
  421. package/src/table/filter-params.ts +90 -0
  422. package/src/table/grid-api-impl.ts +321 -0
  423. package/src/table/grid-api.spec.ts +178 -0
  424. package/src/table/grid-api.ts +285 -0
  425. package/src/table/index.ts +73 -1
  426. package/src/table/table-cell.spec.ts +43 -0
  427. package/src/table/table-cell.ts +38 -0
  428. package/src/table/table-filter-outlet.ts +120 -0
  429. package/src/table/table-header.spec.ts +54 -0
  430. package/src/table/table-header.ts +63 -0
  431. package/src/table/table-keyboard.spec.ts +68 -0
  432. package/src/table/table-keyboard.ts +107 -0
  433. package/src/table/table-resource.spec.ts +37 -0
  434. package/src/table/table-resource.ts +36 -0
  435. package/src/table/table-row.spec.ts +54 -0
  436. package/src/table/table-row.ts +31 -0
  437. package/src/table/table-storage.spec.ts +67 -0
  438. package/src/table/table-storage.ts +76 -0
  439. package/src/table/table.spec.ts +102 -43
  440. package/src/table/table.ts +228 -73
  441. package/src/table/table.types.ts +83 -0
  442. package/src/tabs/index.ts +7 -2
  443. package/src/tabs/tabs.context.ts +27 -4
  444. package/src/tabs/tabs.spec.ts +336 -24
  445. package/src/tabs/tabs.ts +313 -79
  446. package/src/tag/config.ts +53 -0
  447. package/src/tag/index.ts +7 -0
  448. package/src/tag/tag-list.ts +76 -0
  449. package/src/tag/tag-remove.ts +61 -0
  450. package/src/tag/tag.context.ts +36 -0
  451. package/src/tag/tag.spec.ts +240 -0
  452. package/src/tag/tag.ts +203 -0
  453. package/src/textarea/config.ts +42 -0
  454. package/src/textarea/index.ts +8 -0
  455. package/src/textarea/textarea.spec.ts +176 -0
  456. package/src/textarea/textarea.ts +235 -0
  457. package/src/time-picker/index.ts +15 -0
  458. package/src/time-picker/time-picker-meridiem.ts +123 -0
  459. package/src/time-picker/time-picker-segment.ts +318 -0
  460. package/src/time-picker/time-picker.context.ts +38 -0
  461. package/src/time-picker/time-picker.format.ts +181 -0
  462. package/src/time-picker/time-picker.spec.ts +189 -0
  463. package/src/time-picker/time-picker.ts +274 -0
  464. package/src/toast/_examples/index.ts +5 -0
  465. package/src/toast/_examples/toast.example.ts +282 -0
  466. package/src/toast/_examples/toast.finance.example.ts +180 -0
  467. package/src/toast/_examples/toast.retro.example.ts +161 -0
  468. package/src/toast/index.ts +8 -1
  469. package/src/toast/toast.ref.ts +26 -0
  470. package/src/toast/toast.service.ts +227 -41
  471. package/src/toast/toast.spec.ts +178 -25
  472. package/src/toast/toast.strategy.ts +10 -0
  473. package/src/toast/toast.ts +178 -22
  474. package/src/toggle/toggle.ts +10 -2
  475. package/src/tooltip/_examples/index.ts +6 -0
  476. package/src/tooltip/_examples/tooltip.example.ts +82 -0
  477. package/src/tooltip/_examples/tooltip.finance.example.ts +97 -0
  478. package/src/tooltip/_examples/tooltip.placements.example.ts +83 -0
  479. package/src/tooltip/_examples/tooltip.retro.example.ts +107 -0
  480. package/src/tooltip/index.ts +4 -5
  481. package/src/tooltip/tooltip-arrow.ts +31 -0
  482. package/src/tooltip/tooltip-content.ts +38 -0
  483. package/src/tooltip/tooltip-group.ts +32 -0
  484. package/src/tooltip/tooltip-trigger.ts +47 -0
  485. package/src/tooltip/tooltip.spec.ts +38 -102
  486. package/src/tooltip/tooltip.ts +5 -129
  487. package/src/tree-select/index.ts +12 -0
  488. package/src/tree-select/tree-select-content.ts +199 -0
  489. package/src/tree-select/tree-select-node.ts +132 -0
  490. package/src/tree-select/tree-select-root.ts +272 -0
  491. package/src/tree-select/tree-select-trigger.ts +90 -0
  492. package/src/tree-select/tree-select.context.ts +63 -0
  493. package/src/tree-select/tree-select.spec.ts +433 -0
  494. package/src/tree-select/tree-select.ts +2 -0
  495. package/src/typography/blockquote.ts +57 -0
  496. package/src/typography/code.ts +53 -0
  497. package/src/typography/index.ts +22 -0
  498. package/src/typography/lead.ts +49 -0
  499. package/src/typography/muted.ts +29 -0
  500. package/src/typography/prose.css +312 -0
  501. package/src/typography/truncate.ts +99 -0
  502. package/src/typography/typography.spec.ts +203 -0
  503. package/tsconfig.lib.json +9 -1
  504. package/tsconfig.lib.prod.json +7 -1
  505. package/tsconfig.spec.json +9 -1
  506. package/vite.config.ts +8 -0
  507. package/src/button/button.example.ts +0 -30
  508. package/src/button/button.finance.example.ts +0 -37
  509. package/src/button/button.retro.example.ts +0 -47
  510. package/src/button/button.sizes.example.ts +0 -25
  511. package/src/dialog/dialog.confirm.example.ts +0 -57
  512. package/src/dialog/dialog.context.ts +0 -11
  513. package/src/dialog/dialog.example.ts +0 -40
  514. package/src/dialog/dialog.finance.example.ts +0 -47
  515. package/src/dialog/dialog.retro.example.ts +0 -46
  516. package/src/menu/index.ts +0 -2
  517. package/src/menu/menu.context.ts +0 -10
  518. package/src/menu/menu.example.ts +0 -39
  519. package/src/menu/menu.spec.ts +0 -168
  520. package/src/menu/menu.ts +0 -176
  521. package/src/popover/popover.context.ts +0 -18
  522. package/src/popover/popover.example.ts +0 -50
  523. package/src/popover/popover.finance.example.ts +0 -52
  524. package/src/popover/popover.retro.example.ts +0 -53
  525. package/src/primitives/overlay/overlay.spec.ts +0 -90
  526. package/src/primitives/overlay/overlay.ts +0 -102
  527. package/src/select/select.context.ts +0 -3
  528. package/src/toast/toast.example.ts +0 -134
  529. package/src/toast/toast.finance.example.ts +0 -68
  530. package/src/toast/toast.retro.example.ts +0 -69
  531. package/src/tooltip/tooltip.example.ts +0 -46
  532. package/src/tooltip/tooltip.finance.example.ts +0 -54
  533. package/src/tooltip/tooltip.placements.example.ts +0 -56
  534. package/src/tooltip/tooltip.retro.example.ts +0 -65
@@ -0,0 +1,90 @@
1
+ import {
2
+ InjectionToken,
3
+ Injector,
4
+ Provider,
5
+ TemplateRef,
6
+ Type,
7
+ inject,
8
+ type Signal,
9
+ } from '@angular/core';
10
+ import type { Column, RowData } from '@tanstack/angular-table';
11
+ import type { KjColumnApi, KjGridApi } from './grid-api';
12
+
13
+ /**
14
+ * Context handed to every custom filter — component class or template.
15
+ *
16
+ * Mirrors AG-Grid's `IFilterParams` shape: the column being filtered, the
17
+ * grid + column APIs for cross-cutting actions, the current model as a
18
+ * reactive signal, and an imperative setter that clears the filter on
19
+ * `null`/`undefined`/`''`. A signal is used (rather than a callback) so
20
+ * filter UIs can derive bound values via `computed()` without their own
21
+ * change-detection plumbing.
22
+ *
23
+ * Components either accept a single required input named `params` of this
24
+ * shape, or call {@link injectKjFilterParams}. Templates receive the same
25
+ * context via `$implicit` (`let-params`).
26
+ */
27
+ export interface KjFilterParams<TData extends RowData = unknown, TValue = unknown> {
28
+ /** The TanStack column the filter targets. */
29
+ readonly column: Column<TData, TValue>;
30
+ /** Grid-wide imperative API for cross-column actions. */
31
+ readonly api: KjGridApi<TData>;
32
+ /** Per-column imperative API. */
33
+ readonly columnApi: KjColumnApi<TData>;
34
+ /** Live filter model — reactive view of `column.getFilterValue()`. */
35
+ readonly model: Signal<TValue | null>;
36
+ /** Imperative setter. `null`, `undefined`, or `''` clear the filter. */
37
+ setModel(value: TValue | null | undefined): void;
38
+ /** True when the filter currently restricts results. */
39
+ isActive(): boolean;
40
+ /** Convenience: clear this filter. Equivalent to `setModel(null)`. */
41
+ clear(): void;
42
+ }
43
+
44
+ /**
45
+ * Anything that can render a filter UI: a standalone component class or a
46
+ * `TemplateRef` whose `$implicit` context is a `KjFilterParams`.
47
+ */
48
+ export type KjFilterRenderer<TData extends RowData = unknown, TValue = unknown> =
49
+ | Type<{ params?: unknown } & object>
50
+ | TemplateRef<KjFilterParams<TData, TValue>>;
51
+
52
+ /**
53
+ * Private token. Use {@link provideKjFilterParams} / {@link injectKjFilterParams}
54
+ * — the token itself is not exported from the package so consumers cannot
55
+ * bypass the helpers (and can't accidentally provide a malformed value).
56
+ */
57
+ const KJ_FILTER_PARAMS = new InjectionToken<KjFilterParams>('kj.filter.params');
58
+
59
+ /**
60
+ * Returns a `Provider` that exposes a `KjFilterParams` instance to a child
61
+ * injector. Used by `KjTableFilterOutlet` and the styled-wrapper's filter
62
+ * mounting code; user code should normally not call this directly.
63
+ */
64
+ export function provideKjFilterParams<TData extends RowData, TValue>(
65
+ params: KjFilterParams<TData, TValue>,
66
+ ): Provider {
67
+ return { provide: KJ_FILTER_PARAMS, useValue: params };
68
+ }
69
+
70
+ /**
71
+ * Resolve the active `KjFilterParams` from the current injection context.
72
+ *
73
+ * @example
74
+ * ```ts
75
+ * @Component({ selector: 'my-filter', template: '…' })
76
+ * class MyFilter {
77
+ * protected readonly params = injectKjFilterParams<User, string>();
78
+ * protected onInput(v: string) { this.params.setModel(v || null); }
79
+ * }
80
+ * ```
81
+ */
82
+ export function injectKjFilterParams<
83
+ TData extends RowData = unknown,
84
+ TValue = unknown,
85
+ >(injector?: Injector): KjFilterParams<TData, TValue> {
86
+ const params = injector
87
+ ? injector.get(KJ_FILTER_PARAMS)
88
+ : inject(KJ_FILTER_PARAMS);
89
+ return params as KjFilterParams<TData, TValue>;
90
+ }
@@ -0,0 +1,321 @@
1
+ import type { WritableSignal, Signal } from '@angular/core';
2
+ import type {
3
+ ColumnFiltersState,
4
+ ColumnOrderState,
5
+ ColumnPinningState,
6
+ ColumnSizingState,
7
+ ExpandedState,
8
+ GroupingState,
9
+ PaginationState,
10
+ RowData,
11
+ RowSelectionState,
12
+ Table,
13
+ VisibilityState,
14
+ } from '@tanstack/angular-table';
15
+ import type {
16
+ KjColumnApi,
17
+ KjColumnGroupingApi,
18
+ KjColumnOrderApi,
19
+ KjColumnPinningApi,
20
+ KjColumnSizingApi,
21
+ KjColumnVisibilityApi,
22
+ KjDensityApi,
23
+ KjExpansionApi,
24
+ KjFilterApi,
25
+ KjGlobalFilterApi,
26
+ KjGridApi,
27
+ KjGroupingApi,
28
+ KjPaginationApi,
29
+ KjRowsApi,
30
+ KjSelectionApi,
31
+ KjSortApi,
32
+ } from './grid-api';
33
+ import { isKjFilterModel, type KjFilterModel, type KjGridFilterModel } from './filter-models';
34
+ import type { KjTableDensity, KjTableState } from './table.types';
35
+
36
+ /**
37
+ * Build a `KjGridApi` + `KjColumnApi` pair bound to a directive instance.
38
+ * Called once from `KjTable` and cached. Methods close over the directive's
39
+ * private state signal and the lazy TanStack `Table` getter so every call
40
+ * sees the live grid.
41
+ */
42
+ export function createGridApi<TData extends RowData>(opts: {
43
+ state: Signal<KjTableState>;
44
+ table: () => Table<TData>;
45
+ patch: <K extends keyof KjTableState>(
46
+ key: K,
47
+ updater: KjTableState[K] | ((prev: KjTableState[K]) => KjTableState[K]),
48
+ ) => void;
49
+ setStateInternal: WritableSignal<KjTableState>['update'];
50
+ resetState: () => void;
51
+ defaultState: KjTableState;
52
+ }): { gridApi: KjGridApi<TData>; columnApi: KjColumnApi<TData> } {
53
+ const { state, table, patch, resetState, defaultState } = opts;
54
+
55
+ const setStateMerge = (partial: Partial<KjTableState>): void => {
56
+ opts.setStateInternal((s) => ({ ...s, ...partial }));
57
+ };
58
+
59
+ // ── KjColumnApi namespaces ────────────────────────────────────────────────
60
+
61
+ const visibility: KjColumnVisibilityApi = {
62
+ get: () => state().columnVisibility,
63
+ set: (model) => patch('columnVisibility', model),
64
+ isVisible: (id) => state().columnVisibility[id] !== false,
65
+ setVisible: (id, visible) =>
66
+ patch('columnVisibility', (prev: VisibilityState) => ({ ...prev, [id]: visible })),
67
+ setManyVisible: (ids, visible) =>
68
+ patch('columnVisibility', (prev: VisibilityState) => {
69
+ const next = { ...prev };
70
+ for (const id of ids) next[id] = visible;
71
+ return next;
72
+ }),
73
+ };
74
+
75
+ const sizing: KjColumnSizingApi = {
76
+ get: () => state().columnSizing,
77
+ set: (model) => patch('columnSizing', model),
78
+ width: (id) => table().getColumn(id)?.getSize() ?? 0,
79
+ setWidth: (id, width) =>
80
+ patch('columnSizing', (prev: ColumnSizingState) => ({ ...prev, [id]: width })),
81
+ };
82
+
83
+ const pinning: KjColumnPinningApi = {
84
+ get: () => state().columnPinning,
85
+ set: (model) => patch('columnPinning', model),
86
+ of: (id) => {
87
+ const p = state().columnPinning;
88
+ if ((p.left ?? []).includes(id)) return 'left';
89
+ if ((p.right ?? []).includes(id)) return 'right';
90
+ return null;
91
+ },
92
+ pin: (id, side) =>
93
+ patch('columnPinning', (prev: ColumnPinningState) => ({
94
+ left: (prev.left ?? []).filter((c) => c !== id).concat(side === 'left' ? [id] : []),
95
+ right: (prev.right ?? []).filter((c) => c !== id).concat(side === 'right' ? [id] : []),
96
+ })),
97
+ };
98
+
99
+ const order: KjColumnOrderApi = {
100
+ get: () => state().columnOrder,
101
+ set: (o) => patch('columnOrder', o),
102
+ move: (id, toIndex) =>
103
+ patch('columnOrder', (prev: ColumnOrderState) => {
104
+ const base = prev.length > 0 ? prev : table().getAllLeafColumns().map((c) => c.id);
105
+ const without = base.filter((c) => c !== id);
106
+ const clamped = Math.max(0, Math.min(toIndex, without.length));
107
+ return [...without.slice(0, clamped), id, ...without.slice(clamped)];
108
+ }),
109
+ };
110
+
111
+ const colGrouping: KjColumnGroupingApi = {
112
+ is: (id) => state().grouping.includes(id),
113
+ set: (id, grouped) =>
114
+ patch('grouping', (prev: GroupingState) =>
115
+ grouped
116
+ ? prev.includes(id) ? prev : [...prev, id]
117
+ : prev.filter((c) => c !== id),
118
+ ),
119
+ };
120
+
121
+ const columnApi: KjColumnApi<TData> = {
122
+ get: (id) => table().getColumn(id) ?? null,
123
+ all: () => table().getAllColumns(),
124
+ leaves: () => table().getAllLeafColumns(),
125
+ visibleLeaves: () => table().getVisibleLeafColumns(),
126
+ visibility,
127
+ sizing,
128
+ pinning,
129
+ order,
130
+ grouping: colGrouping,
131
+ reset: () =>
132
+ setStateMerge({
133
+ columnVisibility: defaultState.columnVisibility,
134
+ columnSizing: defaultState.columnSizing,
135
+ columnPinning: defaultState.columnPinning,
136
+ columnOrder: defaultState.columnOrder,
137
+ grouping: defaultState.grouping,
138
+ }),
139
+ };
140
+
141
+ // ── KjGridApi namespaces ──────────────────────────────────────────────────
142
+
143
+ const rows: KjRowsApi<TData> = {
144
+ all: () => (table().options.data ?? []) as readonly TData[],
145
+ displayed: () => table().getRowModel().rows,
146
+ count: () => (table().options.data?.length ?? 0),
147
+ filteredCount: () => table().getFilteredRowModel().rows.length,
148
+ displayedCount: () => table().getRowModel().rows.length,
149
+ get: (id) => table().getRow(id, /* searchAll */ true),
150
+ };
151
+
152
+ const selection: KjSelectionApi<TData> = {
153
+ get: () => state().rowSelection,
154
+ set: (model) => patch('rowSelection', model),
155
+ rows: () => table().getSelectedRowModel().rows,
156
+ ids: () => Object.keys(state().rowSelection).filter((id) => state().rowSelection[id]),
157
+ has: () => {
158
+ const sel = state().rowSelection;
159
+ for (const key in sel) if (sel[key]) return true;
160
+ return false;
161
+ },
162
+ select: (id, selected = true) =>
163
+ patch('rowSelection', (prev: RowSelectionState) => ({ ...prev, [id]: selected })),
164
+ deselect: (id) =>
165
+ patch('rowSelection', (prev: RowSelectionState) => {
166
+ const next = { ...prev };
167
+ delete next[id];
168
+ return next;
169
+ }),
170
+ toggle: (id) =>
171
+ patch('rowSelection', (prev: RowSelectionState) => ({ ...prev, [id]: !prev[id] })),
172
+ all: () => {
173
+ const next: RowSelectionState = {};
174
+ for (const r of table().getFilteredRowModel().rows) next[r.id] = true;
175
+ patch('rowSelection', next);
176
+ },
177
+ clear: () => patch('rowSelection', {}),
178
+ };
179
+
180
+ const sort: KjSortApi = {
181
+ get: () => state().sorting,
182
+ set: (s) => patch('sorting', s),
183
+ toggle: (columnId, multi = false) => {
184
+ const col = table().getColumn(columnId);
185
+ if (!col) return;
186
+ col.toggleSorting(undefined, multi);
187
+ },
188
+ clear: () => patch('sorting', []),
189
+ };
190
+
191
+ const globalFilter: KjGlobalFilterApi = {
192
+ get: () => state().globalFilter,
193
+ set: (value) => patch('globalFilter', value),
194
+ clear: () => patch('globalFilter', ''),
195
+ };
196
+
197
+ const filter: KjFilterApi = {
198
+ get: (id) => state().columnFilters.find((f) => f.id === id)?.value,
199
+ set: (id, value) =>
200
+ patch('columnFilters', (prev: ColumnFiltersState) => {
201
+ const without = prev.filter((f) => f.id !== id);
202
+ return value === undefined || value === null || value === ''
203
+ ? without
204
+ : [...without, { id, value }];
205
+ }),
206
+ clear: (id) =>
207
+ patch('columnFilters', (prev: ColumnFiltersState) => prev.filter((f) => f.id !== id)),
208
+ all: () => state().columnFilters,
209
+ setAll: (filters) => patch('columnFilters', filters),
210
+ global: globalFilter,
211
+ clearAll: () => setStateMerge({ columnFilters: [], globalFilter: '' }),
212
+
213
+ getModelFor: (id) => {
214
+ const v = state().columnFilters.find((f) => f.id === id)?.value;
215
+ return isKjFilterModel(v) ? v : undefined;
216
+ },
217
+ setModelFor: (id, model) =>
218
+ patch('columnFilters', (prev: ColumnFiltersState) => {
219
+ const without = prev.filter((f) => f.id !== id);
220
+ return model == null ? without : [...without, { id, value: model }];
221
+ }),
222
+ getModel: (): KjGridFilterModel => {
223
+ const out: Record<string, KjFilterModel> = {};
224
+ for (const entry of state().columnFilters) {
225
+ if (isKjFilterModel(entry.value)) out[entry.id] = entry.value;
226
+ }
227
+ return out;
228
+ },
229
+ setModel: (model) =>
230
+ patch('columnFilters', () => {
231
+ if (!model) return [];
232
+ return Object.entries(model).map(([id, value]) => ({ id, value }));
233
+ }),
234
+ };
235
+
236
+ const pagination: KjPaginationApi = {
237
+ get: () => state().pagination,
238
+ set: (p) => patch('pagination', p),
239
+ pageCount: () => table().getPageCount(),
240
+ setPageIndex: (pageIndex) =>
241
+ patch('pagination', (prev: PaginationState) => ({ ...prev, pageIndex: Math.max(0, pageIndex) })),
242
+ setPageSize: (pageSize) =>
243
+ patch('pagination', () => ({ pageIndex: 0, pageSize: Math.max(1, pageSize) })),
244
+ next: () =>
245
+ patch('pagination', (prev: PaginationState) => ({
246
+ ...prev,
247
+ pageIndex: Math.min(prev.pageIndex + 1, Math.max(0, table().getPageCount() - 1)),
248
+ })),
249
+ previous: () =>
250
+ patch('pagination', (prev: PaginationState) => ({
251
+ ...prev,
252
+ pageIndex: Math.max(0, prev.pageIndex - 1),
253
+ })),
254
+ first: () => patch('pagination', (prev: PaginationState) => ({ ...prev, pageIndex: 0 })),
255
+ last: () =>
256
+ patch('pagination', (prev: PaginationState) => ({
257
+ ...prev,
258
+ pageIndex: Math.max(0, table().getPageCount() - 1),
259
+ })),
260
+ };
261
+
262
+ const expansion: KjExpansionApi<TData> = {
263
+ get: () => state().expanded,
264
+ set: (e) => patch('expanded', e),
265
+ setRow: (id, expanded) =>
266
+ patch('expanded', (prev: ExpandedState) => {
267
+ if (prev === true) {
268
+ const next: Record<string, boolean> = {};
269
+ for (const r of table().getCoreRowModel().rows) next[r.id] = true;
270
+ next[id] = expanded;
271
+ return next;
272
+ }
273
+ return { ...prev, [id]: expanded };
274
+ }),
275
+ toggle: (id) =>
276
+ patch('expanded', (prev: ExpandedState) => {
277
+ if (prev === true) {
278
+ const next: Record<string, boolean> = {};
279
+ for (const r of table().getCoreRowModel().rows) next[r.id] = true;
280
+ next[id] = false;
281
+ return next;
282
+ }
283
+ return { ...prev, [id]: !prev[id] };
284
+ }),
285
+ expandAll: () => patch('expanded', true),
286
+ collapseAll: () => patch('expanded', {}),
287
+ };
288
+
289
+ const grouping: KjGroupingApi = {
290
+ get: () => state().grouping,
291
+ set: (g) => patch('grouping', g),
292
+ add: (id) =>
293
+ patch('grouping', (prev: GroupingState) => prev.includes(id) ? prev : [...prev, id]),
294
+ remove: (id) =>
295
+ patch('grouping', (prev: GroupingState) =>
296
+ id === undefined ? [] : prev.filter((c) => c !== id),
297
+ ),
298
+ };
299
+
300
+ const density: KjDensityApi = {
301
+ get: () => state().density,
302
+ set: (d: KjTableDensity) => patch('density', d),
303
+ };
304
+
305
+ const gridApi: KjGridApi<TData> = {
306
+ state,
307
+ table,
308
+ rows,
309
+ selection,
310
+ sort,
311
+ filter,
312
+ pagination,
313
+ expansion,
314
+ grouping,
315
+ density,
316
+ setState: setStateMerge,
317
+ resetState,
318
+ };
319
+
320
+ return { gridApi, columnApi };
321
+ }
@@ -0,0 +1,178 @@
1
+ import { Component, signal, ChangeDetectionStrategy } from '@angular/core';
2
+ import { render } from '@testing-library/angular';
3
+ import { describe, expect, it } from 'vitest';
4
+ import { KjTable } from './table';
5
+ import { kjColumn } from './column-helpers';
6
+
7
+ interface User {
8
+ id: string;
9
+ name: string;
10
+ age: number;
11
+ }
12
+
13
+ @Component({
14
+ standalone: true,
15
+ imports: [KjTable],
16
+ changeDetection: ChangeDetectionStrategy.Eager,
17
+ template: `<table
18
+ [kjTable]="cols"
19
+ [kjTableData]="data()"
20
+ [kjGetRowId]="getId"
21
+ #t="kjTable"
22
+ ></table>`,
23
+ })
24
+ class Host {
25
+ protected readonly cols = [
26
+ kjColumn<User>({ accessorKey: 'name', header: 'Name' }),
27
+ kjColumn<User>({ accessorKey: 'age', header: 'Age', filterFn: 'equals' }),
28
+ ];
29
+ protected readonly data = signal<User[]>([
30
+ { id: '1', name: 'Alice', age: 30 },
31
+ { id: '2', name: 'Bob', age: 25 },
32
+ { id: '3', name: 'Carol', age: 40 },
33
+ ]);
34
+ protected readonly getId = (row: User) => row.id;
35
+ }
36
+
37
+ async function getDir() {
38
+ const r = await render(Host);
39
+ return r.fixture.debugElement.children[0].injector.get(KjTable<User>);
40
+ }
41
+
42
+ describe('KjGridApi (regrouped)', () => {
43
+ it('rows: count / displayedCount / filteredCount', async () => {
44
+ const { rows } = (await getDir()).gridApi;
45
+ expect(rows.count()).toBe(3);
46
+ expect(rows.displayedCount()).toBe(3);
47
+ expect(rows.filteredCount()).toBe(3);
48
+ });
49
+
50
+ it('selection: select/deselect/toggle/all/clear', async () => {
51
+ const { selection } = (await getDir()).gridApi;
52
+ expect(selection.has()).toBe(false);
53
+
54
+ selection.select('1');
55
+ expect(selection.has()).toBe(true);
56
+ expect(selection.ids()).toEqual(['1']);
57
+
58
+ selection.toggle('2');
59
+ expect([...selection.ids()].sort()).toEqual(['1', '2']);
60
+
61
+ selection.deselect('1');
62
+ expect(selection.ids()).toEqual(['2']);
63
+
64
+ selection.all();
65
+ expect([...selection.ids()].sort()).toEqual(['1', '2', '3']);
66
+
67
+ selection.clear();
68
+ expect(selection.has()).toBe(false);
69
+ });
70
+
71
+ it('sort: set / clear', async () => {
72
+ const { sort } = (await getDir()).gridApi;
73
+ sort.set([{ id: 'name', desc: true }]);
74
+ expect(sort.get()).toEqual([{ id: 'name', desc: true }]);
75
+ sort.clear();
76
+ expect(sort.get()).toEqual([]);
77
+ });
78
+
79
+ it('filter: column set/clear, global, clearAll', async () => {
80
+ const { filter, rows } = (await getDir()).gridApi;
81
+ filter.set('age', 30);
82
+ expect(filter.get('age')).toBe(30);
83
+ expect(rows.filteredCount()).toBe(1);
84
+ filter.clear('age');
85
+ expect(filter.get('age')).toBeUndefined();
86
+ expect(rows.filteredCount()).toBe(3);
87
+
88
+ filter.global.set('al');
89
+ expect(filter.global.get()).toBe('al');
90
+ filter.clearAll();
91
+ expect(filter.global.get()).toBe('');
92
+ expect(filter.all()).toEqual([]);
93
+ });
94
+
95
+ it('pagination: next/previous/first/last + setPageSize resets index', async () => {
96
+ const { pagination } = (await getDir()).gridApi;
97
+ pagination.setPageSize(1);
98
+ expect(pagination.pageCount()).toBe(3);
99
+ pagination.next();
100
+ expect(pagination.get().pageIndex).toBe(1);
101
+ pagination.last();
102
+ expect(pagination.get().pageIndex).toBe(2);
103
+ pagination.previous();
104
+ expect(pagination.get().pageIndex).toBe(1);
105
+ pagination.first();
106
+ expect(pagination.get().pageIndex).toBe(0);
107
+ pagination.setPageSize(2);
108
+ expect(pagination.get()).toEqual({ pageIndex: 0, pageSize: 2 });
109
+ });
110
+
111
+ it('density: get/set', async () => {
112
+ const { density } = (await getDir()).gridApi;
113
+ expect(density.get()).toBe('standard');
114
+ density.set('compact');
115
+ expect(density.get()).toBe('compact');
116
+ });
117
+
118
+ it('grouping: add / remove / set', async () => {
119
+ const { grouping } = (await getDir()).gridApi;
120
+ grouping.add('name');
121
+ expect(grouping.get()).toEqual(['name']);
122
+ grouping.add('name'); // no-op
123
+ expect(grouping.get()).toEqual(['name']);
124
+ grouping.remove('name');
125
+ expect(grouping.get()).toEqual([]);
126
+ grouping.set(['name', 'age']);
127
+ grouping.remove();
128
+ expect(grouping.get()).toEqual([]);
129
+ });
130
+ });
131
+
132
+ describe('KjColumnApi (regrouped)', () => {
133
+ it('visibility: setVisible / setManyVisible / isVisible', async () => {
134
+ const { visibility } = (await getDir()).columnApi;
135
+ expect(visibility.isVisible('name')).toBe(true);
136
+ visibility.setVisible('name', false);
137
+ expect(visibility.isVisible('name')).toBe(false);
138
+ visibility.setManyVisible(['name', 'age'], true);
139
+ expect(visibility.isVisible('name')).toBe(true);
140
+ expect(visibility.isVisible('age')).toBe(true);
141
+ });
142
+
143
+ it('pinning: pin / of', async () => {
144
+ const { pinning } = (await getDir()).columnApi;
145
+ expect(pinning.of('name')).toBeNull();
146
+ pinning.pin('name', 'left');
147
+ expect(pinning.of('name')).toBe('left');
148
+ pinning.pin('name', 'right');
149
+ expect(pinning.of('name')).toBe('right');
150
+ pinning.pin('name', null);
151
+ expect(pinning.of('name')).toBeNull();
152
+ });
153
+
154
+ it('order: move', async () => {
155
+ const { order } = (await getDir()).columnApi;
156
+ order.move('age', 0);
157
+ expect(order.get()[0]).toBe('age');
158
+ });
159
+
160
+ it('grouping (per-column): is / set', async () => {
161
+ const { grouping } = (await getDir()).columnApi;
162
+ grouping.set('name', true);
163
+ expect(grouping.is('name')).toBe(true);
164
+ grouping.set('name', false);
165
+ expect(grouping.is('name')).toBe(false);
166
+ });
167
+
168
+ it('reset() clears every column-level slice', async () => {
169
+ const colApi = (await getDir()).columnApi;
170
+ colApi.pinning.pin('name', 'left');
171
+ colApi.visibility.setVisible('age', false);
172
+ colApi.grouping.set('name', true);
173
+ colApi.reset();
174
+ expect(colApi.pinning.of('name')).toBeNull();
175
+ expect(colApi.visibility.isVisible('age')).toBe(true);
176
+ expect(colApi.grouping.is('name')).toBe(false);
177
+ });
178
+ });