@kouji-ui/components 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 (730) hide show
  1. package/.turbo/turbo-build.log +29 -0
  2. package/CHANGELOG.md +192 -0
  3. package/ng-package.json +7 -0
  4. package/package.json +43 -0
  5. package/src/accordion/_examples/accordion.default.example.ts +31 -0
  6. package/src/accordion/_examples/accordion.disabled.example.ts +38 -0
  7. package/src/accordion/_examples/accordion.multiple.example.ts +31 -0
  8. package/src/accordion/_examples/accordion.rich-content.example.ts +49 -0
  9. package/src/accordion/_examples/index.ts +6 -0
  10. package/src/accordion/accordion.arrow-nav.example.ts +39 -0
  11. package/src/accordion/accordion.css +68 -0
  12. package/src/accordion/accordion.playground.ts +119 -0
  13. package/src/accordion/accordion.spec.ts +117 -0
  14. package/src/accordion/accordion.ts +153 -0
  15. package/src/accordion/accordion.usage.example.ts +38 -0
  16. package/src/accordion/accordion.value.example.ts +60 -0
  17. package/src/accordion/index.ts +1 -0
  18. package/src/alert/_examples/alert.banner.example.ts +56 -0
  19. package/src/alert/_examples/alert.dismissible.example.ts +53 -0
  20. package/src/alert/_examples/alert.example.ts +40 -0
  21. package/src/alert/_examples/alert.variants.example.ts +66 -0
  22. package/src/alert/_examples/alert.with-actions.example.ts +57 -0
  23. package/src/alert/_examples/index.ts +7 -0
  24. package/src/alert/alert.css +133 -0
  25. package/src/alert/alert.playground.ts +111 -0
  26. package/src/alert/alert.spec.ts +167 -0
  27. package/src/alert/alert.ts +250 -0
  28. package/src/alert/alert.usage.example.ts +58 -0
  29. package/src/alert/index.ts +8 -0
  30. package/src/avatar/_examples/avatar-group.example.ts +31 -0
  31. package/src/avatar/_examples/avatar-group.list.example.ts +45 -0
  32. package/src/avatar/_examples/avatar-group.overflow.example.ts +33 -0
  33. package/src/avatar/_examples/avatar-group.shapes.example.ts +39 -0
  34. package/src/avatar/_examples/avatar-group.sizes.example.ts +44 -0
  35. package/src/avatar/_examples/avatar.default.example.ts +18 -0
  36. package/src/avatar/_examples/avatar.initials.example.ts +20 -0
  37. package/src/avatar/_examples/avatar.shapes.example.ts +22 -0
  38. package/src/avatar/_examples/avatar.sizes.example.ts +26 -0
  39. package/src/avatar/_examples/avatar.with-image.example.ts +20 -0
  40. package/src/avatar/_examples/index.ts +12 -0
  41. package/src/avatar/avatar-group.spec.ts +138 -0
  42. package/src/avatar/avatar-group.ts +127 -0
  43. package/src/avatar/avatar-group.usage.example.ts +30 -0
  44. package/src/avatar/avatar.css +58 -0
  45. package/src/avatar/avatar.playground.ts +95 -0
  46. package/src/avatar/avatar.ts +123 -0
  47. package/src/avatar/index.ts +2 -0
  48. package/src/badge/_examples/badge.default.example.ts +18 -0
  49. package/src/badge/_examples/badge.sizes.example.ts +25 -0
  50. package/src/badge/_examples/badge.variants.example.ts +24 -0
  51. package/src/badge/_examples/badge.with-dot.example.ts +31 -0
  52. package/src/badge/_examples/badge.with-icon.example.ts +23 -0
  53. package/src/badge/_examples/index.ts +7 -0
  54. package/src/badge/badge.css +59 -0
  55. package/src/badge/badge.playground.ts +49 -0
  56. package/src/badge/badge.ts +86 -0
  57. package/src/badge/badge.usage.example.ts +22 -0
  58. package/src/badge/index.ts +1 -0
  59. package/src/breadcrumb/_examples/breadcrumb.custom-separator.example.ts +53 -0
  60. package/src/breadcrumb/_examples/breadcrumb.example.ts +48 -0
  61. package/src/breadcrumb/_examples/breadcrumb.long-path.example.ts +58 -0
  62. package/src/breadcrumb/_examples/breadcrumb.truncated.example.ts +59 -0
  63. package/src/breadcrumb/_examples/breadcrumb.with-icons.example.ts +66 -0
  64. package/src/breadcrumb/_examples/index.ts +7 -0
  65. package/src/breadcrumb/breadcrumb.css +121 -0
  66. package/src/breadcrumb/breadcrumb.playground.ts +93 -0
  67. package/src/breadcrumb/breadcrumb.spec.ts +230 -0
  68. package/src/breadcrumb/breadcrumb.ts +272 -0
  69. package/src/breadcrumb/breadcrumb.usage.example.ts +45 -0
  70. package/src/breadcrumb/index.ts +1 -0
  71. package/src/button/_examples/button.anchor.example.ts +18 -0
  72. package/src/button/_examples/button.configured.example.ts +43 -0
  73. package/src/button/_examples/button.disabled.example.ts +25 -0
  74. package/src/button/_examples/button.example.ts +22 -0
  75. package/src/button/_examples/button.icon.example.ts +27 -0
  76. package/src/button/_examples/button.loading.example.ts +31 -0
  77. package/src/button/_examples/button.pressed.example.ts +24 -0
  78. package/src/button/_examples/button.sizes.example.ts +26 -0
  79. package/src/button/_examples/button.usage.example.ts +66 -0
  80. package/src/button/_examples/button.variants.example.ts +26 -0
  81. package/src/button/_examples/index.ts +12 -0
  82. package/src/button/button.css +263 -0
  83. package/src/button/button.playground.ts +79 -0
  84. package/src/button/button.spec.ts +100 -0
  85. package/src/button/button.ts +150 -0
  86. package/src/button/index.ts +1 -0
  87. package/src/button-group/_examples/button-group.example.ts +30 -0
  88. package/src/button-group/_examples/button-group.icon-only.example.ts +30 -0
  89. package/src/button-group/_examples/button-group.toggle.example.ts +36 -0
  90. package/src/button-group/_examples/button-group.variants.example.ts +40 -0
  91. package/src/button-group/_examples/button-group.vertical.example.ts +29 -0
  92. package/src/button-group/_examples/index.ts +7 -0
  93. package/src/button-group/button-group.css +80 -0
  94. package/src/button-group/button-group.playground.ts +94 -0
  95. package/src/button-group/button-group.spec.ts +119 -0
  96. package/src/button-group/button-group.ts +130 -0
  97. package/src/button-group/button-group.usage.example.ts +35 -0
  98. package/src/button-group/index.ts +1 -0
  99. package/src/calendar/_examples/calendar.example.ts +33 -0
  100. package/src/calendar/_examples/index.ts +3 -0
  101. package/src/calendar/calendar.css +129 -0
  102. package/src/calendar/calendar.playground.ts +84 -0
  103. package/src/calendar/calendar.spec.ts +50 -0
  104. package/src/calendar/calendar.ts +171 -0
  105. package/src/calendar/calendar.usage.example.ts +33 -0
  106. package/src/calendar/index.ts +1 -0
  107. package/src/card/_examples/card.cover.example.ts +53 -0
  108. package/src/card/_examples/card.example.ts +27 -0
  109. package/src/card/_examples/card.full.example.ts +51 -0
  110. package/src/card/_examples/index.ts +5 -0
  111. package/src/card/card.css +120 -0
  112. package/src/card/card.playground.ts +116 -0
  113. package/src/card/card.spec.ts +50 -0
  114. package/src/card/card.ts +194 -0
  115. package/src/card/card.usage.example.ts +46 -0
  116. package/src/card/index.ts +1 -0
  117. package/src/carousel/_examples/carousel.autoplay.example.ts +69 -0
  118. package/src/carousel/_examples/carousel.example.ts +60 -0
  119. package/src/carousel/_examples/carousel.indicators.example.ts +64 -0
  120. package/src/carousel/_examples/carousel.lazy-load.example.ts +85 -0
  121. package/src/carousel/_examples/carousel.tabs-pattern.example.ts +61 -0
  122. package/src/carousel/_examples/index.ts +7 -0
  123. package/src/carousel/carousel.css +181 -0
  124. package/src/carousel/carousel.playground.ts +135 -0
  125. package/src/carousel/carousel.spec.ts +211 -0
  126. package/src/carousel/carousel.ts +399 -0
  127. package/src/carousel/carousel.usage.example.ts +46 -0
  128. package/src/carousel/index.ts +1 -0
  129. package/src/cascade-select/_examples/cascade-select.data-driven.example.ts +119 -0
  130. package/src/cascade-select/_examples/cascade-select.disabled.example.ts +74 -0
  131. package/src/cascade-select/_examples/cascade-select.example.ts +80 -0
  132. package/src/cascade-select/_examples/cascade-select.field.example.ts +73 -0
  133. package/src/cascade-select/_examples/cascade-select.path.example.ts +85 -0
  134. package/src/cascade-select/_examples/index.ts +7 -0
  135. package/src/cascade-select/cascade-select.css +120 -0
  136. package/src/cascade-select/cascade-select.playground.ts +133 -0
  137. package/src/cascade-select/cascade-select.ts +201 -0
  138. package/src/cascade-select/cascade-select.usage.example.ts +44 -0
  139. package/src/cascade-select/index.ts +5 -0
  140. package/src/chat/_examples/chat-bubble.example.ts +71 -0
  141. package/src/chat/_examples/chat-bubble.grouped.example.ts +69 -0
  142. package/src/chat/_examples/chat-bubble.sides.example.ts +41 -0
  143. package/src/chat/_examples/chat-bubble.variants.example.ts +58 -0
  144. package/src/chat/_examples/chat-bubble.with-state.example.ts +57 -0
  145. package/src/chat/_examples/index.ts +7 -0
  146. package/src/chat/chat.css +231 -0
  147. package/src/chat/chat.playground.ts +171 -0
  148. package/src/chat/chat.spec.ts +343 -0
  149. package/src/chat/chat.ts +269 -0
  150. package/src/chat/chat.usage.example.ts +49 -0
  151. package/src/chat/index.ts +13 -0
  152. package/src/checkbox/_examples/checkbox.checked.example.ts +20 -0
  153. package/src/checkbox/_examples/checkbox.default.example.ts +20 -0
  154. package/src/checkbox/_examples/checkbox.disabled.example.ts +26 -0
  155. package/src/checkbox/_examples/checkbox.indeterminate.example.ts +20 -0
  156. package/src/checkbox/_examples/checkbox.usage.example.ts +62 -0
  157. package/src/checkbox/_examples/index.ts +7 -0
  158. package/src/checkbox/checkbox.css +74 -0
  159. package/src/checkbox/checkbox.playground.ts +68 -0
  160. package/src/checkbox/checkbox.ts +122 -0
  161. package/src/checkbox/index.ts +1 -0
  162. package/src/color-picker/_examples/color-picker.alpha.example.ts +36 -0
  163. package/src/color-picker/_examples/color-picker.example.ts +34 -0
  164. package/src/color-picker/_examples/color-picker.hex-input.example.ts +53 -0
  165. package/src/color-picker/_examples/color-picker.in-form.example.ts +60 -0
  166. package/src/color-picker/_examples/color-picker.usage.example.ts +58 -0
  167. package/src/color-picker/_examples/color-picker.with-presets.example.ts +45 -0
  168. package/src/color-picker/_examples/index.ts +8 -0
  169. package/src/color-picker/color-picker.css +183 -0
  170. package/src/color-picker/color-picker.playground.ts +83 -0
  171. package/src/color-picker/color-picker.spec.ts +94 -0
  172. package/src/color-picker/color-picker.ts +234 -0
  173. package/src/color-picker/index.ts +1 -0
  174. package/src/combobox/_examples/combobox.async.example.ts +85 -0
  175. package/src/combobox/_examples/combobox.empty-state.example.ts +36 -0
  176. package/src/combobox/_examples/combobox.example.ts +36 -0
  177. package/src/combobox/_examples/combobox.free-text.example.ts +42 -0
  178. package/src/combobox/_examples/combobox.usage.example.ts +51 -0
  179. package/src/combobox/_examples/combobox.with-icons.example.ts +49 -0
  180. package/src/combobox/_examples/index.ts +8 -0
  181. package/src/combobox/combobox.css +101 -0
  182. package/src/combobox/combobox.playground.ts +90 -0
  183. package/src/combobox/combobox.spec.ts +111 -0
  184. package/src/combobox/combobox.ts +219 -0
  185. package/src/combobox/index.ts +6 -0
  186. package/src/command-palette/_examples/command-palette.async.example.ts +99 -0
  187. package/src/command-palette/_examples/command-palette.dialog.example.ts +90 -0
  188. package/src/command-palette/_examples/command-palette.example.ts +40 -0
  189. package/src/command-palette/_examples/command-palette.fuzzy.example.ts +54 -0
  190. package/src/command-palette/_examples/command-palette.groups.example.ts +55 -0
  191. package/src/command-palette/_examples/command-palette.usage.example.ts +49 -0
  192. package/src/command-palette/_examples/index.ts +8 -0
  193. package/src/command-palette/command-palette.css +234 -0
  194. package/src/command-palette/command-palette.playground.ts +119 -0
  195. package/src/command-palette/command-palette.ts +448 -0
  196. package/src/command-palette/index.ts +10 -0
  197. package/src/confirm-popup/_examples/confirm-popup.destructive.example.ts +72 -0
  198. package/src/confirm-popup/_examples/confirm-popup.example.ts +82 -0
  199. package/src/confirm-popup/_examples/confirm-popup.placement.example.ts +97 -0
  200. package/src/confirm-popup/_examples/confirm-popup.usage.example.ts +94 -0
  201. package/src/confirm-popup/_examples/confirm-popup.with-message.example.ts +76 -0
  202. package/src/confirm-popup/_examples/index.ts +7 -0
  203. package/src/confirm-popup/confirm-popup.css +47 -0
  204. package/src/confirm-popup/confirm-popup.playground.ts +109 -0
  205. package/src/confirm-popup/confirm-popup.spec.ts +209 -0
  206. package/src/confirm-popup/confirm-popup.ts +279 -0
  207. package/src/confirm-popup/index.ts +1 -0
  208. package/src/date-picker/_examples/date-picker.disabled-dates.example.ts +44 -0
  209. package/src/date-picker/_examples/date-picker.example.ts +38 -0
  210. package/src/date-picker/_examples/date-picker.locale.example.ts +50 -0
  211. package/src/date-picker/_examples/date-picker.readonly.example.ts +32 -0
  212. package/src/date-picker/_examples/date-picker.usage.example.ts +60 -0
  213. package/src/date-picker/_examples/date-picker.with-min-max.example.ts +47 -0
  214. package/src/date-picker/_examples/index.ts +8 -0
  215. package/src/date-picker/date-picker.css +61 -0
  216. package/src/date-picker/date-picker.playground.ts +79 -0
  217. package/src/date-picker/date-picker.spec.ts +71 -0
  218. package/src/date-picker/date-picker.ts +185 -0
  219. package/src/date-picker/index.ts +1 -0
  220. package/src/dialog/_examples/dialog.confirmation.example.ts +30 -0
  221. package/src/dialog/_examples/dialog.default.example.ts +30 -0
  222. package/src/dialog/_examples/dialog.nested.example.ts +86 -0
  223. package/src/dialog/_examples/dialog.scrollable.example.ts +30 -0
  224. package/src/dialog/_examples/dialog.usage.example.ts +57 -0
  225. package/src/dialog/_examples/dialog.with-form.example.ts +48 -0
  226. package/src/dialog/_examples/index.ts +8 -0
  227. package/src/dialog/dialog.css +56 -0
  228. package/src/dialog/dialog.playground.ts +136 -0
  229. package/src/dialog/dialog.ts +82 -0
  230. package/src/dialog/index.ts +1 -0
  231. package/src/divider/_examples/divider.example.ts +27 -0
  232. package/src/divider/_examples/divider.sizes.example.ts +33 -0
  233. package/src/divider/_examples/divider.structural.example.ts +55 -0
  234. package/src/divider/_examples/divider.usage.example.ts +48 -0
  235. package/src/divider/_examples/divider.variants.example.ts +33 -0
  236. package/src/divider/_examples/divider.vertical.example.ts +38 -0
  237. package/src/divider/_examples/divider.with-content.example.ts +38 -0
  238. package/src/divider/_examples/index.ts +9 -0
  239. package/src/divider/divider.css +93 -0
  240. package/src/divider/divider.playground.ts +97 -0
  241. package/src/divider/divider.spec.ts +207 -0
  242. package/src/divider/divider.ts +220 -0
  243. package/src/divider/index.ts +1 -0
  244. package/src/drawer/_examples/drawer.example.ts +30 -0
  245. package/src/drawer/_examples/drawer.modal-vs-non-modal.example.ts +27 -0
  246. package/src/drawer/_examples/drawer.scrollable.example.ts +30 -0
  247. package/src/drawer/_examples/drawer.sides.example.ts +32 -0
  248. package/src/drawer/_examples/drawer.usage.example.ts +56 -0
  249. package/src/drawer/_examples/drawer.with-form.example.ts +48 -0
  250. package/src/drawer/_examples/index.ts +8 -0
  251. package/src/drawer/drawer.css +130 -0
  252. package/src/drawer/drawer.playground.ts +107 -0
  253. package/src/drawer/drawer.spec.ts +216 -0
  254. package/src/drawer/drawer.ts +85 -0
  255. package/src/drawer/index.ts +1 -0
  256. package/src/dropdown-menu/_examples/dropdown-menu.disabled.example.ts +19 -0
  257. package/src/dropdown-menu/_examples/dropdown-menu.example.ts +20 -0
  258. package/src/dropdown-menu/_examples/dropdown-menu.shortcuts.example.ts +31 -0
  259. package/src/dropdown-menu/_examples/dropdown-menu.sides.example.ts +18 -0
  260. package/src/dropdown-menu/_examples/dropdown-menu.usage.example.ts +56 -0
  261. package/src/dropdown-menu/_examples/dropdown-menu.with-icons.example.ts +31 -0
  262. package/src/dropdown-menu/_examples/dropdown-menu.with-separator.example.ts +41 -0
  263. package/src/dropdown-menu/_examples/index.ts +9 -0
  264. package/src/dropdown-menu/dropdown-menu.css +108 -0
  265. package/src/dropdown-menu/dropdown-menu.playground.ts +109 -0
  266. package/src/dropdown-menu/dropdown-menu.spec.ts +5 -0
  267. package/src/dropdown-menu/dropdown-menu.ts +128 -0
  268. package/src/dropdown-menu/index.ts +1 -0
  269. package/src/empty-state/_examples/empty-state.error.example.ts +63 -0
  270. package/src/empty-state/_examples/empty-state.example.ts +59 -0
  271. package/src/empty-state/_examples/empty-state.search.example.ts +82 -0
  272. package/src/empty-state/_examples/empty-state.sizes.example.ts +76 -0
  273. package/src/empty-state/_examples/empty-state.usage.example.ts +66 -0
  274. package/src/empty-state/_examples/empty-state.with-actions.example.ts +68 -0
  275. package/src/empty-state/_examples/index.ts +8 -0
  276. package/src/empty-state/empty-state.css +114 -0
  277. package/src/empty-state/empty-state.playground.ts +87 -0
  278. package/src/empty-state/empty-state.spec.ts +211 -0
  279. package/src/empty-state/empty-state.ts +276 -0
  280. package/src/empty-state/index.ts +1 -0
  281. package/src/example-components.ts +396 -0
  282. package/src/field/_examples/field.disabled.example.ts +49 -0
  283. package/src/field/_examples/field.example.ts +51 -0
  284. package/src/field/_examples/field.required.example.ts +46 -0
  285. package/src/field/_examples/field.with-error.example.ts +73 -0
  286. package/src/field/_examples/field.with-prefix-suffix.example.ts +63 -0
  287. package/src/field/_examples/index.ts +7 -0
  288. package/src/field/field.css +138 -0
  289. package/src/field/field.playground.ts +108 -0
  290. package/src/field/field.spec.ts +132 -0
  291. package/src/field/field.ts +232 -0
  292. package/src/field/field.usage.example.ts +63 -0
  293. package/src/field/index.ts +7 -0
  294. package/src/file-upload/_examples/file-upload.dropzone.example.ts +32 -0
  295. package/src/file-upload/_examples/file-upload.example.ts +29 -0
  296. package/src/file-upload/_examples/file-upload.image-preview.example.ts +31 -0
  297. package/src/file-upload/_examples/file-upload.multiple.example.ts +23 -0
  298. package/src/file-upload/_examples/file-upload.with-progress.example.ts +59 -0
  299. package/src/file-upload/_examples/index.ts +7 -0
  300. package/src/file-upload/file-upload.css +207 -0
  301. package/src/file-upload/file-upload.playground.ts +84 -0
  302. package/src/file-upload/file-upload.spec.ts +94 -0
  303. package/src/file-upload/file-upload.ts +301 -0
  304. package/src/file-upload/file-upload.usage.example.ts +45 -0
  305. package/src/file-upload/index.ts +1 -0
  306. package/src/form/_examples/form.async-submit.example.ts +72 -0
  307. package/src/form/_examples/form.compound.example.ts +93 -0
  308. package/src/form/_examples/form.example.ts +70 -0
  309. package/src/form/_examples/form.validation.example.ts +67 -0
  310. package/src/form/_examples/index.ts +6 -0
  311. package/src/form/form.css +63 -0
  312. package/src/form/form.playground.ts +145 -0
  313. package/src/form/form.spec.ts +96 -0
  314. package/src/form/form.ts +216 -0
  315. package/src/form/form.usage.example.ts +63 -0
  316. package/src/form/index.ts +5 -0
  317. package/src/icon/_examples/icon.gallery.example.ts +199 -0
  318. package/src/icon/_examples/icon.usage.example.ts +46 -0
  319. package/src/icon/_examples/index.ts +4 -0
  320. package/src/icon/icon.playground.ts +63 -0
  321. package/src/icon/index.ts +5 -0
  322. package/src/icon/lucide/icon-names.generated.ts +1708 -0
  323. package/src/icon/lucide/icon-names.ts +18 -0
  324. package/src/icon/lucide/index.ts +2 -0
  325. package/src/icon/lucide/provide-lucide-icons.ts +96 -0
  326. package/src/input/_examples/index.ts +4 -0
  327. package/src/input/_examples/input.color.example.ts +33 -0
  328. package/src/input/_examples/input.example.ts +22 -0
  329. package/src/input/index.ts +1 -0
  330. package/src/input/input.css +70 -0
  331. package/src/input/input.playground.ts +79 -0
  332. package/src/input/input.spec.ts +98 -0
  333. package/src/input/input.ts +158 -0
  334. package/src/input/input.usage.example.ts +40 -0
  335. package/src/input-group/_examples/index.ts +7 -0
  336. package/src/input-group/_examples/input-group.button.example.ts +43 -0
  337. package/src/input-group/_examples/input-group.example.ts +39 -0
  338. package/src/input-group/_examples/input-group.icon.example.ts +49 -0
  339. package/src/input-group/_examples/input-group.url.example.ts +36 -0
  340. package/src/input-group/_examples/input-group.variants.example.ts +39 -0
  341. package/src/input-group/index.ts +1 -0
  342. package/src/input-group/input-group.css +125 -0
  343. package/src/input-group/input-group.playground.ts +90 -0
  344. package/src/input-group/input-group.ts +142 -0
  345. package/src/input-group/input-group.usage.example.ts +47 -0
  346. package/src/input-mask/_examples/index.ts +8 -0
  347. package/src/input-mask/_examples/input-mask.credit-card.example.ts +90 -0
  348. package/src/input-mask/_examples/input-mask.custom-tokens.example.ts +87 -0
  349. package/src/input-mask/_examples/input-mask.date.example.ts +61 -0
  350. package/src/input-mask/_examples/input-mask.example.ts +61 -0
  351. package/src/input-mask/_examples/input-mask.usage.example.ts +44 -0
  352. package/src/input-mask/_examples/input-mask.validation.example.ts +80 -0
  353. package/src/input-mask/index.ts +9 -0
  354. package/src/input-mask/input-mask.css +39 -0
  355. package/src/input-mask/input-mask.playground.ts +79 -0
  356. package/src/input-mask/input-mask.ts +130 -0
  357. package/src/input-otp/_examples/index.ts +8 -0
  358. package/src/input-otp/_examples/input-otp.autosubmit.example.ts +71 -0
  359. package/src/input-otp/_examples/input-otp.example.ts +47 -0
  360. package/src/input-otp/_examples/input-otp.lengths.example.ts +67 -0
  361. package/src/input-otp/_examples/input-otp.masked.example.ts +46 -0
  362. package/src/input-otp/_examples/input-otp.reactive.example.ts +58 -0
  363. package/src/input-otp/_examples/input-otp.separator.example.ts +49 -0
  364. package/src/input-otp/index.ts +1 -0
  365. package/src/input-otp/input-otp.css +87 -0
  366. package/src/input-otp/input-otp.playground.ts +107 -0
  367. package/src/input-otp/input-otp.ts +244 -0
  368. package/src/input-otp/input-otp.usage.example.ts +45 -0
  369. package/src/kbd/_examples/index.ts +6 -0
  370. package/src/kbd/_examples/kbd.combo.example.ts +24 -0
  371. package/src/kbd/_examples/kbd.example.ts +22 -0
  372. package/src/kbd/_examples/kbd.in-tooltip.example.ts +43 -0
  373. package/src/kbd/_examples/kbd.sizes.example.ts +31 -0
  374. package/src/kbd/index.ts +1 -0
  375. package/src/kbd/kbd.css +67 -0
  376. package/src/kbd/kbd.playground.ts +51 -0
  377. package/src/kbd/kbd.spec.ts +123 -0
  378. package/src/kbd/kbd.ts +123 -0
  379. package/src/kbd/kbd.usage.example.ts +38 -0
  380. package/src/link/_examples/index.ts +8 -0
  381. package/src/link/_examples/link.disabled.example.ts +23 -0
  382. package/src/link/_examples/link.example.ts +26 -0
  383. package/src/link/_examples/link.external.example.ts +33 -0
  384. package/src/link/_examples/link.in-prose.example.ts +36 -0
  385. package/src/link/_examples/link.sizes.example.ts +28 -0
  386. package/src/link/_examples/link.variants.example.ts +25 -0
  387. package/src/link/index.ts +1 -0
  388. package/src/link/link.css +104 -0
  389. package/src/link/link.playground.ts +98 -0
  390. package/src/link/link.spec.ts +146 -0
  391. package/src/link/link.ts +133 -0
  392. package/src/link/link.usage.example.ts +37 -0
  393. package/src/list/_examples/index.ts +7 -0
  394. package/src/list/_examples/list.divided.example.ts +32 -0
  395. package/src/list/_examples/list.example.ts +31 -0
  396. package/src/list/_examples/list.interactive.example.ts +51 -0
  397. package/src/list/_examples/list.nav.example.ts +44 -0
  398. package/src/list/_examples/list.with-icons.example.ts +97 -0
  399. package/src/list/index.ts +1 -0
  400. package/src/list/list.css +166 -0
  401. package/src/list/list.playground.ts +90 -0
  402. package/src/list/list.spec.ts +121 -0
  403. package/src/list/list.ts +227 -0
  404. package/src/list/list.usage.example.ts +45 -0
  405. package/src/menubar/_examples/index.ts +6 -0
  406. package/src/menubar/_examples/menubar.disabled-item.example.ts +23 -0
  407. package/src/menubar/_examples/menubar.example.ts +22 -0
  408. package/src/menubar/_examples/menubar.with-shortcuts.example.ts +33 -0
  409. package/src/menubar/_examples/menubar.with-submenu.example.ts +76 -0
  410. package/src/menubar/index.ts +1 -0
  411. package/src/menubar/menubar.css +62 -0
  412. package/src/menubar/menubar.playground.ts +96 -0
  413. package/src/menubar/menubar.ts +160 -0
  414. package/src/menubar/menubar.usage.example.ts +33 -0
  415. package/src/number-input/_examples/index.ts +7 -0
  416. package/src/number-input/_examples/number-input.currency.example.ts +35 -0
  417. package/src/number-input/_examples/number-input.decimal.example.ts +34 -0
  418. package/src/number-input/_examples/number-input.example.ts +24 -0
  419. package/src/number-input/_examples/number-input.min-max.example.ts +33 -0
  420. package/src/number-input/_examples/number-input.with-stepper.example.ts +45 -0
  421. package/src/number-input/index.ts +1 -0
  422. package/src/number-input/number-input.css +115 -0
  423. package/src/number-input/number-input.playground.ts +92 -0
  424. package/src/number-input/number-input.spec.ts +102 -0
  425. package/src/number-input/number-input.ts +212 -0
  426. package/src/number-input/number-input.usage.example.ts +73 -0
  427. package/src/overlay/overlay.css +32 -0
  428. package/src/overlay-badge/_examples/index.ts +7 -0
  429. package/src/overlay-badge/_examples/overlay-badge.described.example.ts +36 -0
  430. package/src/overlay-badge/_examples/overlay-badge.dot.example.ts +28 -0
  431. package/src/overlay-badge/_examples/overlay-badge.example.ts +34 -0
  432. package/src/overlay-badge/_examples/overlay-badge.on-avatar.example.ts +38 -0
  433. package/src/overlay-badge/_examples/overlay-badge.positions.example.ts +39 -0
  434. package/src/overlay-badge/index.ts +1 -0
  435. package/src/overlay-badge/overlay-badge.css +118 -0
  436. package/src/overlay-badge/overlay-badge.playground.ts +92 -0
  437. package/src/overlay-badge/overlay-badge.spec.ts +174 -0
  438. package/src/overlay-badge/overlay-badge.ts +232 -0
  439. package/src/overlay-badge/overlay-badge.usage.example.ts +44 -0
  440. package/src/pagination/_examples/index.ts +7 -0
  441. package/src/pagination/_examples/pagination.boundaries.example.ts +56 -0
  442. package/src/pagination/_examples/pagination.compact.example.ts +42 -0
  443. package/src/pagination/_examples/pagination.example.ts +55 -0
  444. package/src/pagination/_examples/pagination.large.example.ts +54 -0
  445. package/src/pagination/_examples/pagination.with-info.example.ts +49 -0
  446. package/src/pagination/index.ts +1 -0
  447. package/src/pagination/pagination.css +146 -0
  448. package/src/pagination/pagination.playground.ts +107 -0
  449. package/src/pagination/pagination.spec.ts +202 -0
  450. package/src/pagination/pagination.ts +432 -0
  451. package/src/pagination/pagination.usage.example.ts +50 -0
  452. package/src/password-input/_examples/index.ts +6 -0
  453. package/src/password-input/_examples/password-input.example.ts +24 -0
  454. package/src/password-input/_examples/password-input.strength.example.ts +45 -0
  455. package/src/password-input/_examples/password-input.toggle.example.ts +43 -0
  456. package/src/password-input/_examples/password-input.with-rules.example.ts +78 -0
  457. package/src/password-input/index.ts +1 -0
  458. package/src/password-input/password-input.css +155 -0
  459. package/src/password-input/password-input.playground.ts +81 -0
  460. package/src/password-input/password-input.spec.ts +129 -0
  461. package/src/password-input/password-input.ts +254 -0
  462. package/src/password-input/password-input.usage.example.ts +55 -0
  463. package/src/playground-types.ts +47 -0
  464. package/src/popover/_examples/index.ts +7 -0
  465. package/src/popover/_examples/popover.cancellable.example.ts +20 -0
  466. package/src/popover/_examples/popover.example.ts +20 -0
  467. package/src/popover/_examples/popover.modal.example.ts +22 -0
  468. package/src/popover/_examples/popover.sides.example.ts +37 -0
  469. package/src/popover/_examples/popover.with-form.example.ts +38 -0
  470. package/src/popover/index.ts +1 -0
  471. package/src/popover/popover.css +71 -0
  472. package/src/popover/popover.playground.ts +86 -0
  473. package/src/popover/popover.spec.ts +5 -0
  474. package/src/popover/popover.ts +94 -0
  475. package/src/popover/popover.usage.example.ts +48 -0
  476. package/src/progress-bar/_examples/index.ts +7 -0
  477. package/src/progress-bar/_examples/progress-bar.example.ts +22 -0
  478. package/src/progress-bar/_examples/progress-bar.indeterminate.example.ts +23 -0
  479. package/src/progress-bar/_examples/progress-bar.sizes.example.ts +29 -0
  480. package/src/progress-bar/_examples/progress-bar.variants.example.ts +30 -0
  481. package/src/progress-bar/_examples/progress-bar.with-label.example.ts +30 -0
  482. package/src/progress-bar/index.ts +1 -0
  483. package/src/progress-bar/progress-bar.css +113 -0
  484. package/src/progress-bar/progress-bar.playground.ts +87 -0
  485. package/src/progress-bar/progress-bar.spec.ts +233 -0
  486. package/src/progress-bar/progress-bar.ts +155 -0
  487. package/src/progress-bar/progress-bar.usage.example.ts +52 -0
  488. package/src/public-api.ts +61 -0
  489. package/src/radio/_examples/index.ts +6 -0
  490. package/src/radio/_examples/radio.default.example.ts +26 -0
  491. package/src/radio/_examples/radio.disabled.example.ts +26 -0
  492. package/src/radio/_examples/radio.group.example.ts +27 -0
  493. package/src/radio/_examples/radio.inline.example.ts +26 -0
  494. package/src/radio/index.ts +1 -0
  495. package/src/radio/radio.css +58 -0
  496. package/src/radio/radio.playground.ts +90 -0
  497. package/src/radio/radio.ts +143 -0
  498. package/src/radio/radio.usage.example.ts +54 -0
  499. package/src/select/_examples/index.ts +6 -0
  500. package/src/select/_examples/select.default.example.ts +26 -0
  501. package/src/select/_examples/select.disabled.example.ts +24 -0
  502. package/src/select/_examples/select.grouped.example.ts +37 -0
  503. package/src/select/_examples/select.placeholder.example.ts +26 -0
  504. package/src/select/index.ts +1 -0
  505. package/src/select/select.css +65 -0
  506. package/src/select/select.playground.ts +81 -0
  507. package/src/select/select.ts +176 -0
  508. package/src/select/select.usage.example.ts +64 -0
  509. package/src/skeleton/_examples/index.ts +6 -0
  510. package/src/skeleton/_examples/skeleton.animations.example.ts +52 -0
  511. package/src/skeleton/_examples/skeleton.card.example.ts +68 -0
  512. package/src/skeleton/_examples/skeleton.example.ts +24 -0
  513. package/src/skeleton/_examples/skeleton.shapes.example.ts +55 -0
  514. package/src/skeleton/index.ts +1 -0
  515. package/src/skeleton/skeleton.css +111 -0
  516. package/src/skeleton/skeleton.playground.ts +80 -0
  517. package/src/skeleton/skeleton.spec.ts +126 -0
  518. package/src/skeleton/skeleton.ts +155 -0
  519. package/src/skeleton/skeleton.usage.example.ts +49 -0
  520. package/src/slider/_examples/index.ts +7 -0
  521. package/src/slider/_examples/slider.example.ts +41 -0
  522. package/src/slider/_examples/slider.formatted.example.ts +53 -0
  523. package/src/slider/_examples/slider.range.example.ts +48 -0
  524. package/src/slider/_examples/slider.vertical.example.ts +48 -0
  525. package/src/slider/_examples/slider.with-marks.example.ts +46 -0
  526. package/src/slider/index.ts +1 -0
  527. package/src/slider/slider.css +172 -0
  528. package/src/slider/slider.playground.ts +88 -0
  529. package/src/slider/slider.spec.ts +139 -0
  530. package/src/slider/slider.ts +246 -0
  531. package/src/slider/slider.usage.example.ts +68 -0
  532. package/src/speed-dial/_examples/index.ts +7 -0
  533. package/src/speed-dial/_examples/speed-dial.directions.example.ts +85 -0
  534. package/src/speed-dial/_examples/speed-dial.disabled.example.ts +71 -0
  535. package/src/speed-dial/_examples/speed-dial.example.ts +48 -0
  536. package/src/speed-dial/_examples/speed-dial.usage.example.ts +59 -0
  537. package/src/speed-dial/_examples/speed-dial.with-tooltips.example.ts +65 -0
  538. package/src/speed-dial/index.ts +1 -0
  539. package/src/speed-dial/speed-dial.css +137 -0
  540. package/src/speed-dial/speed-dial.playground.ts +137 -0
  541. package/src/speed-dial/speed-dial.spec.ts +191 -0
  542. package/src/speed-dial/speed-dial.ts +257 -0
  543. package/src/spinner/_examples/index.ts +8 -0
  544. package/src/spinner/_examples/spinner.animations.example.ts +54 -0
  545. package/src/spinner/_examples/spinner.example.ts +26 -0
  546. package/src/spinner/_examples/spinner.in-button.example.ts +51 -0
  547. package/src/spinner/_examples/spinner.sizes.example.ts +31 -0
  548. package/src/spinner/_examples/spinner.usage.example.ts +45 -0
  549. package/src/spinner/_examples/spinner.variants.example.ts +34 -0
  550. package/src/spinner/index.ts +1 -0
  551. package/src/spinner/spinner.css +161 -0
  552. package/src/spinner/spinner.playground.ts +68 -0
  553. package/src/spinner/spinner.spec.ts +184 -0
  554. package/src/spinner/spinner.ts +185 -0
  555. package/src/stepper/_examples/index.ts +8 -0
  556. package/src/stepper/_examples/stepper.example.ts +62 -0
  557. package/src/stepper/_examples/stepper.non-linear.example.ts +63 -0
  558. package/src/stepper/_examples/stepper.optional-step.example.ts +62 -0
  559. package/src/stepper/_examples/stepper.usage.example.ts +73 -0
  560. package/src/stepper/_examples/stepper.vertical.example.ts +66 -0
  561. package/src/stepper/_examples/stepper.with-error.example.ts +63 -0
  562. package/src/stepper/index.ts +1 -0
  563. package/src/stepper/stepper.css +147 -0
  564. package/src/stepper/stepper.playground.ts +88 -0
  565. package/src/stepper/stepper.spec.ts +200 -0
  566. package/src/stepper/stepper.ts +242 -0
  567. package/src/table/_examples/index.ts +23 -0
  568. package/src/table/_examples/table.column-pinning.example.ts +55 -0
  569. package/src/table/_examples/table.column-resize.example.ts +49 -0
  570. package/src/table/_examples/table.column-visibility.example.ts +52 -0
  571. package/src/table/_examples/table.density.example.ts +71 -0
  572. package/src/table/_examples/table.editable.example.ts +85 -0
  573. package/src/table/_examples/table.empty-and-error.example.ts +112 -0
  574. package/src/table/_examples/table.example.ts +45 -0
  575. package/src/table/_examples/table.export.example.ts +82 -0
  576. package/src/table/_examples/table.filterable.example.ts +67 -0
  577. package/src/table/_examples/table.grouping.example.ts +63 -0
  578. package/src/table/_examples/table.keyboard.example.ts +115 -0
  579. package/src/table/_examples/table.master-detail.example.ts +102 -0
  580. package/src/table/_examples/table.persistence.example.ts +85 -0
  581. package/src/table/_examples/table.playground.ts +154 -0
  582. package/src/table/_examples/table.row-pinning.example.ts +71 -0
  583. package/src/table/_examples/table.selection.example.ts +67 -0
  584. package/src/table/_examples/table.server-mode.example.ts +120 -0
  585. package/src/table/_examples/table.sortable.example.ts +49 -0
  586. package/src/table/_examples/table.theming.example.ts +64 -0
  587. package/src/table/_examples/table.usage.example.ts +90 -0
  588. package/src/table/_examples/table.virtualized.example.ts +122 -0
  589. package/src/table/index.ts +11 -0
  590. package/src/table/table-cell-editor-outlet.ts +111 -0
  591. package/src/table/table-editors/boolean-editor.ts +71 -0
  592. package/src/table/table-editors/date-editor.ts +117 -0
  593. package/src/table/table-editors/editors.spec.ts +147 -0
  594. package/src/table/table-editors/index.ts +41 -0
  595. package/src/table/table-editors/number-editor.ts +89 -0
  596. package/src/table/table-editors/select-editor.ts +107 -0
  597. package/src/table/table-editors/text-editor.ts +82 -0
  598. package/src/table/table-export.spec.ts +33 -0
  599. package/src/table/table-export.ts +53 -0
  600. package/src/table/table-filter-outlet.ts +137 -0
  601. package/src/table/table-filters/date-filter.ts +122 -0
  602. package/src/table/table-filters/filters.css +53 -0
  603. package/src/table/table-filters/filters.spec.ts +277 -0
  604. package/src/table/table-filters/index.ts +11 -0
  605. package/src/table/table-filters/number-filter.ts +232 -0
  606. package/src/table/table-filters/select-filter.ts +129 -0
  607. package/src/table/table-filters/text-filter.ts +110 -0
  608. package/src/table/table-pagination.spec.ts +118 -0
  609. package/src/table/table-pagination.ts +191 -0
  610. package/src/table/table-side-panel.spec.ts +170 -0
  611. package/src/table/table-side-panel.ts +263 -0
  612. package/src/table/table-status-bar.spec.ts +78 -0
  613. package/src/table/table-status-bar.ts +70 -0
  614. package/src/table/table-toolbar.spec.ts +180 -0
  615. package/src/table/table-toolbar.ts +244 -0
  616. package/src/table/table-virtual.spec.ts +103 -0
  617. package/src/table/table-virtual.ts +180 -0
  618. package/src/table/table.css +468 -0
  619. package/src/table/table.spec.ts +175 -0
  620. package/src/table/table.ts +1009 -0
  621. package/src/tabs/_examples/index.ts +8 -0
  622. package/src/tabs/_examples/tabs.controlled.example.ts +59 -0
  623. package/src/tabs/_examples/tabs.disabled.example.ts +34 -0
  624. package/src/tabs/_examples/tabs.example.ts +34 -0
  625. package/src/tabs/_examples/tabs.manual-activation.example.ts +34 -0
  626. package/src/tabs/_examples/tabs.usage.example.ts +43 -0
  627. package/src/tabs/_examples/tabs.vertical.example.ts +33 -0
  628. package/src/tabs/index.ts +1 -0
  629. package/src/tabs/tabs.css +80 -0
  630. package/src/tabs/tabs.playground.ts +88 -0
  631. package/src/tabs/tabs.spec.ts +135 -0
  632. package/src/tabs/tabs.ts +204 -0
  633. package/src/tag/_examples/index.ts +9 -0
  634. package/src/tag/_examples/tag.example.ts +22 -0
  635. package/src/tag/_examples/tag.list.example.ts +38 -0
  636. package/src/tag/_examples/tag.removable.example.ts +39 -0
  637. package/src/tag/_examples/tag.selectable.example.ts +33 -0
  638. package/src/tag/_examples/tag.sizes.example.ts +25 -0
  639. package/src/tag/_examples/tag.usage.example.ts +62 -0
  640. package/src/tag/_examples/tag.variants.example.ts +29 -0
  641. package/src/tag/index.ts +1 -0
  642. package/src/tag/tag.css +167 -0
  643. package/src/tag/tag.playground.ts +63 -0
  644. package/src/tag/tag.spec.ts +153 -0
  645. package/src/tag/tag.ts +186 -0
  646. package/src/test-setup.ts +5 -0
  647. package/src/textarea/_examples/index.ts +8 -0
  648. package/src/textarea/_examples/textarea.autoresize.example.ts +37 -0
  649. package/src/textarea/_examples/textarea.character-count.example.ts +34 -0
  650. package/src/textarea/_examples/textarea.example.ts +22 -0
  651. package/src/textarea/_examples/textarea.no-resize.example.ts +28 -0
  652. package/src/textarea/_examples/textarea.usage.example.ts +50 -0
  653. package/src/textarea/_examples/textarea.with-field.example.ts +66 -0
  654. package/src/textarea/index.ts +1 -0
  655. package/src/textarea/textarea.css +117 -0
  656. package/src/textarea/textarea.playground.ts +70 -0
  657. package/src/textarea/textarea.spec.ts +161 -0
  658. package/src/textarea/textarea.ts +339 -0
  659. package/src/time-picker/_examples/index.ts +8 -0
  660. package/src/time-picker/_examples/time-picker.12-hour.example.ts +24 -0
  661. package/src/time-picker/_examples/time-picker.example.ts +24 -0
  662. package/src/time-picker/_examples/time-picker.formatted.example.ts +32 -0
  663. package/src/time-picker/_examples/time-picker.range.example.ts +54 -0
  664. package/src/time-picker/_examples/time-picker.usage.example.ts +53 -0
  665. package/src/time-picker/_examples/time-picker.with-seconds.example.ts +24 -0
  666. package/src/time-picker/index.ts +1 -0
  667. package/src/time-picker/time-picker.css +126 -0
  668. package/src/time-picker/time-picker.playground.ts +72 -0
  669. package/src/time-picker/time-picker.spec.ts +77 -0
  670. package/src/time-picker/time-picker.ts +207 -0
  671. package/src/toast/_examples/index.ts +7 -0
  672. package/src/toast/_examples/toast.default.example.ts +37 -0
  673. package/src/toast/_examples/toast.dismissible.example.ts +38 -0
  674. package/src/toast/_examples/toast.usage.example.ts +57 -0
  675. package/src/toast/_examples/toast.variants.example.ts +43 -0
  676. package/src/toast/_examples/toast.with-action.example.ts +46 -0
  677. package/src/toast/index.ts +1 -0
  678. package/src/toast/toast.css +115 -0
  679. package/src/toast/toast.playground.ts +61 -0
  680. package/src/toast/toast.ts +168 -0
  681. package/src/toggle/_examples/index.ts +7 -0
  682. package/src/toggle/_examples/toggle.checked.example.ts +20 -0
  683. package/src/toggle/_examples/toggle.default.example.ts +20 -0
  684. package/src/toggle/_examples/toggle.disabled.example.ts +26 -0
  685. package/src/toggle/_examples/toggle.usage.example.ts +51 -0
  686. package/src/toggle/_examples/toggle.with-label.example.ts +30 -0
  687. package/src/toggle/index.ts +1 -0
  688. package/src/toggle/toggle.css +123 -0
  689. package/src/toggle/toggle.playground.ts +65 -0
  690. package/src/toggle/toggle.ts +113 -0
  691. package/src/tooltip/_examples/index.ts +9 -0
  692. package/src/tooltip/_examples/tooltip.delays.example.ts +16 -0
  693. package/src/tooltip/_examples/tooltip.disabled.example.ts +16 -0
  694. package/src/tooltip/_examples/tooltip.example.ts +16 -0
  695. package/src/tooltip/_examples/tooltip.group.example.ts +20 -0
  696. package/src/tooltip/_examples/tooltip.rich.example.ts +19 -0
  697. package/src/tooltip/_examples/tooltip.sides.example.ts +18 -0
  698. package/src/tooltip/_examples/tooltip.usage.example.ts +50 -0
  699. package/src/tooltip/index.ts +1 -0
  700. package/src/tooltip/tooltip.css +61 -0
  701. package/src/tooltip/tooltip.playground.ts +79 -0
  702. package/src/tooltip/tooltip.spec.ts +5 -0
  703. package/src/tooltip/tooltip.ts +102 -0
  704. package/src/tree-select/_examples/index.ts +8 -0
  705. package/src/tree-select/_examples/tree-select.disabled.example.ts +106 -0
  706. package/src/tree-select/_examples/tree-select.example.ts +65 -0
  707. package/src/tree-select/_examples/tree-select.expanded.example.ts +72 -0
  708. package/src/tree-select/_examples/tree-select.field.example.ts +77 -0
  709. package/src/tree-select/_examples/tree-select.multi.example.ts +73 -0
  710. package/src/tree-select/_examples/tree-select.usage.example.ts +85 -0
  711. package/src/tree-select/index.ts +1 -0
  712. package/src/tree-select/tree-select.css +220 -0
  713. package/src/tree-select/tree-select.playground.ts +83 -0
  714. package/src/tree-select/tree-select.ts +348 -0
  715. package/src/typography/_examples/index.ts +9 -0
  716. package/src/typography/_examples/typography.blockquote.example.ts +34 -0
  717. package/src/typography/_examples/typography.code.example.ts +32 -0
  718. package/src/typography/_examples/typography.example.ts +42 -0
  719. package/src/typography/_examples/typography.lead.example.ts +37 -0
  720. package/src/typography/_examples/typography.muted.example.ts +27 -0
  721. package/src/typography/_examples/typography.truncate.example.ts +41 -0
  722. package/src/typography/_examples/typography.usage.example.ts +44 -0
  723. package/src/typography/index.ts +8 -0
  724. package/src/typography/typography.playground.ts +101 -0
  725. package/src/typography/typography.spec.ts +70 -0
  726. package/src/typography/typography.ts +105 -0
  727. package/tsconfig.lib.json +25 -0
  728. package/tsconfig.lib.prod.json +17 -0
  729. package/tsconfig.spec.json +16 -0
  730. package/vite.config.ts +33 -0
@@ -0,0 +1,468 @@
1
+ /* Density + variant tokens. All spacing via --kj-base-space-*.
2
+ *
3
+ * Sizing contract: the table is container-driven. If a parent gives `<kj-table>`
4
+ * a fixed height (`height: 400px`, a flex/grid track, etc.) the body fills
5
+ * the remaining space inside the wrapper and the row-scroll happens INSIDE
6
+ * `.kj-table-body`. If no parent constraint is set, the table grows to its
7
+ * natural content height — no internal scroll. `min-height: 0` / `min-width: 0`
8
+ * are the magic flex pieces that let the body actually shrink past content
9
+ * to honour an outer constraint. The same applies for width: the wrapper
10
+ * fills the host's width and the body scrolls horizontally when columns
11
+ * overflow.
12
+ */
13
+ :host {
14
+ display: flex;
15
+ flex-direction: column;
16
+ min-height: 0;
17
+ min-width: 0;
18
+ font-family: var(--kj-font-sans);
19
+ font-size: var(--kj-text-sm);
20
+ /* Default row height — predictable + virtualization-friendly. Density
21
+ variants below override; consumers can also write the var directly
22
+ (`<kj-table style="--kj-table-row-height: 2.75rem">…</kj-table>`). */
23
+ --kj-table-row-height: 2.25rem;
24
+ }
25
+ :host([data-density="compact"]) { --kj-table-row-height: 1.75rem; }
26
+ :host([data-density="comfortable"]) { --kj-table-row-height: 2.75rem; }
27
+
28
+ .kj-table-wrapper {
29
+ display: flex;
30
+ flex-direction: column;
31
+ flex: 1 1 auto;
32
+ min-height: 0;
33
+ min-width: 0;
34
+ position: relative;
35
+ }
36
+
37
+ .kj-table-body {
38
+ position: relative;
39
+ overflow: auto;
40
+ /* Use block layout (not flex) for the body so the `<table>` keeps its
41
+ natural row-height behaviour. With flex, a child `<table>` stretched
42
+ to fill the body — that made a single row balloon to fill the entire
43
+ viewport when filters narrowed the result set. Block layout lets the
44
+ table size to its content; the body's `overflow: auto` still scrolls
45
+ when there are many rows, and the leftover space appears below the
46
+ last row when there are few. */
47
+ display: block;
48
+ flex: 1 1 auto;
49
+ min-height: 0;
50
+ min-width: 0;
51
+ }
52
+
53
+ .kj-table-body > table {
54
+ /* Table never flex-grows; row heights stay content-driven (or row-height
55
+ CSS var-driven if the consumer sets `--kj-table-row-height`). */
56
+ min-width: 100%;
57
+ }
58
+
59
+ :host th,
60
+ :host td {
61
+ height: var(--kj-table-row-height);
62
+ }
63
+
64
+ :host table {
65
+ width: 100%;
66
+ border-collapse: collapse;
67
+ background: var(--kj-bg-surface);
68
+ color: var(--kj-fg-default);
69
+ }
70
+
71
+ :host th,
72
+ :host td {
73
+ text-align: left;
74
+ padding: var(--kj-base-space-sm) var(--kj-base-space-md);
75
+ border-bottom: 1px solid var(--kj-border-default);
76
+ position: relative;
77
+ }
78
+
79
+ :host th {
80
+ font-weight: 600;
81
+ background: var(--kj-bg-elevated);
82
+ }
83
+
84
+ /* ── Sort indicator ─────────────────────────────────────────────
85
+ The wrapper template renders a `<i kjIcon>` after the header label
86
+ when the column is sortable. CSS here just owns layout + tint:
87
+ - default → muted (unsorted/sortable)
88
+ - data-sort=… → brand primary
89
+ The icon sits inline so it survives the resize handle on the right
90
+ edge of the cell. */
91
+ :host th[aria-sort] {
92
+ user-select: none;
93
+ }
94
+ .kj-table-sort-indicator {
95
+ display: inline-flex;
96
+ align-items: center;
97
+ margin-inline-start: var(--kj-base-space-xs, 0.25rem);
98
+ color: var(--kj-fg-subtle, var(--kj-fg-muted));
99
+ transition: color var(--kj-transition);
100
+ vertical-align: middle;
101
+ }
102
+ :host th[data-sort="asc"] .kj-table-sort-indicator,
103
+ :host th[data-sort="desc"] .kj-table-sort-indicator {
104
+ color: var(--kj-fg-primary);
105
+ }
106
+ :host th[aria-sort]:hover .kj-table-sort-indicator,
107
+ :host th[aria-sort]:focus-visible .kj-table-sort-indicator {
108
+ color: var(--kj-fg-default);
109
+ }
110
+
111
+ :host([data-density="compact"]) th,
112
+ :host([data-density="compact"]) td {
113
+ padding: var(--kj-base-space-xs) var(--kj-base-space-sm);
114
+ }
115
+
116
+ :host([data-density="comfortable"]) th,
117
+ :host([data-density="comfortable"]) td {
118
+ padding: var(--kj-base-space-md) var(--kj-base-space-lg);
119
+ }
120
+
121
+ :host([data-variant="striped"]) tbody tr:nth-child(even) td {
122
+ background: var(--kj-bg-elevated);
123
+ }
124
+
125
+ :host([data-variant="clean"]) th,
126
+ :host([data-variant="clean"]) td {
127
+ border-bottom-color: transparent;
128
+ }
129
+
130
+ :host td:focus-visible,
131
+ :host th:focus-visible {
132
+ outline: 2px solid var(--kj-border-focus);
133
+ outline-offset: -2px;
134
+ }
135
+
136
+ /* Inline cell editors must NOT push the column wider than its existing
137
+ content. A bare `<input>` (and the styled select trigger) has an
138
+ intrinsic min-content width — ~20 chars from `size` for inputs, the
139
+ selected label for triggers — that table auto-layout uses to size the
140
+ column.
141
+
142
+ Trick: render an invisible "ghost" of the cell's value so the cell
143
+ keeps its natural content width, then lift every editor host out of
144
+ the in-flow stacking context with `position: absolute`. Editors use
145
+ `display: contents` by default — we override that while editing so
146
+ they actually get a box that can be positioned. */
147
+ :host td.kj-table-cell--editing {
148
+ position: relative;
149
+ }
150
+ :host td .kj-table-cell-ghost {
151
+ visibility: hidden;
152
+ white-space: pre;
153
+ display: inline-block;
154
+ pointer-events: none;
155
+ }
156
+ /* `::ng-deep` is required because the editor components are created
157
+ dynamically via `ViewContainerRef.createComponent` from inside the
158
+ `kjCellEditorOutlet` directive. Dynamic elements don't inherit the
159
+ parent template's emulated-encapsulation attributes, so a scoped
160
+ selector wouldn't match. */
161
+ /* `!important` is needed to override the editor / input components'
162
+ inline `style="display: contents"` host bindings (those win over
163
+ stylesheets). `::ng-deep` reaches the dynamically-created editor
164
+ components, which don't inherit the parent template's emulated
165
+ encapsulation attributes. */
166
+ :host td.kj-table-cell--editing ::ng-deep kj-text-editor,
167
+ :host td.kj-table-cell--editing ::ng-deep kj-number-editor,
168
+ :host td.kj-table-cell--editing ::ng-deep kj-select-editor,
169
+ :host td.kj-table-cell--editing ::ng-deep kj-date-editor,
170
+ :host td.kj-table-cell--editing ::ng-deep kj-boolean-editor {
171
+ position: absolute !important;
172
+ inset: 0 !important;
173
+ display: flex !important;
174
+ align-items: center !important;
175
+ padding: inherit !important;
176
+ background: var(--kj-bg-surface);
177
+ z-index: 1;
178
+ }
179
+ :host td.kj-table-cell--editing ::ng-deep kj-input,
180
+ :host td.kj-table-cell--editing ::ng-deep kj-number-input,
181
+ :host td.kj-table-cell--editing ::ng-deep kj-select {
182
+ display: flex !important;
183
+ width: 100% !important;
184
+ min-width: 0 !important;
185
+ box-sizing: border-box;
186
+ }
187
+ :host td.kj-table-cell--editing ::ng-deep input,
188
+ :host td.kj-table-cell--editing ::ng-deep .kj-select-trigger {
189
+ width: 100% !important;
190
+ min-width: 0 !important;
191
+ box-sizing: border-box;
192
+ }
193
+ /* The anchor span itself contributes nothing to layout — the directive
194
+ creates the editor as its NEXT SIBLING in the cell, not as a child. */
195
+ :host td .kj-table-editor-anchor {
196
+ display: none;
197
+ }
198
+
199
+ /* Selected rows get a brand-accent tint + a left border stripe so a
200
+ keyboard user can tell which row is selected at a glance, even when
201
+ the row is not focused. */
202
+ :host tr[data-selected] td {
203
+ background: color-mix(in oklab, var(--kj-bg-primary, var(--kj-bg-accent, currentColor)) 12%, var(--kj-bg-surface));
204
+ }
205
+ :host tr[data-selected] td:first-child {
206
+ box-shadow: inset 3px 0 0 0 var(--kj-bg-primary, var(--kj-fg-primary));
207
+ }
208
+
209
+ /* ── Pinned columns ─────────────────────────────────────────────
210
+ Sticky positioning + a visible boundary (border + soft shadow) so the
211
+ pinned edge reads as a separate region from the scrolling middle. The
212
+ :host([data-variant]) toggles don't affect pin borders — they're a
213
+ structural cue, not a visual variant. */
214
+ :host td[data-pin="left"],
215
+ :host th[data-pin="left"] {
216
+ position: sticky;
217
+ left: 0;
218
+ z-index: 1;
219
+ background: var(--kj-bg-surface);
220
+ }
221
+ :host td[data-pin="right"],
222
+ :host th[data-pin="right"] {
223
+ position: sticky;
224
+ right: 0;
225
+ z-index: 1;
226
+ background: var(--kj-bg-surface);
227
+ }
228
+
229
+ /* Boundary indicator on the inside edge of each pinned region.
230
+
231
+ Last LEFT-pinned cell: a `[data-pin="left"]` whose next sibling is NOT
232
+ also left-pinned — uses `:not(:has(+ ...))`.
233
+
234
+ First RIGHT-pinned cell: a `[data-pin="right"]` whose previous sibling
235
+ is NOT right-pinned — uses the `:not([..]) + [data-pin="right"]` pattern.
236
+
237
+ Both are purely declarative; no JS bookkeeping. */
238
+ :host td[data-pin="left"]:not(:has(+ td[data-pin="left"])),
239
+ :host th[data-pin="left"]:not(:has(+ th[data-pin="left"])) {
240
+ border-right: 1px solid var(--kj-border-strong, var(--kj-border-default));
241
+ box-shadow: 4px 0 6px -4px rgba(0, 0, 0, 0.25);
242
+ }
243
+ :host tr > :not([data-pin="right"]) + td[data-pin="right"],
244
+ :host tr > :not([data-pin="right"]) + th[data-pin="right"] {
245
+ border-left: 1px solid var(--kj-border-strong, var(--kj-border-default));
246
+ box-shadow: -4px 0 6px -4px rgba(0, 0, 0, 0.25);
247
+ }
248
+
249
+ /* Striped variant: pinned cells still get the alternate background so the
250
+ sticky cell doesn't visually float over a coloured row beneath it. */
251
+ :host([data-variant="striped"]) tbody tr:nth-child(even) td[data-pin] {
252
+ background: var(--kj-bg-elevated);
253
+ }
254
+
255
+ /* ── Resize handle ──────────────────────────────────────────────
256
+ Always-visible thin track on the right edge of each `<th>`; widens
257
+ and brightens to the focus color on hover/focus so users can tell
258
+ it's draggable. Hidden when no resize is enabled (the host doesn't
259
+ render the element). */
260
+ .kj-table-resize-handle {
261
+ position: absolute;
262
+ top: 25%;
263
+ right: 0;
264
+ width: 6px;
265
+ height: 50%;
266
+ cursor: col-resize;
267
+ user-select: none;
268
+ touch-action: none;
269
+ background: transparent;
270
+ border-right: 2px solid var(--kj-border-strong, var(--kj-border-default));
271
+ transition: border-color var(--kj-transition), background var(--kj-transition), width var(--kj-transition);
272
+ }
273
+ .kj-table-resize-handle:hover,
274
+ .kj-table-resize-handle:focus-visible {
275
+ border-right-color: var(--kj-border-focus);
276
+ background: color-mix(in srgb, var(--kj-border-focus) 20%, transparent);
277
+ width: 8px;
278
+ outline: none;
279
+ }
280
+
281
+ /* ── Resize preview guide ───────────────────────────────────────
282
+ While a column is being resized (TanStack `onEnd` mode), the
283
+ wrapper sets `data-resizing` on the header and pipes the live
284
+ cursor delta into `--kj-resize-delta`. The handle becomes a
285
+ tall vertical line anchored to the column's current right edge
286
+ and translated by the delta — it visually tracks where the new
287
+ edge will land before the column actually reflows on mouseup.
288
+
289
+ `top: 0; height: 9999px` overflows the `<th>`; the surrounding
290
+ `.kj-table-body` has `overflow: auto`, so the visible portion
291
+ is naturally clipped to the table's height. */
292
+ :host th[data-resizing] .kj-table-resize-handle {
293
+ top: 0;
294
+ height: 9999px;
295
+ width: 0;
296
+ background: transparent;
297
+ border-right: 2px solid var(--kj-border-focus, var(--kj-bg-primary));
298
+ transform: translateX(var(--kj-resize-delta, 0px));
299
+ pointer-events: none;
300
+ z-index: 3;
301
+ transition: none;
302
+ }
303
+
304
+ /* ── Selection column ───────────────────────────────────────────
305
+ Leading checkbox column auto-rendered when `kjSelectionMode` is
306
+ `'single'` or `'multi'`. Narrow fixed-width column so the row
307
+ data starts at a predictable horizontal position. */
308
+ :host th.kj-table-select-cell,
309
+ :host td.kj-table-select-cell {
310
+ width: 2.5rem;
311
+ padding-inline: var(--kj-base-space-sm);
312
+ text-align: center;
313
+ vertical-align: middle;
314
+ }
315
+ .kj-table-select-cell kj-checkbox {
316
+ display: inline-flex;
317
+ align-items: center;
318
+ justify-content: center;
319
+ }
320
+
321
+ /* ── Filter row beneath the header row ──────────────────────────
322
+ Each cell hosts a styled filter input (text / number / date / select)
323
+ mounted by the wrapper. We keep the row visually distinct from headers
324
+ with a lighter background + thinner padding, and let the input fill
325
+ the cell width so filters feel column-anchored. */
326
+ .kj-table-filter-row > th {
327
+ font-weight: 400;
328
+ background: var(--kj-bg-surface);
329
+ border-top: 1px solid var(--kj-border-muted, var(--kj-border-default));
330
+ }
331
+ .kj-table-filter-cell {
332
+ padding-top: var(--kj-base-space-xs);
333
+ padding-bottom: var(--kj-base-space-xs);
334
+ vertical-align: middle;
335
+ }
336
+ .kj-table-filter-cell .kj-table-filter-anchor + *,
337
+ .kj-table-filter-cell kj-input,
338
+ .kj-table-filter-cell kj-number-input,
339
+ .kj-table-filter-cell kj-date-picker,
340
+ .kj-table-filter-cell kj-select {
341
+ width: 100%;
342
+ }
343
+ .kj-table-filter-anchor {
344
+ display: block;
345
+ width: 100%;
346
+ }
347
+
348
+ /* Inline editors get the same compact xs treatment as filter cells. The
349
+ filter inputs already bind `kjSize="xs"` themselves; this rule covers the
350
+ editor anchors that mount unsized primitives at runtime. */
351
+ :host .kj-table-editor-anchor .kj-input,
352
+ :host .kj-table-editor-anchor .kj-select {
353
+ --kj-input-height: 1.75rem;
354
+ --kj-input-font-size: var(--kj-text-xs);
355
+ --kj-input-padding-x: var(--kj-base-space-sm);
356
+ --kj-input-padding-y: 0;
357
+ --kj-input-radius: var(--kj-radius-selector);
358
+ }
359
+
360
+ /* Empty / error / loading panes. */
361
+ .kj-table-empty,
362
+ .kj-table-error,
363
+ .kj-table-loading {
364
+ display: flex;
365
+ align-items: center;
366
+ justify-content: center;
367
+ padding: var(--kj-base-space-lg);
368
+ color: var(--kj-fg-muted);
369
+ }
370
+
371
+ /* ── Loading state ──────────────────────────────────────────────
372
+ Two modes:
373
+ - Initial load (`data-has-rows="false"`): full-pane overlay with
374
+ a centered "Loading…" message. The user has nothing to look at
375
+ yet so we cover the empty body.
376
+ - Subsequent reloads (`data-has-rows="true"`): a slim 2px brand
377
+ stripe at the top of the body. The stale rows stay readable
378
+ and pointer events keep working — the user can sort/scroll/
379
+ paginate again while the refresh is in flight. */
380
+ .kj-table-loading {
381
+ position: absolute;
382
+ inset: 0;
383
+ background: color-mix(in srgb, var(--kj-bg-surface) 70%, transparent);
384
+ pointer-events: none;
385
+ }
386
+ .kj-table-loading[data-has-rows] {
387
+ inset: 0 0 auto 0;
388
+ height: 2px;
389
+ background: var(--kj-bg-primary);
390
+ padding: 0;
391
+ animation: kj-table-loading-pulse 1.4s ease-in-out infinite;
392
+ }
393
+ .kj-table-loading[data-has-rows] .kj-table-loading-fallback,
394
+ .kj-table-loading[data-has-rows] ::ng-deep [kjLoading] {
395
+ display: none;
396
+ }
397
+
398
+ @keyframes kj-table-loading-pulse {
399
+ 0%, 100% { opacity: 0.55; }
400
+ 50% { opacity: 1; }
401
+ }
402
+ .kj-table-error {
403
+ color: var(--kj-fg-error, var(--kj-fg-default));
404
+ }
405
+ .kj-table-loading-fallback {
406
+ font-size: var(--kj-text-sm);
407
+ }
408
+
409
+ /* Row expansion. */
410
+ .kj-table-expansion-row > td {
411
+ background: var(--kj-bg-elevated);
412
+ }
413
+
414
+ /* ── Pinned-row tbody segments ──────────────────────────────────
415
+ Use the brand accent so pinned rows visually pop out of the center
416
+ body; sticky positioning lets them stay anchored at the top/bottom
417
+ even when the body scrolls. */
418
+ .kj-table-tbody-pinned[data-pin="top"] > tr > td {
419
+ background: var(--kj-bg-elevated);
420
+ border-bottom: 2px solid var(--kj-border-primary, var(--kj-border-strong, var(--kj-border-default)));
421
+ box-shadow: 0 4px 6px -4px rgba(0, 0, 0, 0.25);
422
+ position: sticky;
423
+ top: 0;
424
+ z-index: 2;
425
+ }
426
+ .kj-table-tbody-pinned[data-pin="bottom"] > tr > td {
427
+ background: var(--kj-bg-elevated);
428
+ border-top: 2px solid var(--kj-border-primary, var(--kj-border-strong, var(--kj-border-default)));
429
+ box-shadow: 0 -4px 6px -4px rgba(0, 0, 0, 0.25);
430
+ position: sticky;
431
+ bottom: 0;
432
+ z-index: 2;
433
+ }
434
+
435
+ /* ── Grouping row ───────────────────────────────────────────────
436
+ Rows where a column is grouped show a toggle-able header chip on the
437
+ grouped cell + count of subRows. */
438
+ .kj-table-group-toggle {
439
+ display: inline-flex;
440
+ align-items: center;
441
+ gap: var(--kj-base-space-xs, 0.25rem);
442
+ background: transparent;
443
+ border: 0;
444
+ padding: 0;
445
+ font: inherit;
446
+ color: inherit;
447
+ cursor: pointer;
448
+ }
449
+ .kj-table-group-toggle__chevron {
450
+ display: inline-block;
451
+ width: 0.75rem;
452
+ font-family: var(--kj-font-mono);
453
+ color: var(--kj-fg-muted);
454
+ transition: transform var(--kj-transition);
455
+ }
456
+ .kj-table-group-toggle[aria-expanded="true"] .kj-table-group-toggle__chevron {
457
+ transform: rotate(90deg);
458
+ }
459
+ .kj-table-group-toggle__count {
460
+ margin-inline-start: var(--kj-base-space-xs, 0.25rem);
461
+ font-size: 0.75em;
462
+ color: var(--kj-fg-muted);
463
+ font-variant-numeric: tabular-nums;
464
+ }
465
+ :host tbody tr[data-row-grouped] td {
466
+ background: var(--kj-bg-elevated);
467
+ font-weight: 600;
468
+ }
@@ -0,0 +1,175 @@
1
+ import { Component, signal, ChangeDetectionStrategy } from '@angular/core';
2
+ import { render } from '@testing-library/angular';
3
+ import { axe, toHaveNoViolations } from 'jest-axe';
4
+ import { beforeAll, describe, expect, it, vi } from 'vitest';
5
+ import { KjTableComponent } from './table';
6
+ import { KJ_TABLE_STORAGE, inMemoryAdapter, kjColumn, type KjStorageAdapter } from '@kouji-ui/core';
7
+
8
+ expect.extend(toHaveNoViolations);
9
+
10
+ // jsdom shims for the virtualizer (used by table when virtualization is on).
11
+ class StubResizeObserver {
12
+ observe(): void {}
13
+ unobserve(): void {}
14
+ disconnect(): void {}
15
+ }
16
+ beforeAll(() => {
17
+ vi.stubGlobal('ResizeObserver', StubResizeObserver);
18
+ Object.defineProperty(HTMLElement.prototype, 'offsetWidth', {
19
+ configurable: true,
20
+ get(): number {
21
+ return 400;
22
+ },
23
+ });
24
+ Object.defineProperty(HTMLElement.prototype, 'offsetHeight', {
25
+ configurable: true,
26
+ get(): number {
27
+ return 200;
28
+ },
29
+ });
30
+ });
31
+
32
+ interface User {
33
+ id: string;
34
+ name: string;
35
+ email: string;
36
+ }
37
+
38
+ @Component({
39
+ standalone: true,
40
+ imports: [KjTableComponent],
41
+ changeDetection: ChangeDetectionStrategy.Eager,
42
+ template: `<kj-table [kjData]="data()" [kjColumns]="cols" />`,
43
+ })
44
+ class Host {
45
+ protected readonly data = signal<User[]>([{ id: '1', name: 'A', email: 'a@x' }]);
46
+ protected readonly cols = [
47
+ kjColumn<User>({ accessorKey: 'name', header: 'Name' }),
48
+ kjColumn<User>({ accessorKey: 'email', header: 'Email' }),
49
+ ];
50
+ }
51
+
52
+ describe('KjTableComponent', () => {
53
+ it('renders the data + columns', async () => {
54
+ const { getByText } = await render(Host);
55
+ expect(getByText('A')).toBeInTheDocument();
56
+ expect(getByText('a@x')).toBeInTheDocument();
57
+ expect(getByText('Name')).toBeInTheDocument();
58
+ });
59
+
60
+ it('host carries role="grid"', async () => {
61
+ const { container } = await render(Host);
62
+ expect(container.querySelector('[role="grid"]')).toBeTruthy();
63
+ });
64
+
65
+ it('default playground is axe-clean', async () => {
66
+ const { container } = await render(Host);
67
+ const results = await axe(container);
68
+ expect(results).toHaveNoViolations();
69
+ });
70
+ });
71
+
72
+ // ── Empty slot ─────────────────────────────────────────────────────────────
73
+ @Component({
74
+ standalone: true,
75
+ imports: [KjTableComponent],
76
+ changeDetection: ChangeDetectionStrategy.Eager,
77
+ template: ` <kj-table [kjData]="data" [kjColumns]="cols">
78
+ <div kjEmpty>No data</div>
79
+ </kj-table>`,
80
+ })
81
+ class EmptyHost {
82
+ protected readonly data: User[] = [];
83
+ protected readonly cols = [kjColumn<User>({ accessorKey: 'name', header: 'Name' })];
84
+ }
85
+
86
+ describe('KjTableComponent — slots', () => {
87
+ it('renders the empty slot when data is empty', async () => {
88
+ const { getByText } = await render(EmptyHost);
89
+ expect(getByText('No data')).toBeInTheDocument();
90
+ });
91
+ });
92
+
93
+ // ── Filter row ─────────────────────────────────────────────────────────────
94
+ @Component({
95
+ standalone: true,
96
+ imports: [KjTableComponent],
97
+ changeDetection: ChangeDetectionStrategy.Eager,
98
+ template: `<kj-table [kjData]="data" [kjColumns]="cols" [kjEnableFilters]="true" />`,
99
+ })
100
+ class FilterRowHost {
101
+ protected readonly data: User[] = [{ id: '1', name: 'A', email: 'a@x' }];
102
+ protected readonly cols = [
103
+ kjColumn<User>({ accessorKey: 'name', header: 'Name', kjType: 'text', kjFilterable: true }),
104
+ kjColumn<User>({ accessorKey: 'email', header: 'Email', kjType: 'text', kjFilterable: true }),
105
+ ];
106
+ }
107
+
108
+ describe('KjTableComponent — filter row', () => {
109
+ it('renders a second header row with filter cells when kjEnableFilters=true', async () => {
110
+ const { container } = await render(FilterRowHost);
111
+ const filterRow = container.querySelector('.kj-table-filter-row');
112
+ expect(filterRow).toBeTruthy();
113
+ const anchors = container.querySelectorAll('.kj-table-filter-anchor');
114
+ expect(anchors.length).toBeGreaterThan(0);
115
+ });
116
+ });
117
+
118
+ // ── getRowId ────────────────────────────────────────────────────────────────
119
+ @Component({
120
+ standalone: true,
121
+ imports: [KjTableComponent],
122
+ changeDetection: ChangeDetectionStrategy.Eager,
123
+ template: ` <kj-table [kjData]="data" [kjColumns]="cols" [kjGetRowId]="rowId" />`,
124
+ })
125
+ class GetRowIdHost {
126
+ protected readonly data: User[] = [
127
+ { id: 'user-1', name: 'Alice', email: 'a@x' },
128
+ { id: 'user-2', name: 'Bob', email: 'b@x' },
129
+ ];
130
+ protected readonly cols = [kjColumn<User>({ accessorKey: 'name', header: 'Name' })];
131
+ protected readonly rowId = (r: User): string => r.id;
132
+ }
133
+
134
+ describe('KjTableComponent — kjGetRowId', () => {
135
+ it('keys row selection by the user-supplied id', async () => {
136
+ const { fixture } = await render(GetRowIdHost);
137
+ const dataTable = fixture.debugElement.children[0].componentInstance as KjTableComponent<User>;
138
+ const tbl = dataTable.tableRef();
139
+ tbl.setState({ rowSelection: { 'user-1': true } });
140
+ fixture.detectChanges();
141
+ const row = tbl.table().getRow('user-1');
142
+ expect(row.getIsSelected()).toBe(true);
143
+ expect(tbl.table().getRow('user-2').getIsSelected()).toBe(false);
144
+ });
145
+ });
146
+
147
+ // ── kjStorageKey persistence ───────────────────────────────────────────────
148
+ @Component({
149
+ standalone: true,
150
+ imports: [KjTableComponent],
151
+ changeDetection: ChangeDetectionStrategy.Eager,
152
+ template: ` <kj-table [kjData]="data" [kjColumns]="cols" kjStorageKey="kj.test.dt" />`,
153
+ })
154
+ class StorageHost {
155
+ protected readonly data: User[] = [{ id: '1', name: 'A', email: 'a@x' }];
156
+ protected readonly cols = [kjColumn<User>({ accessorKey: 'name', header: 'Name' })];
157
+ }
158
+
159
+ describe('KjTableComponent — kjStorageKey', () => {
160
+ it('persists state to the injected KJ_TABLE_STORAGE adapter', async () => {
161
+ const adapter: KjStorageAdapter = inMemoryAdapter();
162
+ const writeSpy = vi.spyOn(adapter, 'write');
163
+ const { fixture } = await render(StorageHost, {
164
+ providers: [{ provide: KJ_TABLE_STORAGE, useValue: adapter }],
165
+ });
166
+ const dataTable = fixture.debugElement.children[0].componentInstance as KjTableComponent<User>;
167
+ dataTable.tableRef().setState({ globalFilter: 'foo' });
168
+ fixture.detectChanges();
169
+ await fixture.whenStable();
170
+ expect(writeSpy).toHaveBeenCalled();
171
+ const lastCall = writeSpy.mock.calls.at(-1)!;
172
+ expect(lastCall[0]).toBe('kj.test.dt');
173
+ expect((lastCall[1] as { globalFilter: string }).globalFilter).toBe('foo');
174
+ });
175
+ });