@kouji-ui/core 0.1.1 → 0.1.3

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 (535) hide show
  1. package/fesm2022/kouji-ui-core.mjs +26789 -0
  2. package/fesm2022/kouji-ui-core.mjs.map +1 -0
  3. package/package.json +15 -7
  4. package/types/kouji-ui-core.d.ts +13545 -0
  5. package/.turbo/turbo-build.log +0 -30
  6. package/CHANGELOG.md +0 -190
  7. package/ng-package.json +0 -11
  8. package/src/a11y/.gitkeep +0 -0
  9. package/src/a11y/aria-describedby.spec.ts +0 -55
  10. package/src/a11y/aria-describedby.ts +0 -37
  11. package/src/a11y/aria-labelledby.spec.ts +0 -55
  12. package/src/a11y/aria-labelledby.ts +0 -38
  13. package/src/a11y/focus-trap.spec.ts +0 -86
  14. package/src/a11y/focus-trap.ts +0 -72
  15. package/src/a11y/index.ts +0 -10
  16. package/src/a11y/live-region.spec.ts +0 -58
  17. package/src/a11y/live-region.ts +0 -50
  18. package/src/a11y/roving-tabindex.spec.ts +0 -201
  19. package/src/a11y/roving-tabindex.ts +0 -153
  20. package/src/a11y/visually-hidden.spec.ts +0 -34
  21. package/src/a11y/visually-hidden.ts +0 -26
  22. package/src/accordion/accordion.context.ts +0 -44
  23. package/src/accordion/accordion.spec.ts +0 -242
  24. package/src/accordion/accordion.ts +0 -401
  25. package/src/accordion/index.ts +0 -8
  26. package/src/alert/alert.context.ts +0 -28
  27. package/src/alert/alert.spec.ts +0 -217
  28. package/src/alert/alert.ts +0 -417
  29. package/src/alert/config.ts +0 -46
  30. package/src/alert/index.ts +0 -19
  31. package/src/avatar/avatar-group.context.ts +0 -45
  32. package/src/avatar/avatar-group.spec.ts +0 -358
  33. package/src/avatar/avatar-group.ts +0 -259
  34. package/src/avatar/avatar.spec.ts +0 -18
  35. package/src/avatar/avatar.ts +0 -39
  36. package/src/avatar/index.ts +0 -11
  37. package/src/badge/badge.spec.ts +0 -28
  38. package/src/badge/badge.ts +0 -35
  39. package/src/badge/index.ts +0 -1
  40. package/src/breadcrumb/breadcrumb-current.ts +0 -38
  41. package/src/breadcrumb/breadcrumb-ellipsis.ts +0 -71
  42. package/src/breadcrumb/breadcrumb-item.ts +0 -41
  43. package/src/breadcrumb/breadcrumb-link.ts +0 -44
  44. package/src/breadcrumb/breadcrumb-list.ts +0 -42
  45. package/src/breadcrumb/breadcrumb-separator.ts +0 -45
  46. package/src/breadcrumb/breadcrumb.context.ts +0 -45
  47. package/src/breadcrumb/breadcrumb.spec.ts +0 -354
  48. package/src/breadcrumb/breadcrumb.ts +0 -239
  49. package/src/breadcrumb/config.ts +0 -84
  50. package/src/breadcrumb/index.ts +0 -18
  51. package/src/button/_examples/button.example.ts +0 -71
  52. package/src/button/_examples/button.finance.example.ts +0 -83
  53. package/src/button/_examples/button.retro.example.ts +0 -91
  54. package/src/button/_examples/button.sizes.example.ts +0 -60
  55. package/src/button/_examples/index.ts +0 -6
  56. package/src/button/button.spec.ts +0 -163
  57. package/src/button/button.ts +0 -142
  58. package/src/button/config.spec.ts +0 -33
  59. package/src/button/config.ts +0 -45
  60. package/src/button/index.ts +0 -2
  61. package/src/button-group/button-group.context.ts +0 -28
  62. package/src/button-group/button-group.spec.ts +0 -99
  63. package/src/button-group/button-group.ts +0 -99
  64. package/src/button-group/index.ts +0 -2
  65. package/src/calendar/calendar-day.ts +0 -102
  66. package/src/calendar/calendar-grid.ts +0 -90
  67. package/src/calendar/calendar-header.ts +0 -65
  68. package/src/calendar/calendar.context.ts +0 -53
  69. package/src/calendar/calendar.spec.ts +0 -225
  70. package/src/calendar/calendar.ts +0 -233
  71. package/src/calendar/date-utils.ts +0 -225
  72. package/src/calendar/index.ts +0 -28
  73. package/src/carousel/carousel.context.ts +0 -81
  74. package/src/carousel/carousel.spec.ts +0 -337
  75. package/src/carousel/carousel.ts +0 -919
  76. package/src/carousel/index.ts +0 -22
  77. package/src/cascade-select/cascade-select-option.ts +0 -205
  78. package/src/cascade-select/cascade-select-panel.ts +0 -106
  79. package/src/cascade-select/cascade-select-root.ts +0 -265
  80. package/src/cascade-select/cascade-select-sub-panel.ts +0 -168
  81. package/src/cascade-select/cascade-select-trigger.ts +0 -44
  82. package/src/cascade-select/cascade-select.context.ts +0 -71
  83. package/src/cascade-select/cascade-select.spec.ts +0 -241
  84. package/src/cascade-select/cascade-select.ts +0 -5
  85. package/src/cascade-select/index.ts +0 -11
  86. package/src/chart/chart.spec.ts +0 -27
  87. package/src/chart/chart.ts +0 -52
  88. package/src/chart/index.ts +0 -1
  89. package/src/chat/chat-avatar.ts +0 -31
  90. package/src/chat/chat-bubble.ts +0 -49
  91. package/src/chat/chat-footer.ts +0 -67
  92. package/src/chat/chat-header.ts +0 -41
  93. package/src/chat/chat-log.ts +0 -43
  94. package/src/chat/chat.context.ts +0 -64
  95. package/src/chat/chat.spec.ts +0 -341
  96. package/src/chat/chat.ts +0 -191
  97. package/src/chat/config.ts +0 -53
  98. package/src/chat/index.ts +0 -21
  99. package/src/checkbox/checkbox.spec.ts +0 -35
  100. package/src/checkbox/checkbox.ts +0 -89
  101. package/src/checkbox/index.ts +0 -1
  102. package/src/color-picker/color-picker.context.ts +0 -74
  103. package/src/color-picker/color-picker.spec.ts +0 -241
  104. package/src/color-picker/color-picker.ts +0 -698
  105. package/src/color-picker/color-picker.utils.ts +0 -140
  106. package/src/color-picker/index.ts +0 -28
  107. package/src/combobox/combobox-input.ts +0 -143
  108. package/src/combobox/combobox-listbox.ts +0 -49
  109. package/src/combobox/combobox-option.ts +0 -43
  110. package/src/combobox/combobox-root.ts +0 -281
  111. package/src/combobox/combobox.spec.ts +0 -75
  112. package/src/combobox/combobox.ts +0 -4
  113. package/src/combobox/index.ts +0 -4
  114. package/src/command-palette/command-empty.ts +0 -36
  115. package/src/command-palette/command-group.ts +0 -21
  116. package/src/command-palette/command-input.ts +0 -70
  117. package/src/command-palette/command-item.ts +0 -60
  118. package/src/command-palette/command-list.ts +0 -25
  119. package/src/command-palette/command-palette-dialog.ts +0 -74
  120. package/src/command-palette/command-palette-trigger.ts +0 -64
  121. package/src/command-palette/command-palette.filters.ts +0 -53
  122. package/src/command-palette/command-palette.spec.ts +0 -349
  123. package/src/command-palette/command-palette.ts +0 -204
  124. package/src/command-palette/command-separator.ts +0 -18
  125. package/src/command-palette/index.ts +0 -15
  126. package/src/confirm-popup/confirm-popup-action.ts +0 -39
  127. package/src/confirm-popup/confirm-popup-cancel.ts +0 -38
  128. package/src/confirm-popup/confirm-popup-content.ts +0 -113
  129. package/src/confirm-popup/confirm-popup-message.ts +0 -36
  130. package/src/confirm-popup/confirm-popup-trigger.ts +0 -31
  131. package/src/confirm-popup/confirm-popup.context.ts +0 -41
  132. package/src/confirm-popup/confirm-popup.spec.ts +0 -337
  133. package/src/confirm-popup/confirm-popup.ts +0 -109
  134. package/src/confirm-popup/index.ts +0 -12
  135. package/src/date-picker/date-picker-calendar.ts +0 -65
  136. package/src/date-picker/date-picker-trigger.ts +0 -215
  137. package/src/date-picker/date-picker.context.ts +0 -50
  138. package/src/date-picker/date-picker.spec.ts +0 -117
  139. package/src/date-picker/date-picker.ts +0 -127
  140. package/src/date-picker/index.ts +0 -7
  141. package/src/dialog/_examples/dialog.confirm.example.ts +0 -145
  142. package/src/dialog/_examples/dialog.example.ts +0 -106
  143. package/src/dialog/_examples/dialog.finance.example.ts +0 -121
  144. package/src/dialog/_examples/dialog.retro.example.ts +0 -126
  145. package/src/dialog/_examples/index.ts +0 -6
  146. package/src/dialog/dialog.ref.ts +0 -42
  147. package/src/dialog/dialog.service.ts +0 -66
  148. package/src/dialog/dialog.spec.ts +0 -37
  149. package/src/dialog/dialog.ts +0 -26
  150. package/src/dialog/index.ts +0 -3
  151. package/src/divider/divider.spec.ts +0 -223
  152. package/src/divider/divider.ts +0 -137
  153. package/src/divider/index.ts +0 -5
  154. package/src/drawer/drawer.ref.ts +0 -63
  155. package/src/drawer/drawer.service.ts +0 -106
  156. package/src/drawer/drawer.spec.ts +0 -117
  157. package/src/drawer/drawer.ts +0 -122
  158. package/src/drawer/index.ts +0 -10
  159. package/src/dropdown-menu/dropdown-menu-content.ts +0 -258
  160. package/src/dropdown-menu/dropdown-menu-group.ts +0 -31
  161. package/src/dropdown-menu/dropdown-menu-item.ts +0 -51
  162. package/src/dropdown-menu/dropdown-menu-label.ts +0 -41
  163. package/src/dropdown-menu/dropdown-menu-separator.ts +0 -27
  164. package/src/dropdown-menu/dropdown-menu-trigger.ts +0 -140
  165. package/src/dropdown-menu/dropdown-menu.spec.ts +0 -265
  166. package/src/dropdown-menu/dropdown-menu.ts +0 -60
  167. package/src/dropdown-menu/index.ts +0 -15
  168. package/src/example-components.ts +0 -42
  169. package/src/field/field-error.ts +0 -49
  170. package/src/field/field-group.ts +0 -39
  171. package/src/field/field-help.ts +0 -47
  172. package/src/field/field-label.ts +0 -30
  173. package/src/field/field.context.ts +0 -28
  174. package/src/field/field.spec.ts +0 -179
  175. package/src/field/field.ts +0 -121
  176. package/src/field/index.ts +0 -6
  177. package/src/file-upload/file-upload.context.ts +0 -89
  178. package/src/file-upload/file-upload.spec.ts +0 -290
  179. package/src/file-upload/file-upload.ts +0 -639
  180. package/src/file-upload/file-upload.types.ts +0 -59
  181. package/src/file-upload/index.ts +0 -23
  182. package/src/form/form-error-summary.ts +0 -87
  183. package/src/form/form-field.context.ts +0 -3
  184. package/src/form/form-field.spec.ts +0 -25
  185. package/src/form/form-field.ts +0 -52
  186. package/src/form/form.context.ts +0 -53
  187. package/src/form/form.spec.ts +0 -162
  188. package/src/form/form.ts +0 -326
  189. package/src/form/index.ts +0 -11
  190. package/src/icon/E2E.md +0 -14
  191. package/src/icon/icon.directive.spec.ts +0 -198
  192. package/src/icon/icon.directive.ts +0 -113
  193. package/src/icon/icon.mode.spec.ts +0 -29
  194. package/src/icon/icon.mode.ts +0 -23
  195. package/src/icon/icon.providers.spec.ts +0 -63
  196. package/src/icon/icon.providers.ts +0 -47
  197. package/src/icon/icon.resolver.spec.ts +0 -96
  198. package/src/icon/icon.resolver.ts +0 -49
  199. package/src/icon/icon.tokens.ts +0 -88
  200. package/src/icon/icon.types.ts +0 -48
  201. package/src/icon/index.ts +0 -21
  202. package/src/input/index.ts +0 -1
  203. package/src/input/input.spec.ts +0 -43
  204. package/src/input/input.ts +0 -89
  205. package/src/input-group/index.ts +0 -3
  206. package/src/input-group/input-group-addon.ts +0 -92
  207. package/src/input-group/input-group.context.ts +0 -27
  208. package/src/input-group/input-group.spec.ts +0 -186
  209. package/src/input-group/input-group.ts +0 -136
  210. package/src/input-mask/index.ts +0 -11
  211. package/src/input-mask/input-mask.compile.ts +0 -69
  212. package/src/input-mask/input-mask.engine.ts +0 -376
  213. package/src/input-mask/input-mask.presets.ts +0 -24
  214. package/src/input-mask/input-mask.spec.ts +0 -304
  215. package/src/input-mask/input-mask.tokens.ts +0 -49
  216. package/src/input-mask/input-mask.ts +0 -280
  217. package/src/input-otp/index.ts +0 -2
  218. package/src/input-otp/input-otp.context.ts +0 -41
  219. package/src/input-otp/input-otp.spec.ts +0 -308
  220. package/src/input-otp/input-otp.ts +0 -470
  221. package/src/kbd/index.ts +0 -1
  222. package/src/kbd/kbd.spec.ts +0 -127
  223. package/src/kbd/kbd.ts +0 -132
  224. package/src/link/config.ts +0 -44
  225. package/src/link/index.ts +0 -2
  226. package/src/link/link.spec.ts +0 -246
  227. package/src/link/link.ts +0 -226
  228. package/src/list/index.ts +0 -11
  229. package/src/list/list.spec.ts +0 -237
  230. package/src/list/list.ts +0 -277
  231. package/src/menubar/index.ts +0 -7
  232. package/src/menubar/menubar-item.ts +0 -204
  233. package/src/menubar/menubar.context.ts +0 -43
  234. package/src/menubar/menubar.spec.ts +0 -433
  235. package/src/menubar/menubar.ts +0 -309
  236. package/src/number-input/index.ts +0 -4
  237. package/src/number-input/number-input-group.ts +0 -64
  238. package/src/number-input/number-input.context.ts +0 -31
  239. package/src/number-input/number-input.format.ts +0 -148
  240. package/src/number-input/number-input.spec.ts +0 -170
  241. package/src/number-input/number-input.ts +0 -457
  242. package/src/number-input/number-stepper.ts +0 -193
  243. package/src/overlay-badge/index.ts +0 -7
  244. package/src/overlay-badge/overlay-badge-content.ts +0 -73
  245. package/src/overlay-badge/overlay-badge.context.ts +0 -37
  246. package/src/overlay-badge/overlay-badge.spec.ts +0 -220
  247. package/src/overlay-badge/overlay-badge.ts +0 -128
  248. package/src/pagination/config.ts +0 -82
  249. package/src/pagination/index.ts +0 -19
  250. package/src/pagination/page-tokens.ts +0 -78
  251. package/src/pagination/pagination-ellipsis.ts +0 -69
  252. package/src/pagination/pagination-first.ts +0 -84
  253. package/src/pagination/pagination-info.ts +0 -70
  254. package/src/pagination/pagination-item.ts +0 -81
  255. package/src/pagination/pagination-last.ts +0 -85
  256. package/src/pagination/pagination-next.ts +0 -86
  257. package/src/pagination/pagination-previous.ts +0 -90
  258. package/src/pagination/pagination.context.ts +0 -52
  259. package/src/pagination/pagination.spec.ts +0 -388
  260. package/src/pagination/pagination.ts +0 -288
  261. package/src/password-input/index.ts +0 -15
  262. package/src/password-input/password-input.context.ts +0 -65
  263. package/src/password-input/password-input.scorer.ts +0 -34
  264. package/src/password-input/password-input.spec.ts +0 -274
  265. package/src/password-input/password-input.ts +0 -488
  266. package/src/popover/_examples/index.ts +0 -5
  267. package/src/popover/_examples/popover.example.ts +0 -92
  268. package/src/popover/_examples/popover.finance.example.ts +0 -106
  269. package/src/popover/_examples/popover.retro.example.ts +0 -103
  270. package/src/popover/index.ts +0 -5
  271. package/src/popover/popover-arrow.ts +0 -30
  272. package/src/popover/popover-close.ts +0 -36
  273. package/src/popover/popover-content.ts +0 -41
  274. package/src/popover/popover-title.ts +0 -39
  275. package/src/popover/popover-trigger.ts +0 -40
  276. package/src/popover/popover.spec.ts +0 -59
  277. package/src/popover/popover.ts +0 -5
  278. package/src/presets/bind-presets.spec.ts +0 -50
  279. package/src/presets/bind-presets.ts +0 -43
  280. package/src/presets/index.ts +0 -3
  281. package/src/presets/size.spec.ts +0 -67
  282. package/src/presets/size.ts +0 -59
  283. package/src/presets/variant.spec.ts +0 -72
  284. package/src/presets/variant.ts +0 -62
  285. package/src/primitives/.gitkeep +0 -0
  286. package/src/primitives/directionality/directionality.spec.ts +0 -112
  287. package/src/primitives/directionality/directionality.ts +0 -89
  288. package/src/primitives/directionality/index.ts +0 -1
  289. package/src/primitives/forms/form-control.spec.ts +0 -67
  290. package/src/primitives/forms/form-control.ts +0 -94
  291. package/src/primitives/forms/index.ts +0 -1
  292. package/src/primitives/index.ts +0 -6
  293. package/src/primitives/interaction/disabled.spec.ts +0 -47
  294. package/src/primitives/interaction/disabled.ts +0 -31
  295. package/src/primitives/interaction/focus-ring.spec.ts +0 -62
  296. package/src/primitives/interaction/focus-ring.ts +0 -59
  297. package/src/primitives/interaction/index.ts +0 -2
  298. package/src/primitives/list/filterable-list.spec.ts +0 -114
  299. package/src/primitives/list/filterable-list.ts +0 -126
  300. package/src/primitives/list/group.spec.ts +0 -99
  301. package/src/primitives/list/group.ts +0 -139
  302. package/src/primitives/list/index.ts +0 -8
  303. package/src/primitives/list/inject-helpers.ts +0 -8
  304. package/src/primitives/list/item.spec.ts +0 -173
  305. package/src/primitives/list/item.ts +0 -222
  306. package/src/primitives/list/navigator.spec.ts +0 -286
  307. package/src/primitives/list/navigator.ts +0 -238
  308. package/src/primitives/list/selection.spec.ts +0 -214
  309. package/src/primitives/list/selection.ts +0 -339
  310. package/src/primitives/list/tokens.ts +0 -106
  311. package/src/primitives/list/type-ahead.spec.ts +0 -58
  312. package/src/primitives/list/type-ahead.ts +0 -46
  313. package/src/primitives/overlay/backdrop.spec.ts +0 -54
  314. package/src/primitives/overlay/backdrop.ts +0 -31
  315. package/src/primitives/overlay/builder.spec.ts +0 -38
  316. package/src/primitives/overlay/builder.ts +0 -151
  317. package/src/primitives/overlay/container.ts +0 -42
  318. package/src/primitives/overlay/context.ts +0 -14
  319. package/src/primitives/overlay/controller.spec.ts +0 -86
  320. package/src/primitives/overlay/controller.ts +0 -190
  321. package/src/primitives/overlay/id.spec.ts +0 -24
  322. package/src/primitives/overlay/id.ts +0 -17
  323. package/src/primitives/overlay/index.ts +0 -18
  324. package/src/primitives/overlay/overlay.css +0 -42
  325. package/src/primitives/overlay/panel.spec.ts +0 -52
  326. package/src/primitives/overlay/panel.ts +0 -102
  327. package/src/primitives/overlay/stack.spec.ts +0 -55
  328. package/src/primitives/overlay/stack.ts +0 -113
  329. package/src/primitives/overlay/strategies/backdrop/blurred.spec.ts +0 -11
  330. package/src/primitives/overlay/strategies/backdrop/blurred.ts +0 -5
  331. package/src/primitives/overlay/strategies/backdrop/none.spec.ts +0 -10
  332. package/src/primitives/overlay/strategies/backdrop/none.ts +0 -9
  333. package/src/primitives/overlay/strategies/backdrop/solid.spec.ts +0 -18
  334. package/src/primitives/overlay/strategies/backdrop/solid.ts +0 -23
  335. package/src/primitives/overlay/strategies/focus-trap/inert-based.spec.ts +0 -28
  336. package/src/primitives/overlay/strategies/focus-trap/inert-based.ts +0 -38
  337. package/src/primitives/overlay/strategies/focus-trap/no-trap.spec.ts +0 -9
  338. package/src/primitives/overlay/strategies/focus-trap/no-trap.ts +0 -8
  339. package/src/primitives/overlay/strategies/focus-trap/tab-cycle.spec.ts +0 -49
  340. package/src/primitives/overlay/strategies/focus-trap/tab-cycle.ts +0 -85
  341. package/src/primitives/overlay/strategies/index.ts +0 -34
  342. package/src/primitives/overlay/strategies/live-announcer/_announce.ts +0 -35
  343. package/src/primitives/overlay/strategies/live-announcer/assertive.spec.ts +0 -21
  344. package/src/primitives/overlay/strategies/live-announcer/assertive.ts +0 -11
  345. package/src/primitives/overlay/strategies/live-announcer/polite.spec.ts +0 -21
  346. package/src/primitives/overlay/strategies/live-announcer/polite.ts +0 -11
  347. package/src/primitives/overlay/strategies/live-announcer/silent.spec.ts +0 -12
  348. package/src/primitives/overlay/strategies/live-announcer/silent.ts +0 -5
  349. package/src/primitives/overlay/strategies/mount/body-portal.spec.ts +0 -40
  350. package/src/primitives/overlay/strategies/mount/body-portal.ts +0 -91
  351. package/src/primitives/overlay/strategies/mount/in-container.spec.ts +0 -43
  352. package/src/primitives/overlay/strategies/mount/in-container.ts +0 -39
  353. package/src/primitives/overlay/strategies/mount/in-place.spec.ts +0 -40
  354. package/src/primitives/overlay/strategies/mount/in-place.ts +0 -20
  355. package/src/primitives/overlay/strategies/position/anchored-to.spec.ts +0 -56
  356. package/src/primitives/overlay/strategies/position/anchored-to.ts +0 -248
  357. package/src/primitives/overlay/strategies/position/corner.spec.ts +0 -36
  358. package/src/primitives/overlay/strategies/position/corner.ts +0 -33
  359. package/src/primitives/overlay/strategies/position/edge-sheet.spec.ts +0 -32
  360. package/src/primitives/overlay/strategies/position/edge-sheet.ts +0 -36
  361. package/src/primitives/overlay/strategies/position/in-place-sibling.spec.ts +0 -25
  362. package/src/primitives/overlay/strategies/position/in-place-sibling.ts +0 -13
  363. package/src/primitives/overlay/strategies/position/point-at.spec.ts +0 -40
  364. package/src/primitives/overlay/strategies/position/point-at.ts +0 -34
  365. package/src/primitives/overlay/strategies/position/viewport-centered.spec.ts +0 -31
  366. package/src/primitives/overlay/strategies/position/viewport-centered.ts +0 -31
  367. package/src/primitives/overlay/strategies/scroll-lock/css-clip.spec.ts +0 -15
  368. package/src/primitives/overlay/strategies/scroll-lock/css-clip.ts +0 -39
  369. package/src/primitives/overlay/strategies/scroll-lock/html-overflow.spec.ts +0 -21
  370. package/src/primitives/overlay/strategies/scroll-lock/html-overflow.ts +0 -44
  371. package/src/primitives/overlay/strategies/scroll-lock/none.spec.ts +0 -9
  372. package/src/primitives/overlay/strategies/scroll-lock/none.ts +0 -5
  373. package/src/primitives/overlay/strategies/trigger-event/on-click.spec.ts +0 -32
  374. package/src/primitives/overlay/strategies/trigger-event/on-click.ts +0 -28
  375. package/src/primitives/overlay/strategies/trigger-event/on-context-menu.spec.ts +0 -45
  376. package/src/primitives/overlay/strategies/trigger-event/on-context-menu.ts +0 -70
  377. package/src/primitives/overlay/strategies/trigger-event/on-focus-or-input.spec.ts +0 -35
  378. package/src/primitives/overlay/strategies/trigger-event/on-focus-or-input.ts +0 -34
  379. package/src/primitives/overlay/strategies/trigger-event/on-focus.spec.ts +0 -64
  380. package/src/primitives/overlay/strategies/trigger-event/on-focus.ts +0 -37
  381. package/src/primitives/overlay/strategies/trigger-event/on-hotkey.spec.ts +0 -37
  382. package/src/primitives/overlay/strategies/trigger-event/on-hotkey.ts +0 -59
  383. package/src/primitives/overlay/strategies/trigger-event/on-hover.spec.ts +0 -34
  384. package/src/primitives/overlay/strategies/trigger-event/on-hover.ts +0 -86
  385. package/src/primitives/overlay/strategies/trigger-event/programmatic.spec.ts +0 -16
  386. package/src/primitives/overlay/strategies/trigger-event/programmatic.ts +0 -12
  387. package/src/primitives/overlay/tokens.ts +0 -54
  388. package/src/primitives/overlay/trigger.spec.ts +0 -103
  389. package/src/primitives/overlay/trigger.ts +0 -75
  390. package/src/primitives/overlay/types.ts +0 -24
  391. package/src/primitives/overlay/wrapper.ts +0 -50
  392. package/src/primitives/signals/deep-signal.ts +0 -109
  393. package/src/primitives/signals/index.ts +0 -1
  394. package/src/progress-bar/config.ts +0 -48
  395. package/src/progress-bar/index.ts +0 -12
  396. package/src/progress-bar/progress-bar-fill.ts +0 -37
  397. package/src/progress-bar/progress-bar.context.ts +0 -34
  398. package/src/progress-bar/progress-bar.spec.ts +0 -423
  399. package/src/progress-bar/progress-bar.ts +0 -217
  400. package/src/public-api.ts +0 -84
  401. package/src/radio/index.ts +0 -2
  402. package/src/radio/radio.context.ts +0 -3
  403. package/src/radio/radio.spec.ts +0 -36
  404. package/src/radio/radio.ts +0 -66
  405. package/src/select/index.ts +0 -4
  406. package/src/select/select-content.ts +0 -69
  407. package/src/select/select-option.ts +0 -35
  408. package/src/select/select-root.ts +0 -129
  409. package/src/select/select-trigger.ts +0 -93
  410. package/src/select/select.spec.ts +0 -138
  411. package/src/select/select.ts +0 -4
  412. package/src/skeleton/index.ts +0 -5
  413. package/src/skeleton/skeleton.spec.ts +0 -115
  414. package/src/skeleton/skeleton.ts +0 -56
  415. package/src/slider/index.ts +0 -10
  416. package/src/slider/slider-range.ts +0 -49
  417. package/src/slider/slider-thumb.ts +0 -335
  418. package/src/slider/slider-track.ts +0 -70
  419. package/src/slider/slider.context.ts +0 -79
  420. package/src/slider/slider.geometry.ts +0 -73
  421. package/src/slider/slider.spec.ts +0 -216
  422. package/src/slider/slider.ts +0 -443
  423. package/src/speed-dial/index.ts +0 -10
  424. package/src/speed-dial/speed-dial-action.ts +0 -40
  425. package/src/speed-dial/speed-dial-actions.ts +0 -31
  426. package/src/speed-dial/speed-dial-trigger.ts +0 -55
  427. package/src/speed-dial/speed-dial.context.ts +0 -36
  428. package/src/speed-dial/speed-dial.spec.ts +0 -143
  429. package/src/speed-dial/speed-dial.ts +0 -127
  430. package/src/spinner/config.ts +0 -48
  431. package/src/spinner/index.ts +0 -8
  432. package/src/spinner/spinner.spec.ts +0 -262
  433. package/src/spinner/spinner.ts +0 -129
  434. package/src/stepper/index.ts +0 -15
  435. package/src/stepper/stepper.context.ts +0 -63
  436. package/src/stepper/stepper.spec.ts +0 -403
  437. package/src/stepper/stepper.ts +0 -544
  438. package/src/styles/docs-themes.css +0 -82
  439. package/src/styles.css +0 -17
  440. package/src/table/column-helpers.spec.ts +0 -74
  441. package/src/table/column-helpers.ts +0 -68
  442. package/src/table/filter-fns.ts +0 -230
  443. package/src/table/filter-models.spec.ts +0 -240
  444. package/src/table/filter-models.ts +0 -124
  445. package/src/table/filter-params.ts +0 -90
  446. package/src/table/grid-api-impl.ts +0 -321
  447. package/src/table/grid-api.spec.ts +0 -178
  448. package/src/table/grid-api.ts +0 -285
  449. package/src/table/index.ts +0 -73
  450. package/src/table/table-cell.spec.ts +0 -43
  451. package/src/table/table-cell.ts +0 -38
  452. package/src/table/table-filter-outlet.ts +0 -120
  453. package/src/table/table-header.spec.ts +0 -54
  454. package/src/table/table-header.ts +0 -63
  455. package/src/table/table-keyboard.spec.ts +0 -68
  456. package/src/table/table-keyboard.ts +0 -107
  457. package/src/table/table-resource.spec.ts +0 -37
  458. package/src/table/table-resource.ts +0 -36
  459. package/src/table/table-row.spec.ts +0 -54
  460. package/src/table/table-row.ts +0 -31
  461. package/src/table/table-storage.spec.ts +0 -67
  462. package/src/table/table-storage.ts +0 -76
  463. package/src/table/table.spec.ts +0 -172
  464. package/src/table/table.ts +0 -281
  465. package/src/table/table.types.ts +0 -83
  466. package/src/tabs/index.ts +0 -7
  467. package/src/tabs/tabs.context.ts +0 -32
  468. package/src/tabs/tabs.spec.ts +0 -352
  469. package/src/tabs/tabs.ts +0 -364
  470. package/src/tag/config.ts +0 -53
  471. package/src/tag/index.ts +0 -7
  472. package/src/tag/tag-list.ts +0 -76
  473. package/src/tag/tag-remove.ts +0 -61
  474. package/src/tag/tag.context.ts +0 -36
  475. package/src/tag/tag.spec.ts +0 -240
  476. package/src/tag/tag.ts +0 -203
  477. package/src/test-setup.ts +0 -5
  478. package/src/textarea/config.ts +0 -42
  479. package/src/textarea/index.ts +0 -8
  480. package/src/textarea/textarea.spec.ts +0 -176
  481. package/src/textarea/textarea.ts +0 -235
  482. package/src/time-picker/index.ts +0 -15
  483. package/src/time-picker/time-picker-meridiem.ts +0 -123
  484. package/src/time-picker/time-picker-segment.ts +0 -318
  485. package/src/time-picker/time-picker.context.ts +0 -38
  486. package/src/time-picker/time-picker.format.ts +0 -181
  487. package/src/time-picker/time-picker.spec.ts +0 -189
  488. package/src/time-picker/time-picker.ts +0 -274
  489. package/src/toast/_examples/index.ts +0 -5
  490. package/src/toast/_examples/toast.example.ts +0 -282
  491. package/src/toast/_examples/toast.finance.example.ts +0 -180
  492. package/src/toast/_examples/toast.retro.example.ts +0 -161
  493. package/src/toast/index.ts +0 -28
  494. package/src/toast/toast.ref.ts +0 -26
  495. package/src/toast/toast.service.ts +0 -339
  496. package/src/toast/toast.spec.ts +0 -247
  497. package/src/toast/toast.strategy.ts +0 -112
  498. package/src/toast/toast.ts +0 -463
  499. package/src/toast/toast.types.ts +0 -5
  500. package/src/toggle/index.ts +0 -1
  501. package/src/toggle/toggle.spec.ts +0 -24
  502. package/src/toggle/toggle.ts +0 -48
  503. package/src/tooltip/_examples/index.ts +0 -6
  504. package/src/tooltip/_examples/tooltip.example.ts +0 -82
  505. package/src/tooltip/_examples/tooltip.finance.example.ts +0 -97
  506. package/src/tooltip/_examples/tooltip.placements.example.ts +0 -83
  507. package/src/tooltip/_examples/tooltip.retro.example.ts +0 -107
  508. package/src/tooltip/index.ts +0 -4
  509. package/src/tooltip/tooltip-arrow.ts +0 -31
  510. package/src/tooltip/tooltip-content.ts +0 -38
  511. package/src/tooltip/tooltip-group.ts +0 -32
  512. package/src/tooltip/tooltip-trigger.ts +0 -47
  513. package/src/tooltip/tooltip.spec.ts +0 -40
  514. package/src/tooltip/tooltip.ts +0 -5
  515. package/src/tree-select/index.ts +0 -12
  516. package/src/tree-select/tree-select-content.ts +0 -199
  517. package/src/tree-select/tree-select-node.ts +0 -132
  518. package/src/tree-select/tree-select-root.ts +0 -272
  519. package/src/tree-select/tree-select-trigger.ts +0 -90
  520. package/src/tree-select/tree-select.context.ts +0 -63
  521. package/src/tree-select/tree-select.spec.ts +0 -433
  522. package/src/tree-select/tree-select.ts +0 -2
  523. package/src/typography/blockquote.ts +0 -57
  524. package/src/typography/code.ts +0 -53
  525. package/src/typography/index.ts +0 -22
  526. package/src/typography/lead.ts +0 -49
  527. package/src/typography/muted.ts +0 -29
  528. package/src/typography/truncate.ts +0 -99
  529. package/src/typography/typography.spec.ts +0 -203
  530. package/tsconfig.lib.json +0 -21
  531. package/tsconfig.lib.prod.json +0 -17
  532. package/tsconfig.spec.json +0 -18
  533. package/vite.config.ts +0 -27
  534. /package/{src/icon → icon}/icon.css +0 -0
  535. /package/{src/typography → typography}/prose.css +0 -0
@@ -1,179 +0,0 @@
1
- import { Component, signal, ChangeDetectionStrategy } from '@angular/core';
2
- import { TestBed } from '@angular/core/testing';
3
- import { describe, expect, test, beforeEach } from 'vitest';
4
- import { KjAriaDescribedBy } from '../a11y/aria-describedby';
5
- import { KjField } from './field';
6
- import { KjFieldError } from './field-error';
7
- import { KjFieldGroup } from './field-group';
8
- import { KjFieldHelp } from './field-help';
9
- import { KjFieldLabel } from './field-label';
10
-
11
- @Component({
12
- standalone: true,
13
- imports: [KjField, KjFieldLabel, KjFieldHelp, KjFieldError, KjFieldGroup, KjAriaDescribedBy],
14
- changeDetection: ChangeDetectionStrategy.Eager,
15
- template: `
16
- <div
17
- kjField
18
- #f="kjField"
19
- [kjRequired]="required()"
20
- [kjDisabled]="disabled()"
21
- [kjInvalid]="invalid()"
22
- >
23
- <!-- eslint-disable-next-line @angular-eslint/template/label-has-associated-control -->
24
- <label kjFieldLabel>Email</label>
25
- <input
26
- type="email"
27
- kjAriaDescribedBy
28
- [id]="f.controlId()"
29
- [kjDescribedBy]="f.describedByIds()"
30
- />
31
- @if (showHelp()) {
32
- <span kjFieldHelp>Format: name@example.com</span>
33
- }
34
- @if (showError()) {
35
- <span kjFieldError>Enter a valid email.</span>
36
- }
37
- </div>
38
- `,
39
- })
40
- class HostComponent {
41
- required = signal(false);
42
- disabled = signal(false);
43
- invalid = signal(false);
44
- showHelp = signal(true);
45
- showError = signal(true);
46
- }
47
-
48
- describe('KjField', () => {
49
- beforeEach(() => {
50
- TestBed.configureTestingModule({ imports: [HostComponent] });
51
- });
52
-
53
- test('mints stable ids and wires label[for] to control id', () => {
54
- const fixture = TestBed.createComponent(HostComponent);
55
- fixture.detectChanges();
56
- const label = fixture.nativeElement.querySelector('label') as HTMLLabelElement;
57
- const input = fixture.nativeElement.querySelector('input') as HTMLInputElement;
58
- expect(label.getAttribute('for')).toBe(input.id);
59
- expect(input.id).toMatch(/^kj-field-\d+$/);
60
- expect(label.id).toMatch(/^kj-field-label-\d+$/);
61
- });
62
-
63
- test('appends help id to aria-describedby when not invalid', () => {
64
- const fixture = TestBed.createComponent(HostComponent);
65
- fixture.detectChanges();
66
- const help = fixture.nativeElement.querySelector('[kjFieldHelp]') as HTMLElement;
67
- const input = fixture.nativeElement.querySelector('input') as HTMLInputElement;
68
- expect(input.getAttribute('aria-describedby')).toBe(help.id);
69
- });
70
-
71
- test('appends both help and error ids when invalid', () => {
72
- const fixture = TestBed.createComponent(HostComponent);
73
- fixture.componentInstance.invalid.set(true);
74
- fixture.detectChanges();
75
- const help = fixture.nativeElement.querySelector('[kjFieldHelp]') as HTMLElement;
76
- const error = fixture.nativeElement.querySelector('[kjFieldError]') as HTMLElement;
77
- const input = fixture.nativeElement.querySelector('input') as HTMLInputElement;
78
- const ids = input.getAttribute('aria-describedby')!.split(' ');
79
- expect(ids).toContain(help.id);
80
- expect(ids).toContain(error.id);
81
- // hints first, errors second
82
- expect(ids.indexOf(help.id)).toBeLessThan(ids.indexOf(error.id));
83
- });
84
-
85
- test('toggles data-invalid / data-required / data-disabled on the field root', () => {
86
- const fixture = TestBed.createComponent(HostComponent);
87
- fixture.componentInstance.invalid.set(true);
88
- fixture.componentInstance.required.set(true);
89
- fixture.componentInstance.disabled.set(true);
90
- fixture.detectChanges();
91
- const root = fixture.nativeElement.querySelector('[kjField]') as HTMLElement;
92
- expect(root.hasAttribute('data-invalid')).toBe(true);
93
- expect(root.hasAttribute('data-required')).toBe(true);
94
- expect(root.hasAttribute('data-disabled')).toBe(true);
95
- });
96
-
97
- test('error element is hidden when not invalid and visible when invalid', () => {
98
- const fixture = TestBed.createComponent(HostComponent);
99
- fixture.detectChanges();
100
- const error = fixture.nativeElement.querySelector('[kjFieldError]') as HTMLElement;
101
- expect(error.hasAttribute('hidden')).toBe(true);
102
- fixture.componentInstance.invalid.set(true);
103
- fixture.detectChanges();
104
- expect(error.hasAttribute('hidden')).toBe(false);
105
- });
106
-
107
- test('help element hides when invalid (error takes precedence)', () => {
108
- const fixture = TestBed.createComponent(HostComponent);
109
- fixture.detectChanges();
110
- const help = fixture.nativeElement.querySelector('[kjFieldHelp]') as HTMLElement;
111
- expect(help.hasAttribute('hidden')).toBe(false);
112
- fixture.componentInstance.invalid.set(true);
113
- fixture.detectChanges();
114
- expect(help.hasAttribute('hidden')).toBe(true);
115
- });
116
-
117
- test('error element carries role=alert and aria-live=polite', () => {
118
- const fixture = TestBed.createComponent(HostComponent);
119
- fixture.detectChanges();
120
- const error = fixture.nativeElement.querySelector('[kjFieldError]') as HTMLElement;
121
- expect(error.getAttribute('role')).toBe('alert');
122
- expect(error.getAttribute('aria-live')).toBe('polite');
123
- });
124
-
125
- test('label mirrors required / disabled / invalid via data-*', () => {
126
- const fixture = TestBed.createComponent(HostComponent);
127
- fixture.componentInstance.required.set(true);
128
- fixture.componentInstance.disabled.set(true);
129
- fixture.componentInstance.invalid.set(true);
130
- fixture.detectChanges();
131
- const label = fixture.nativeElement.querySelector('label') as HTMLLabelElement;
132
- expect(label.hasAttribute('data-required')).toBe(true);
133
- expect(label.hasAttribute('data-disabled')).toBe(true);
134
- expect(label.hasAttribute('data-invalid')).toBe(true);
135
- });
136
-
137
- test('removing a help element deregisters its id from describedby', () => {
138
- const fixture = TestBed.createComponent(HostComponent);
139
- fixture.detectChanges();
140
- const input = fixture.nativeElement.querySelector('input') as HTMLInputElement;
141
- expect(input.getAttribute('aria-describedby')).toBeTruthy();
142
- fixture.componentInstance.showHelp.set(false);
143
- fixture.detectChanges();
144
- expect(input.getAttribute('aria-describedby')).toBeNull();
145
- });
146
-
147
- test('booleanAttribute coerces string "true"/"" / present', () => {
148
- @Component({
149
- standalone: true,
150
- imports: [KjField],
151
- template: `<div kjField kjRequired kjDisabled kjInvalid #f="kjField"></div>`,
152
- })
153
- class A {}
154
- const fixture = TestBed.createComponent(A);
155
- fixture.detectChanges();
156
- const root = fixture.nativeElement.querySelector('[kjField]') as HTMLElement;
157
- expect(root.hasAttribute('data-required')).toBe(true);
158
- expect(root.hasAttribute('data-disabled')).toBe(true);
159
- expect(root.hasAttribute('data-invalid')).toBe(true);
160
- });
161
-
162
- test('field-group mirrors invalid / disabled state', () => {
163
- @Component({
164
- standalone: true,
165
- imports: [KjField, KjFieldGroup],
166
- template: `
167
- <div kjField [kjInvalid]="true" [kjDisabled]="true">
168
- <div kjFieldGroup data-test="group"></div>
169
- </div>
170
- `,
171
- })
172
- class A {}
173
- const fixture = TestBed.createComponent(A);
174
- fixture.detectChanges();
175
- const group = fixture.nativeElement.querySelector('[data-test="group"]') as HTMLElement;
176
- expect(group.hasAttribute('data-invalid')).toBe(true);
177
- expect(group.hasAttribute('data-disabled')).toBe(true);
178
- });
179
- });
@@ -1,121 +0,0 @@
1
- import {
2
- Directive,
3
- booleanAttribute,
4
- computed,
5
- input,
6
- signal,
7
- } from '@angular/core';
8
- import { KJ_FIELD, KjFieldContext } from './field.context';
9
-
10
- let kjFieldIdCounter = 0;
11
-
12
- /**
13
- * Root directive for a form field. Owns id minting, the
14
- * `aria-describedby` chain, and the required / disabled / invalid state
15
- * propagation that label, help, error, and the inner control all read.
16
- *
17
- * Project a single labelled control plus any number of `[kjFieldLabel]`,
18
- * `[kjFieldHelp]`, and `[kjFieldError]` children. The label auto-wires
19
- * `for=`; help and error ids are appended to the inner control's
20
- * `aria-describedby` via {@link KjAriaDescribedBy}; `aria-invalid` is
21
- * toggled based on `kjInvalid`.
22
- *
23
- * @example
24
- * ```html
25
- * <div kjField [kjInvalid]="ctrl.touched && ctrl.invalid" [kjRequired]="true">
26
- * <label kjFieldLabel>Email</label>
27
- * <input kjInput type="email" [formControl]="ctrl"
28
- * kjAriaDescribedBy [kjDescribedBy]="describedByIds()" />
29
- * <span kjFieldHelp>We'll never share it.</span>
30
- * <span kjFieldError>Enter a valid email.</span>
31
- * </div>
32
- * ```
33
- * @doc-category Core/Inputs
34
- * @doc
35
- * @doc-name field
36
- * @doc-description Groups a form control with its label, help, and error messages and keeps their accessibility wiring in sync.
37
- * @doc-is-main
38
- */
39
- @Directive({
40
- selector: '[kjField]',
41
- standalone: true,
42
- exportAs: 'kjField',
43
- providers: [{ provide: KJ_FIELD, useExisting: KjField }],
44
- host: {
45
- '[attr.data-orientation]': 'kjFieldOrientation()',
46
- '[attr.data-required]': 'required() ? "" : null',
47
- '[attr.data-invalid]': 'invalid() ? "" : null',
48
- '[attr.data-disabled]': 'disabled() ? "" : null',
49
- },
50
- })
51
- export class KjField implements KjFieldContext {
52
- private readonly uid = ++kjFieldIdCounter;
53
-
54
- /** Layout orientation. Reflected as `data-orientation`. */
55
- readonly kjFieldOrientation = input<'vertical' | 'horizontal'>('vertical');
56
-
57
- /** Whether the inner control is required. Drives the visual `*` and
58
- * `aria-required` on the control. */
59
- readonly kjRequired = input<boolean, unknown>(false, {
60
- transform: booleanAttribute,
61
- });
62
-
63
- /** Whether the field (and its inner control) is disabled. Forwarded to
64
- * the control via the field context. */
65
- readonly kjDisabled = input<boolean, unknown>(false, {
66
- transform: booleanAttribute,
67
- });
68
-
69
- /** Whether the inner control is currently in error state. Drives
70
- * `aria-invalid` on the control and toggles visibility of error
71
- * children. */
72
- readonly kjInvalid = input<boolean, unknown>(false, {
73
- transform: booleanAttribute,
74
- });
75
-
76
- /** Override the auto-minted id for the inner control. When unset, the
77
- * field generates a stable `kj-field-N` id. */
78
- readonly kjFieldId = input<string | undefined>(undefined);
79
-
80
- /** Override the auto-minted id for the field's label element. */
81
- readonly kjFieldLabelId = input<string | undefined>(undefined);
82
-
83
- /** @internal */ readonly controlId = computed(
84
- () => this.kjFieldId() ?? `kj-field-${this.uid}`,
85
- );
86
- /** @internal */ readonly labelId = computed(
87
- () => this.kjFieldLabelId() ?? `kj-field-label-${this.uid}`,
88
- );
89
- /** @internal */ readonly required = computed(() => this.kjRequired());
90
- /** @internal */ readonly disabled = computed(() => this.kjDisabled());
91
- /** @internal */ readonly invalid = computed(() => this.kjInvalid());
92
-
93
- // Two parallel registrations (help + error) keep the order stable: hints
94
- // first, errors second. Each registration is an ordered array of ids.
95
- private readonly helpIds = signal<readonly string[]>([]);
96
- private readonly errorIds = signal<readonly string[]>([]);
97
-
98
- /** @internal */ readonly describedByIds = computed<string[]>(() => {
99
- const help = this.helpIds();
100
- // Errors only contribute to describedby when the field is invalid —
101
- // otherwise SR would announce error text on focus when the user hasn't
102
- // yet failed validation.
103
- const errors = this.invalid() ? this.errorIds() : [];
104
- const seen = new Set<string>();
105
- const out: string[] = [];
106
- for (const id of [...help, ...errors]) {
107
- if (id && !seen.has(id)) {
108
- seen.add(id);
109
- out.push(id);
110
- }
111
- }
112
- return out;
113
- });
114
-
115
- /** @internal */
116
- registerDescribedBy(id: string, kind: 'help' | 'error'): () => void {
117
- const target = kind === 'help' ? this.helpIds : this.errorIds;
118
- target.update((ids) => (ids.includes(id) ? ids : [...ids, id]));
119
- return () => target.update((ids) => ids.filter((x) => x !== id));
120
- }
121
- }
@@ -1,6 +0,0 @@
1
- export { KjField } from './field';
2
- export { KjFieldLabel } from './field-label';
3
- export { KjFieldHelp } from './field-help';
4
- export { KjFieldError } from './field-error';
5
- export { KjFieldGroup } from './field-group';
6
- export { KJ_FIELD, type KjFieldContext } from './field.context';
@@ -1,89 +0,0 @@
1
- import { InjectionToken, Signal } from '@angular/core';
2
- import { KjFileStatus, KjUploadableFile } from './file-upload.types';
3
-
4
- /**
5
- * Aggregate status across the full file list. Drives `data-status` on the
6
- * root host so theme CSS can style the wrapper differently while uploads are
7
- * in flight.
8
- */
9
- export type KjFileUploadAggregateStatus =
10
- | 'idle'
11
- | 'pending'
12
- | 'uploading'
13
- | 'complete'
14
- | 'partial-error';
15
-
16
- /**
17
- * Public context the root `KjFileUpload` exposes via DI. Child directives
18
- * (`KjFileUploadTrigger`, `KjFileUploadDropzone`, `KjFileUploadList`,
19
- * `KjFileUploadItem`) inject this token.
20
- */
21
- export interface KjFileUploadContext {
22
- /** Files currently selected (in selection order). Removed entries are dropped. */
23
- readonly files: Signal<readonly KjUploadableFile[]>;
24
- /** Whether the root is disabled. Drop-zone, trigger, and per-row controls all gate on this. */
25
- readonly disabled: Signal<boolean>;
26
- /** True while at least one file is being dragged over the drop-zone host. */
27
- readonly dragActive: Signal<boolean>;
28
- /** Aggregate status for the whole list. */
29
- readonly aggregateStatus: Signal<KjFileUploadAggregateStatus>;
30
- /** Whether `kjMultiple` is on. */
31
- readonly multiple: Signal<boolean>;
32
- /** Configured `accept` MIME / extension list (or `undefined`). */
33
- readonly accept: Signal<string | undefined>;
34
- /** Maximum bytes per file (or `undefined` for no per-file cap). */
35
- readonly maxSize: Signal<number | undefined>;
36
- /** Maximum total file count (or `undefined`). */
37
- readonly maxFiles: Signal<number | undefined>;
38
-
39
- /** Open the native file picker. No-op when disabled. */
40
- openPicker(): void;
41
- /**
42
- * Add candidate files (from drop, programmatic add, or the trigger's file
43
- * input change event). Validates against `accept` / `maxSize` / `maxFiles`,
44
- * mints ids for survivors, appends to the list, and announces.
45
- */
46
- addFiles(files: readonly File[] | FileList): void;
47
- /** Remove a file from the list by id. Aborts an in-flight upload. */
48
- remove(id: string): void;
49
- /** Clear all files. */
50
- clear(): void;
51
- /** Re-run the upload simulation / handler for a single file. */
52
- retry(id: string): void;
53
- /** Cancel an in-flight upload (sets status to `'cancelled'`). */
54
- cancel(id: string): void;
55
- /** Update per-file progress and status (called by simulators / examples). */
56
- setFileStatus(id: string, status: KjFileStatus, progress?: number | null, error?: string): void;
57
-
58
- /** @internal Used by `KjFileUploadTrigger` to register its hidden file input. */
59
- registerPickerInput(el: HTMLInputElement): void;
60
- /** @internal Used by the trigger / drop-zone to forward `change` events. */
61
- onPickerChange(event: Event): void;
62
- /** @internal Drag-event handlers delegated from the drop-zone host bindings. */
63
- onDragEnter(event: Event): void;
64
- onDragOver(event: Event): void;
65
- onDragLeave(event: Event): void;
66
- onDrop(event: Event): void;
67
- }
68
-
69
- /** DI token for the root `KjFileUpload`. */
70
- export const KJ_FILE_UPLOAD = new InjectionToken<KjFileUploadContext>('KjFileUpload');
71
-
72
- /** Per-row context exposed by `KjFileUploadItem`. */
73
- export interface KjFileUploadItemContext {
74
- /** The current `KjUploadableFile` for the row. */
75
- readonly file: Signal<KjUploadableFile>;
76
- /** `0..100` or `null`. */
77
- readonly progress: Signal<number | null>;
78
- /** Per-row status. */
79
- readonly status: Signal<KjFileStatus>;
80
- /** Re-run the upload for this row. */
81
- retry(): void;
82
- /** Cancel an in-flight upload for this row. */
83
- cancel(): void;
84
- /** Remove this row from the list. */
85
- remove(): void;
86
- }
87
-
88
- /** DI token for an individual file row. */
89
- export const KJ_FILE_UPLOAD_ITEM = new InjectionToken<KjFileUploadItemContext>('KjFileUploadItem');
@@ -1,290 +0,0 @@
1
- import { Component, ViewChild, signal, ChangeDetectionStrategy } from '@angular/core';
2
- import { render, fireEvent } from '@testing-library/angular';
3
- import { describe, expect, it } from 'vitest';
4
- import {
5
- KjFileUpload,
6
- KjFileUploadDropzone,
7
- KjFileUploadItem,
8
- KjFileUploadList,
9
- KjFileUploadTrigger,
10
- kjFileMatchesAccept,
11
- } from './file-upload';
12
- import type { KjFileRejection } from './file-upload.types';
13
-
14
- const imports = [
15
- KjFileUpload,
16
- KjFileUploadTrigger,
17
- KjFileUploadDropzone,
18
- KjFileUploadList,
19
- KjFileUploadItem,
20
- ];
21
-
22
- function makeFile(name: string, size = 100, type = 'text/plain'): File {
23
- const blob = new Blob(['x'.repeat(size)], { type });
24
- return new File([blob], name, { type });
25
- }
26
-
27
- @Component({
28
- standalone: true,
29
- imports,
30
- changeDetection: ChangeDetectionStrategy.Eager,
31
- template: `
32
- <div
33
- kjFileUpload
34
- #u="kjFileUpload"
35
- [kjAccept]="accept()"
36
- [kjMultiple]="multiple()"
37
- [kjMaxSize]="maxSize()"
38
- [kjMaxFiles]="maxFiles()"
39
- [kjDisabled]="disabled()"
40
- >
41
- <button kjFileUploadTrigger>Choose</button>
42
- <div kjFileUploadDropzone>Drop files here</div>
43
- <ul kjFileUploadList>
44
- @for (f of u.files(); track f.id) {
45
- <li kjFileUploadItem [kjFile]="f" #row="kjFileUploadItem">
46
- <span class="row-name">{{ f.file.name }}</span>
47
- <span class="row-status">{{ row.status() }}</span>
48
- <button class="row-remove" (click)="row.remove()">Remove</button>
49
- </li>
50
- }
51
- </ul>
52
- </div>
53
- `,
54
- })
55
- class Host {
56
- readonly accept = signal<string | undefined>(undefined);
57
- readonly multiple = signal<boolean>(true);
58
- readonly maxSize = signal<number | undefined>(undefined);
59
- readonly maxFiles = signal<number | undefined>(undefined);
60
- readonly disabled = signal<boolean>(false);
61
- @ViewChild(KjFileUpload, { static: true }) upload!: KjFileUpload;
62
- }
63
-
64
- describe('KjFileUpload', () => {
65
- describe('selection + validation', () => {
66
- it('mints ids and exposes files via context', async () => {
67
- const { container, fixture } = await render(Host);
68
- const root = container.querySelector('[kjFileUpload]')!;
69
- fixture.componentInstance.upload.addFiles([makeFile('a.txt')]);
70
- fixture.detectChanges();
71
- expect(container.querySelectorAll('[kjFileUploadItem]').length).toBe(1);
72
- expect(container.querySelector('.row-name')?.textContent).toBe('a.txt');
73
- expect(root.getAttribute('data-status')).toBe('pending');
74
- });
75
-
76
- it('rejects files over kjMaxSize', async () => {
77
- const { container, fixture } = await render(Host);
78
- fixture.componentInstance.maxSize.set(50);
79
- fixture.detectChanges();
80
- const small = makeFile('s.txt', 10);
81
- const big = makeFile('b.txt', 200);
82
- fixture.componentInstance.upload.addFiles([small, big]);
83
- fixture.detectChanges();
84
- const rows = container.querySelectorAll('[kjFileUploadItem]');
85
- expect(rows.length).toBe(1);
86
- expect(container.querySelector('.row-name')?.textContent).toBe('s.txt');
87
- });
88
-
89
- it('rejects files outside kjAccept', async () => {
90
- const { container, fixture } = await render(Host);
91
- fixture.componentInstance.accept.set('image/*');
92
- fixture.detectChanges();
93
- const png = makeFile('p.png', 10, 'image/png');
94
- const txt = makeFile('t.txt', 10, 'text/plain');
95
- fixture.componentInstance.upload.addFiles([png, txt]);
96
- fixture.detectChanges();
97
- const rows = container.querySelectorAll('[kjFileUploadItem]');
98
- expect(rows.length).toBe(1);
99
- expect(container.querySelector('.row-name')?.textContent).toBe('p.png');
100
- });
101
-
102
- it('caps at kjMaxFiles when adding in multiple mode', async () => {
103
- const { container, fixture } = await render(Host);
104
- fixture.componentInstance.maxFiles.set(2);
105
- fixture.detectChanges();
106
- fixture.componentInstance.upload.addFiles([makeFile('a'), makeFile('b'), makeFile('c')]);
107
- fixture.detectChanges();
108
- expect(container.querySelectorAll('[kjFileUploadItem]').length).toBe(2);
109
- });
110
-
111
- it('replaces existing file in single mode', async () => {
112
- const { container, fixture } = await render(Host);
113
- fixture.componentInstance.multiple.set(false);
114
- fixture.detectChanges();
115
- fixture.componentInstance.upload.addFiles([makeFile('a.txt')]);
116
- fixture.detectChanges();
117
- fixture.componentInstance.upload.addFiles([makeFile('b.txt')]);
118
- fixture.detectChanges();
119
- const rows = container.querySelectorAll('[kjFileUploadItem]');
120
- expect(rows.length).toBe(1);
121
- expect(container.querySelector('.row-name')?.textContent).toBe('b.txt');
122
- });
123
-
124
- it('emits kjReject for size violations', async () => {
125
- const { fixture } = await render(Host);
126
- fixture.componentInstance.maxSize.set(50);
127
- fixture.detectChanges();
128
- let rejected: KjFileRejection[] | null = null;
129
- fixture.componentInstance.upload.kjReject.subscribe((r) => (rejected = r));
130
- fixture.componentInstance.upload.addFiles([makeFile('big', 200)]);
131
- expect(rejected).toBeTruthy();
132
- expect(rejected[0].reason).toBe('size');
133
- });
134
- });
135
-
136
- describe('drop-zone', () => {
137
- it('reflects data-drag-active on dragenter and clears on dragleave', async () => {
138
- const { container, fixture } = await render(Host);
139
- const dz = container.querySelector('[kjFileUploadDropzone]') as HTMLElement;
140
- expect(dz.hasAttribute('data-drag-active')).toBe(false);
141
-
142
- const ev = new Event('dragenter', { bubbles: true, cancelable: true }) as DragEvent;
143
- Object.defineProperty(ev, 'dataTransfer', {
144
- value: { types: ['Files'], files: [] as unknown as FileList },
145
- });
146
- dz.dispatchEvent(ev);
147
- fixture.detectChanges();
148
- expect(dz.hasAttribute('data-drag-active')).toBe(true);
149
-
150
- const leave = new Event('dragleave', { bubbles: true, cancelable: true }) as DragEvent;
151
- Object.defineProperty(leave, 'dataTransfer', {
152
- value: { types: ['Files'], files: [] as unknown as FileList },
153
- });
154
- dz.dispatchEvent(leave);
155
- fixture.detectChanges();
156
- expect(dz.hasAttribute('data-drag-active')).toBe(false);
157
- });
158
-
159
- it('drop adds files', async () => {
160
- const { container, fixture } = await render(Host);
161
- const dz = container.querySelector('[kjFileUploadDropzone]') as HTMLElement;
162
- const file = makeFile('drop.txt');
163
- const ev = new Event('drop', { bubbles: true, cancelable: true }) as DragEvent;
164
- Object.defineProperty(ev, 'dataTransfer', {
165
- value: { types: ['Files'], files: [file] as unknown as FileList },
166
- });
167
- dz.dispatchEvent(ev);
168
- fixture.detectChanges();
169
- expect(container.querySelectorAll('[kjFileUploadItem]').length).toBe(1);
170
- });
171
-
172
- it('Enter / Space on drop-zone opens picker', async () => {
173
- const { container } = await render(Host);
174
- const dz = container.querySelector('[kjFileUploadDropzone]') as HTMLElement;
175
- const hidden = container.querySelector('input[type=file]') as HTMLInputElement;
176
- let clicked = 0;
177
- hidden.addEventListener('click', (e) => {
178
- e.preventDefault();
179
- clicked++;
180
- });
181
- fireEvent.keyDown(dz, { key: 'Enter' });
182
- fireEvent.keyDown(dz, { key: ' ' });
183
- expect(clicked).toBe(2);
184
- });
185
-
186
- it('drop-zone has role=button, tabindex=0, and aria-label', async () => {
187
- const { container } = await render(Host);
188
- const dz = container.querySelector('[kjFileUploadDropzone]') as HTMLElement;
189
- expect(dz.getAttribute('role')).toBe('button');
190
- expect(dz.getAttribute('aria-label')).toBe('Drag files here, or click to browse');
191
- expect(dz.getAttribute('tabindex')).toBe('0');
192
- });
193
- });
194
-
195
- describe('disabled', () => {
196
- it('disabled prevents addFiles and reflects aria-disabled on drop-zone', async () => {
197
- const { container, fixture } = await render(Host);
198
- fixture.componentInstance.disabled.set(true);
199
- fixture.detectChanges();
200
- const dz = container.querySelector('[kjFileUploadDropzone]') as HTMLElement;
201
- expect(dz.getAttribute('aria-disabled')).toBe('true');
202
- fixture.componentInstance.upload.addFiles([makeFile('x.txt')]);
203
- fixture.detectChanges();
204
- expect(container.querySelectorAll('[kjFileUploadItem]').length).toBe(0);
205
- });
206
- });
207
-
208
- describe('per-row controls', () => {
209
- it('remove button removes the row', async () => {
210
- const { container, fixture } = await render(Host);
211
- fixture.componentInstance.upload.addFiles([makeFile('a'), makeFile('b')]);
212
- fixture.detectChanges();
213
- expect(container.querySelectorAll('[kjFileUploadItem]').length).toBe(2);
214
- const removeBtn = container.querySelector('.row-remove') as HTMLElement;
215
- fireEvent.click(removeBtn);
216
- fixture.detectChanges();
217
- expect(container.querySelectorAll('[kjFileUploadItem]').length).toBe(1);
218
- });
219
-
220
- it('retry resets a row to pending', async () => {
221
- const { fixture } = await render(Host);
222
- fixture.componentInstance.upload.addFiles([makeFile('a')]);
223
- const id = fixture.componentInstance.upload.files()[0].id;
224
- fixture.componentInstance.upload.setFileStatus(id, 'error', null, 'boom');
225
- expect(fixture.componentInstance.upload.files()[0].status).toBe('error');
226
- fixture.componentInstance.upload.retry(id);
227
- expect(fixture.componentInstance.upload.files()[0].status).toBe('pending');
228
- });
229
- });
230
-
231
- describe('aggregateStatus', () => {
232
- it('idle when empty, pending after add, uploading then complete after status updates', async () => {
233
- const { container, fixture } = await render(Host);
234
- const root = container.querySelector('[kjFileUpload]') as HTMLElement;
235
- expect(root.getAttribute('data-status')).toBe('idle');
236
- fixture.componentInstance.upload.addFiles([makeFile('a')]);
237
- fixture.detectChanges();
238
- expect(root.getAttribute('data-status')).toBe('pending');
239
- const id = fixture.componentInstance.upload.files()[0].id;
240
- fixture.componentInstance.upload.setFileStatus(id, 'uploading', 50);
241
- fixture.detectChanges();
242
- expect(root.getAttribute('data-status')).toBe('uploading');
243
- fixture.componentInstance.upload.setFileStatus(id, 'done', 100);
244
- fixture.detectChanges();
245
- expect(root.getAttribute('data-status')).toBe('complete');
246
- });
247
- });
248
-
249
- describe('list semantics', () => {
250
- it('list has role=list and items have role=listitem with data-status', async () => {
251
- const { container, fixture } = await render(Host);
252
- const list = container.querySelector('[kjFileUploadList]') as HTMLElement;
253
- expect(list.getAttribute('role')).toBe('list');
254
- fixture.componentInstance.upload.addFiles([makeFile('a')]);
255
- fixture.detectChanges();
256
- const item = container.querySelector('[kjFileUploadItem]') as HTMLElement;
257
- expect(item.getAttribute('role')).toBe('listitem');
258
- expect(item.getAttribute('data-status')).toBe('pending');
259
- });
260
- });
261
- });
262
-
263
- describe('kjFileMatchesAccept', () => {
264
- const f = (name: string, type = '') => new File([new Blob([])], name, { type });
265
-
266
- it('returns true when accept is empty / undefined', () => {
267
- expect(kjFileMatchesAccept(f('a.txt'), undefined)).toBe(true);
268
- expect(kjFileMatchesAccept(f('a.txt'), '')).toBe(true);
269
- });
270
-
271
- it('matches by exact MIME type', () => {
272
- expect(kjFileMatchesAccept(f('a.png', 'image/png'), 'image/png')).toBe(true);
273
- expect(kjFileMatchesAccept(f('a.png', 'image/png'), 'image/jpeg')).toBe(false);
274
- });
275
-
276
- it('matches by MIME prefix (image/*)', () => {
277
- expect(kjFileMatchesAccept(f('a.png', 'image/png'), 'image/*')).toBe(true);
278
- expect(kjFileMatchesAccept(f('a.txt', 'text/plain'), 'image/*')).toBe(false);
279
- });
280
-
281
- it('falls back to extension matching when file.type is empty', () => {
282
- expect(kjFileMatchesAccept(f('a.heic', ''), '.heic')).toBe(true);
283
- expect(kjFileMatchesAccept(f('a.heic', ''), 'image/*')).toBe(false);
284
- });
285
-
286
- it('matches comma-separated lists', () => {
287
- expect(kjFileMatchesAccept(f('a.pdf', 'application/pdf'), 'image/*,.pdf')).toBe(true);
288
- expect(kjFileMatchesAccept(f('a.png', 'image/png'), 'image/*,.pdf')).toBe(true);
289
- });
290
- });