@egose/shadcn-theme-ng 0.0.28 → 0.2.0

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 (237) hide show
  1. package/README.md +130 -13
  2. package/accordion/README.md +376 -34
  3. package/accordion/fesm2022/accordion.mjs +27 -39
  4. package/alert/README.md +343 -34
  5. package/alert/fesm2022/alert.mjs +47 -47
  6. package/alert-dialog/README.md +471 -5
  7. package/alert-dialog/fesm2022/alert-dialog.mjs +47 -47
  8. package/aspect-ratio/README.md +272 -5
  9. package/aspect-ratio/fesm2022/aspect-ratio.mjs +9 -9
  10. package/autocomplete/README.md +473 -34
  11. package/autocomplete/fesm2022/autocomplete.mjs +53 -71
  12. package/avatar/README.md +357 -5
  13. package/avatar/fesm2022/avatar.mjs +32 -32
  14. package/badge/README.md +289 -34
  15. package/badge/fesm2022/badge.mjs +57 -57
  16. package/basic-alert/README.md +324 -34
  17. package/basic-alert/fesm2022/basic-alert.mjs +6 -18
  18. package/breadcrumb/README.md +406 -5
  19. package/breadcrumb/fesm2022/breadcrumb.mjs +33 -39
  20. package/button/README.md +453 -34
  21. package/button/fesm2022/button.mjs +147 -219
  22. package/button/types/button.d.ts +7 -10
  23. package/button-group/README.md +318 -5
  24. package/button-group/fesm2022/button-group.mjs +20 -20
  25. package/calendar/README.md +328 -34
  26. package/calendar/fesm2022/calendar.mjs +29 -743
  27. package/card/README.md +331 -5
  28. package/card/fesm2022/card.mjs +33 -33
  29. package/carousel/README.md +333 -5
  30. package/carousel/fesm2022/carousel.mjs +39 -78
  31. package/checkbox/README.md +291 -34
  32. package/checkbox/fesm2022/checkbox.mjs +20 -58
  33. package/checkbox/types/checkbox.d.ts +5 -4
  34. package/collapsible/README.md +332 -5
  35. package/collapsible/fesm2022/collapsible.mjs +15 -15
  36. package/combobox/README.md +507 -5
  37. package/combobox/fesm2022/combobox.mjs +91 -224
  38. package/command/README.md +435 -5
  39. package/command/fesm2022/command.mjs +49 -109
  40. package/confirmation-dialog/README.md +272 -34
  41. package/confirmation-dialog/fesm2022/confirmation-dialog.mjs +15 -40
  42. package/confirmation-dialog/types/confirmation-dialog.d.ts +8 -4
  43. package/context-menu/README.md +366 -5
  44. package/context-menu/fesm2022/context-menu.mjs +9 -9
  45. package/date-picker/README.md +436 -34
  46. package/date-picker/fesm2022/date-picker.mjs +64 -267
  47. package/date-picker/types/date-picker.d.ts +7 -3
  48. package/dialog/README.md +419 -34
  49. package/dialog/fesm2022/dialog.mjs +45 -71
  50. package/drawer/README.md +395 -5
  51. package/drawer/fesm2022/drawer.mjs +44 -54
  52. package/dropdown-menu/README.md +417 -5
  53. package/dropdown-menu/fesm2022/dropdown-menu.mjs +82 -70
  54. package/dropdown-menu/types/dropdown-menu.d.ts +4 -0
  55. package/empty/README.md +329 -5
  56. package/empty/fesm2022/empty.mjs +30 -30
  57. package/field/README.md +385 -5
  58. package/field/fesm2022/field.mjs +56 -72
  59. package/form-checkbox/README.md +283 -34
  60. package/form-checkbox/fesm2022/form-checkbox.mjs +25 -85
  61. package/form-checkbox/types/form-checkbox.d.ts +7 -1
  62. package/form-date-picker/README.md +293 -34
  63. package/form-date-picker/fesm2022/form-date-picker.mjs +31 -84
  64. package/form-date-picker/types/form-date-picker.d.ts +7 -1
  65. package/form-field/README.md +327 -34
  66. package/form-field/fesm2022/form-field.mjs +33 -19
  67. package/form-field/types/form-field.d.ts +28 -20
  68. package/form-field-simple/README.md +311 -34
  69. package/form-field-simple/fesm2022/form-field-simple.mjs +4 -4
  70. package/form-searchable-multiselect/README.md +332 -34
  71. package/form-searchable-multiselect/fesm2022/form-searchable-multiselect.mjs +31 -91
  72. package/form-searchable-multiselect/types/form-searchable-multiselect.d.ts +7 -1
  73. package/form-select/README.md +321 -34
  74. package/form-select/fesm2022/form-select.mjs +32 -149
  75. package/form-select/types/form-select.d.ts +7 -1
  76. package/form-text-input/README.md +342 -34
  77. package/form-text-input/fesm2022/form-text-input.mjs +35 -149
  78. package/form-text-input/types/form-text-input.d.ts +9 -12
  79. package/form-textarea/README.md +318 -34
  80. package/form-textarea/fesm2022/form-textarea.mjs +34 -109
  81. package/form-textarea/types/form-textarea.d.ts +8 -1
  82. package/hover-card/README.md +256 -5
  83. package/hover-card/fesm2022/hover-card.mjs +19 -19
  84. package/icon/README.md +210 -34
  85. package/icon/fesm2022/icon.mjs +8 -8
  86. package/input/README.md +240 -34
  87. package/input/fesm2022/input.mjs +17 -12
  88. package/input/types/input.d.ts +2 -1
  89. package/input-group/README.md +335 -5
  90. package/input-group/fesm2022/input-group.mjs +34 -34
  91. package/input-otp/README.md +375 -5
  92. package/input-otp/fesm2022/input-otp.mjs +26 -26
  93. package/item/README.md +385 -5
  94. package/item/fesm2022/item.mjs +53 -53
  95. package/kbd/README.md +291 -5
  96. package/kbd/fesm2022/kbd.mjs +12 -12
  97. package/label/README.md +243 -34
  98. package/label/fesm2022/label.mjs +10 -10
  99. package/label/types/label.d.ts +1 -1
  100. package/layout-simple/README.md +174 -44
  101. package/layout-simple/fesm2022/layout-simple.mjs +508 -603
  102. package/layout-simple/types/layout-simple.d.ts +179 -128
  103. package/menu/README.md +418 -0
  104. package/menu/fesm2022/menu.mjs +455 -0
  105. package/menu/package.json +24 -0
  106. package/menu/types/menu.d.ts +137 -0
  107. package/menubar/README.md +343 -5
  108. package/menubar/fesm2022/menubar.mjs +13 -13
  109. package/native-select/README.md +323 -5
  110. package/native-select/fesm2022/native-select.mjs +19 -19
  111. package/navigation-menu/README.md +369 -5
  112. package/navigation-menu/fesm2022/navigation-menu.mjs +35 -47
  113. package/package.json +183 -154
  114. package/pagination/README.md +388 -5
  115. package/pagination/fesm2022/pagination.mjs +45 -331
  116. package/popover/README.md +302 -34
  117. package/popover/fesm2022/popover.mjs +30 -30
  118. package/progress/README.md +311 -5
  119. package/progress/fesm2022/progress.mjs +13 -13
  120. package/radio-group/README.md +335 -34
  121. package/radio-group/fesm2022/radio-group.mjs +26 -19
  122. package/radio-group/types/radio-group.d.ts +1 -1
  123. package/resizable/README.md +269 -5
  124. package/resizable/fesm2022/resizable.mjs +18 -26
  125. package/scroll-area/README.md +233 -5
  126. package/scroll-area/fesm2022/scroll-area.mjs +9 -9
  127. package/searchable-multiselect/README.md +294 -34
  128. package/searchable-multiselect/fesm2022/searchable-multiselect.mjs +28 -117
  129. package/searchable-multiselect/types/searchable-multiselect.d.ts +8 -2
  130. package/select/README.md +408 -34
  131. package/select/fesm2022/select.mjs +71 -111
  132. package/select/types/select.d.ts +3 -1
  133. package/separator/README.md +193 -34
  134. package/separator/fesm2022/separator.mjs +9 -9
  135. package/separator/types/separator.d.ts +1 -1
  136. package/sheet/README.md +282 -34
  137. package/sheet/fesm2022/sheet.mjs +41 -53
  138. package/sidebar/README.md +457 -5
  139. package/sidebar/fesm2022/sidebar.mjs +125 -227
  140. package/skeleton/README.md +217 -5
  141. package/skeleton/fesm2022/skeleton.mjs +9 -9
  142. package/slider/README.md +273 -5
  143. package/slider/fesm2022/slider.mjs +10 -80
  144. package/sonner/README.md +317 -34
  145. package/sonner/fesm2022/sonner.mjs +13 -13
  146. package/spinner/README.md +255 -34
  147. package/spinner/fesm2022/spinner.mjs +11 -11
  148. package/switch/README.md +281 -34
  149. package/switch/fesm2022/switch.mjs +13 -15
  150. package/table/README.md +423 -5
  151. package/table/fesm2022/table.mjs +41 -41
  152. package/tabs/README.md +382 -34
  153. package/tabs/fesm2022/tabs.mjs +35 -111
  154. package/textarea/README.md +282 -5
  155. package/textarea/fesm2022/textarea.mjs +9 -9
  156. package/toggle/README.md +270 -5
  157. package/toggle/fesm2022/toggle.mjs +13 -13
  158. package/toggle-group/README.md +340 -5
  159. package/toggle-group/fesm2022/toggle-group.mjs +13 -13
  160. package/toggle-group/types/toggle-group.d.ts +13 -7
  161. package/tooltip/README.md +240 -34
  162. package/tooltip/fesm2022/tooltip.mjs +14 -14
  163. package/typography/README.md +271 -5
  164. package/typography/fesm2022/typography.mjs +53 -53
  165. package/typography/types/typography.d.ts +19 -19
  166. package/utils/README.md +274 -34
  167. package/utils/fesm2022/utils.mjs +68 -44
  168. package/accordion/fesm2022/accordion.mjs.map +0 -1
  169. package/alert/fesm2022/alert.mjs.map +0 -1
  170. package/alert-dialog/fesm2022/alert-dialog.mjs.map +0 -1
  171. package/aspect-ratio/fesm2022/aspect-ratio.mjs.map +0 -1
  172. package/autocomplete/fesm2022/autocomplete.mjs.map +0 -1
  173. package/avatar/fesm2022/avatar.mjs.map +0 -1
  174. package/badge/fesm2022/badge.mjs.map +0 -1
  175. package/basic-alert/fesm2022/basic-alert.mjs.map +0 -1
  176. package/breadcrumb/fesm2022/breadcrumb.mjs.map +0 -1
  177. package/button/fesm2022/button.mjs.map +0 -1
  178. package/button-group/fesm2022/button-group.mjs.map +0 -1
  179. package/calendar/fesm2022/calendar.mjs.map +0 -1
  180. package/card/fesm2022/card.mjs.map +0 -1
  181. package/carousel/fesm2022/carousel.mjs.map +0 -1
  182. package/checkbox/fesm2022/checkbox.mjs.map +0 -1
  183. package/collapsible/fesm2022/collapsible.mjs.map +0 -1
  184. package/combobox/fesm2022/combobox.mjs.map +0 -1
  185. package/command/fesm2022/command.mjs.map +0 -1
  186. package/confirmation-dialog/fesm2022/confirmation-dialog.mjs.map +0 -1
  187. package/context-menu/fesm2022/context-menu.mjs.map +0 -1
  188. package/date-picker/fesm2022/date-picker.mjs.map +0 -1
  189. package/dialog/fesm2022/dialog.mjs.map +0 -1
  190. package/drawer/fesm2022/drawer.mjs.map +0 -1
  191. package/dropdown-menu/fesm2022/dropdown-menu.mjs.map +0 -1
  192. package/empty/fesm2022/empty.mjs.map +0 -1
  193. package/field/fesm2022/field.mjs.map +0 -1
  194. package/form-checkbox/fesm2022/form-checkbox.mjs.map +0 -1
  195. package/form-date-picker/fesm2022/form-date-picker.mjs.map +0 -1
  196. package/form-field/fesm2022/form-field.mjs.map +0 -1
  197. package/form-field-simple/fesm2022/form-field-simple.mjs.map +0 -1
  198. package/form-searchable-multiselect/fesm2022/form-searchable-multiselect.mjs.map +0 -1
  199. package/form-select/fesm2022/form-select.mjs.map +0 -1
  200. package/form-text-input/fesm2022/form-text-input.mjs.map +0 -1
  201. package/form-textarea/fesm2022/form-textarea.mjs.map +0 -1
  202. package/hover-card/fesm2022/hover-card.mjs.map +0 -1
  203. package/icon/fesm2022/icon.mjs.map +0 -1
  204. package/input/fesm2022/input.mjs.map +0 -1
  205. package/input-group/fesm2022/input-group.mjs.map +0 -1
  206. package/input-otp/fesm2022/input-otp.mjs.map +0 -1
  207. package/item/fesm2022/item.mjs.map +0 -1
  208. package/kbd/fesm2022/kbd.mjs.map +0 -1
  209. package/label/fesm2022/label.mjs.map +0 -1
  210. package/layout-simple/fesm2022/layout-simple.mjs.map +0 -1
  211. package/menubar/fesm2022/menubar.mjs.map +0 -1
  212. package/native-select/fesm2022/native-select.mjs.map +0 -1
  213. package/navigation-menu/fesm2022/navigation-menu.mjs.map +0 -1
  214. package/pagination/fesm2022/pagination.mjs.map +0 -1
  215. package/popover/fesm2022/popover.mjs.map +0 -1
  216. package/progress/fesm2022/progress.mjs.map +0 -1
  217. package/radio-group/fesm2022/radio-group.mjs.map +0 -1
  218. package/resizable/fesm2022/resizable.mjs.map +0 -1
  219. package/scroll-area/fesm2022/scroll-area.mjs.map +0 -1
  220. package/searchable-multiselect/fesm2022/searchable-multiselect.mjs.map +0 -1
  221. package/select/fesm2022/select.mjs.map +0 -1
  222. package/separator/fesm2022/separator.mjs.map +0 -1
  223. package/sheet/fesm2022/sheet.mjs.map +0 -1
  224. package/sidebar/fesm2022/sidebar.mjs.map +0 -1
  225. package/skeleton/fesm2022/skeleton.mjs.map +0 -1
  226. package/slider/fesm2022/slider.mjs.map +0 -1
  227. package/sonner/fesm2022/sonner.mjs.map +0 -1
  228. package/spinner/fesm2022/spinner.mjs.map +0 -1
  229. package/switch/fesm2022/switch.mjs.map +0 -1
  230. package/table/fesm2022/table.mjs.map +0 -1
  231. package/tabs/fesm2022/tabs.mjs.map +0 -1
  232. package/textarea/fesm2022/textarea.mjs.map +0 -1
  233. package/toggle/fesm2022/toggle.mjs.map +0 -1
  234. package/toggle-group/fesm2022/toggle-group.mjs.map +0 -1
  235. package/tooltip/fesm2022/tooltip.mjs.map +0 -1
  236. package/typography/fesm2022/typography.mjs.map +0 -1
  237. package/utils/fesm2022/utils.mjs.map +0 -1
package/README.md CHANGED
@@ -14,17 +14,28 @@ npm install @egose/shadcn-theme-ng
14
14
  npm install @egose/shadcn-theme-ng-tw
15
15
  ```
16
16
 
17
- `pnpm` / `yarn` equivalents work too. Make sure your project's versions satisfy the peer ranges below.
17
+ `pnpm` / `yarn` equivalents work too. npm installs peer dependencies automatically when it can resolve compatible
18
+ versions; applications must keep their existing framework versions inside the supported ranges below.
18
19
 
19
20
  ### Peer dependencies
20
21
 
21
- | Package | Supported version |
22
- | ------------------- | ------------------- |
23
- | `@angular/common` | `^20.2.0` |
24
- | `@angular/core` | `^20.2.0` |
25
- | `@spartan-ng/brain` | `^0.0.1-alpha.512+` |
22
+ | Package | Supported version | Tested version |
23
+ | ------------------- | ------------------ | -------------- |
24
+ | `@angular/cdk` | `>=22.0.0 <23.0.0` | `22.1.3` |
25
+ | `@angular/common` | `>=22.0.0 <23.0.0` | `22.1.3` |
26
+ | `@angular/core` | `>=22.0.0 <23.0.0` | `22.1.3` |
27
+ | `@angular/forms` | `>=22.0.0 <23.0.0` | `22.1.3` |
28
+ | `@angular/router` | `>=22.0.0 <23.0.0` | `22.1.3` |
29
+ | `@ng-icons/core` | `>=35.0.1 <36.0.0` | `35.0.1` |
30
+ | `@spartan-ng/brain` | `>=1.3.2 <2.0.0` | `1.3.2` |
31
+ | `rxjs` | `>=7.8.0 <8.0.0` | `7.8.2` |
26
32
 
27
- `@spartan-ng/brain` is the underlying primitive library that powers most components.
33
+ Angular and CDK must use the same major version. The tested consumer contract is Angular 22, CDK 22, and Spartan 1.3.2;
34
+ the ranges above are copied from the published peer metadata and validated with strict isolated installs.
35
+
36
+ Runtime implementation dependencies such as `@ng-icons/lucide`, `@ng-icons/tabler-icons`, `class-variance-authority`,
37
+ `clsx`, `embla-carousel`, `embla-carousel-angular`, `ngx-scrollbar`, `ngx-sonner`, `tailwind-merge`, and `tslib` are
38
+ installed transitively. Do not install them directly unless your application also imports them.
28
39
 
29
40
  ### Tailwind variants
30
41
 
@@ -37,6 +48,59 @@ There are two published variants of this package. They produce identical markup
37
48
 
38
49
  If your project mixes shadcn styles with other Tailwind utilities that share class names, use the `-tw` variant to avoid collisions.
39
50
 
51
+ Class utilities are normalized to one unprefixed canonical representation during packaging. The plain artifact emits
52
+ unprefixed utilities, while the `-tw` artifact prefixes every recognized utility with `tw:`. Generated JavaScript source
53
+ maps are intentionally excluded because this post-build class and package-identity transformation invalidates ng-packagr's
54
+ maps; shipping no map is safer than shipping a map that points at different generated code.
55
+
56
+ ## Release preparation
57
+
58
+ Prepare both release candidates without publishing by supplying the intended version explicitly:
59
+
60
+ ```bash
61
+ pnpm --dir packages/angular prepare:release --version 1.2.3
62
+ ```
63
+
64
+ This runs `@repo-toolkit/publish-package` with `publish.config.mjs`: it serially
65
+ builds, validates, and packs the plain (`release/plain` → `@egose/shadcn-theme-ng`)
66
+ and `tw:` (`release/tw` → `@egose/shadcn-theme-ng-tw`) variants. The inspectable
67
+ stages and two exact `.tgz` artifacts are written under `packages/angular/release/`.
68
+ Neither package is published unless both candidates pass every step. Publishing is
69
+ intended to run from protected CI with npm trusted publishing/OIDC; `--otp` remains
70
+ available for manual publishes (passed to the toolkit publish command, never logged).
71
+
72
+ ## Source tests
73
+
74
+ Headless-test prerequisite (local and CI): the Karma suites need a
75
+ Chrome-compatible binary. The repository-supported setup downloads it into
76
+ the repo-local `.puppeteer-cache/` directory:
77
+
78
+ ```bash
79
+ pnpm --dir packages/angular install:browser
80
+ ```
81
+
82
+ Alternatively, set `CHROME_BIN` to any Chrome/Chromium binary yourself
83
+ (`test/karma.conf.js` honors a pre-set `CHROME_BIN`, then falls back to a
84
+ system Chrome).
85
+
86
+ Focused library tests are intentionally separate from staged-package and artifact validation:
87
+
88
+ ```bash
89
+ # One selected library
90
+ pnpm --dir packages/angular test:library form-text-input
91
+ pnpm --dir packages/angular test:library utils
92
+
93
+ # Source export contracts plus every selected library, serially and headlessly
94
+ pnpm --dir packages/angular test:libraries
95
+
96
+ # The example shell and router behavior
97
+ pnpm --dir packages/angular/@examples/standard test:ci
98
+ ```
99
+
100
+ The browser suites share `packages/angular/test/setup.ts`, which provides zoneless Angular setup and assertions for form
101
+ bindings and resource teardown. DOM reconciliation uses real `MutationObserver` and animation-frame scheduling; server-mode
102
+ coverage verifies those browser resources are not created. All CI commands disable watch mode so they terminate after one run.
103
+
40
104
  ## Import forms
41
105
 
42
106
  Import each component via its own npm subpath:
@@ -72,23 +136,27 @@ export class MyModule {}
72
136
 
73
137
  Import by component name. Component `NameX` is reachable at `@egose/shadcn-theme-ng/<name-x>` (kebab-case). The current surface:
74
138
 
75
- `accordion`, `alert`, `autocomplete`, `badge`, `basic-alert`, `button`, `calendar`, `checkbox`, `confirmation-dialog`, `date-picker`, `dialog`, `form-checkbox`, `form-date-picker`, `form-field`, `form-field-simple`, `form-searchable-multiselect`, `form-select`, `form-text-input`, `form-textarea`, `icon`, `input`, `label`, `layout-simple`, `menu`, `popover`, `radio-group`, `searchable-multiselect`, `select`, `separator`, `sheet`, `sonner`, `spinner`, `switch`, `tabs`, `tooltip`, `utils`.
139
+ <!-- BEGIN GENERATED SUBPATHS -->
140
+
141
+ `accordion`, `alert`, `alert-dialog`, `aspect-ratio`, `autocomplete`, `avatar`, `badge`, `basic-alert`, `breadcrumb`, `button`, `button-group`, `calendar`, `card`, `carousel`, `checkbox`, `collapsible`, `combobox`, `command`, `confirmation-dialog`, `context-menu`, `date-picker`, `dialog`, `drawer`, `dropdown-menu`, `empty`, `field`, `form-checkbox`, `form-date-picker`, `form-field`, `form-field-simple`, `form-searchable-multiselect`, `form-select`, `form-text-input`, `form-textarea`, `hover-card`, `icon`, `input`, `input-group`, `input-otp`, `item`, `kbd`, `label`, `layout-simple`, `menu`, `menubar`, `native-select`, `navigation-menu`, `pagination`, `popover`, `progress`, `radio-group`, `resizable`, `scroll-area`, `searchable-multiselect`, `select`, `separator`, `sheet`, `sidebar`, `skeleton`, `slider`, `sonner`, `spinner`, `switch`, `table`, `tabs`, `textarea`, `toggle`, `toggle-group`, `tooltip`, `typography`, `utils`.
142
+
143
+ <!-- END GENERATED SUBPATHS -->
76
144
 
77
145
  Anything not in this list is not part of the public surface. The published `exports` map in `package.json` reflects this set exactly — if a subpath is not listed, do not assume it is importable.
78
146
 
79
147
  ## Quick start (Angular standalone)
80
148
 
81
149
  ```ts
82
- import { Component } from "@angular/core";
83
- import { HlmButtonImports } from "@egose/shadcn-theme-ng/button";
84
- import { EgLayoutSimple, MenuItem } from "@egose/shadcn-theme-ng/layout-simple";
150
+ import { Component } from '@angular/core';
151
+ import { HlmButtonImports } from '@egose/shadcn-theme-ng/button';
152
+ import { EgLayoutSimple, MenuItem } from '@egose/shadcn-theme-ng/layout-simple';
85
153
 
86
154
  @Component({
87
155
  selector: "app-demo",
88
156
  standalone: true,
89
- imports: [...HlmButtonImports],
157
+ imports: [EgLayoutSimple, ...HlmButtonImports],
90
158
  template: \`
91
- <eg-layout-simple [menuItems]="items">
159
+ <eg-layout-simple brandName="My workspace" [primaryNavigation]="items">
92
160
  <button hlmBtn variant="primary">Click</button>
93
161
  </eg-layout-simple>
94
162
  \`,
@@ -98,6 +166,55 @@ export class DemoComponent {
98
166
  }
99
167
  ```
100
168
 
169
+ ## Date picker values
170
+
171
+ `hlm-date-picker` emits a native JS `Date` (or `null` when cleared) via the `dateChange` output. Read it in the
172
+ controller with `(dateChange)`, a template ref (`picker.value()`), or a form binding (`ngModel`/`formControlName`,
173
+ the picker is a `ControlValueAccessor`):
174
+
175
+ ```html
176
+ <hlm-date-picker (dateChange)="onDate($event)">
177
+ <hlm-date-picker-input placeholder="Pick a date" />
178
+ </hlm-date-picker>
179
+ ```
180
+
181
+ ```ts
182
+ onDate(date: Date | null) {
183
+ // date is a JS Date, e.g. 2026-09-23T00:00:00 local time (or null on clear)
184
+ }
185
+ ```
186
+
187
+ Unlike the React `FormDatePicker` (which normalizes to local midnight), the Angular picker passes dates through
188
+ untouched by default: calendar clicks usually arrive at local midnight already, but dates typed into the input are
189
+ parsed with `new Date(value)`, where `"YYYY-MM-DD"` means UTC midnight — so the time portion can be non-zero. To
190
+ normalize every value reaching the controller to local midnight, provide a custom config (no library changes needed):
191
+
192
+ ```ts
193
+ import { provideHlmDatePickerConfig } from '@egose/shadcn-theme-ng/date-picker';
194
+
195
+ @Component({
196
+ // ...
197
+ providers: [
198
+ provideHlmDatePickerConfig({
199
+ // Strip the time portion, mirroring React's normalizeDate.
200
+ transformDate: (date: Date) => new Date(date.getFullYear(), date.getMonth(), date.getDate()),
201
+ // Parse typed "YYYY-MM-DD" as a local date instead of new Date(value) (UTC).
202
+ parseDate: (value: string) => {
203
+ const match = /^(\d{4})-(\d{2})-(\d{2})$/.exec(value);
204
+ if (!match) return null;
205
+ const date = new Date(+match[1], +match[2] - 1, +match[3]);
206
+ return isNaN(date.getTime()) ? null : date;
207
+ },
208
+ }),
209
+ ],
210
+ })
211
+ export class MyComponent {}
212
+ ```
213
+
214
+ `transformDate` runs on every path into the model (calendar selection, typed input, `writeValue`), so the controller
215
+ then always sees local-midnight dates. Related: the picker stays open after selection by default; add the
216
+ `autoCloseOnSelect` attribute (or set it in the same config) to close it on select.
217
+
101
218
  ## Working example
102
219
 
103
220
  A complete Angular consumer app lives at [`@examples/standard`](https://github.com/egose/shadcn-theme/tree/main/packages/angular/@examples/standard) — see its `src/app/...` for real usage of `@egose/shadcn-theme-ng/button`, `.../layout-simple`, `.../form-text-input`, `.../autocomplete`, `.../select`, `.../form-checkbox`, `.../sheet`, etc.
@@ -1,64 +1,406 @@
1
- # Accordion
1
+ # Accordion (`@egose/shadcn-theme-ng/accordion`)
2
2
 
3
- This project was generated using [Angular CLI](https://github.com/angular/angular-cli) version 20.2.0.
3
+ A collapsible content panel set in the shadcn/ui Accordion style. Each section pairs a clickable
4
+ trigger row with an expanding content region, so long option lists, FAQs, and settings groups stay
5
+ compact until the user opens them.
4
6
 
5
- ## Code scaffolding
7
+ The Angular implementation is a thin styling layer over the headless
8
+ [`BrnAccordion*` primitives from `@spartan-ng/brain/accordion`](https://www.spartan-ng.com/):
9
+ `HlmAccordion` / `HlmAccordionItem` / `HlmAccordionTrigger` / `HlmAccordionContent` compose
10
+ `BrnAccordion` / `BrnAccordionItem` / `BrnAccordionTrigger` / `BrnAccordionContent` via
11
+ `hostDirectives` (or inheritance for the content), adding shadcn spacing, borders, typography, and
12
+ `class` merging through `hlm()` from `@egose/shadcn-theme-ng/utils`. `HlmAccordionIcon` is a
13
+ companion directive that styles an `ng-icon` (chevron-down) placed inside a trigger.
6
14
 
7
- Angular CLI includes powerful code scaffolding tools. To generate a new component, run:
15
+ > **Ships as:** `@egose/shadcn-theme-ng/accordion` and `@egose/shadcn-theme-ng-tw/accordion`
16
+ > (the `tw:`-prefixed Tailwind variant). Both expose the identical TypeScript surface; only the
17
+ > emitted Tailwind class strings differ. See the [package README](../../README.md) for install
18
+ > steps, peer dependencies, and Tailwind setup. Do not publish this project directory independently.
19
+
20
+ ## Installation
8
21
 
9
22
  ```bash
10
- ng generate component component-name
23
+ # Plain Tailwind (no prefix)
24
+ npm install @egose/shadcn-theme-ng
25
+
26
+ # tw:-prefixed Tailwind variant
27
+ npm install @egose/shadcn-theme-ng-tw
11
28
  ```
12
29
 
13
- For a complete list of available schematics (such as `components`, `directives`, or `pipes`), run:
30
+ Peer dependencies (Angular, `@spartan-ng/brain`, `@ng-icons/*`, `rxjs`, …) are documented in the
31
+ [package README](../../README.md#peer-dependencies). This subpath additionally relies at runtime on
32
+ `@egose/shadcn-theme-ng/utils` (`hlm()`), `@egose/shadcn-theme-ng/icon` (`provideHlmIconConfig`),
33
+ and `@ng-icons/lucide` (`lucideChevronDown`) for the icon directive.
14
34
 
15
- ```bash
16
- ng generate --help
35
+ ## Imports
36
+
37
+ All symbols are exported from the subpath root (`projects/accordion/src/public-api.ts`):
38
+
39
+ ```ts
40
+ import {
41
+ HlmAccordion,
42
+ HlmAccordionItem,
43
+ HlmAccordionTrigger,
44
+ HlmAccordionContent,
45
+ HlmAccordionIcon,
46
+ HlmAccordionImports,
47
+ HlmAccordionModule,
48
+ } from '@egose/shadcn-theme-ng/accordion';
49
+ // tw variant: replace with '@egose/shadcn-theme-ng-tw/accordion'
17
50
  ```
18
51
 
19
- ## Building
52
+ Standalone component — spread the `*Imports` array:
20
53
 
21
- To build the library, run:
54
+ ```ts
55
+ import { Component } from '@angular/core';
56
+ import { HlmAccordionImports } from '@egose/shadcn-theme-ng/accordion';
22
57
 
23
- ```bash
24
- ng build accordion
58
+ @Component({
59
+ selector: 'app-demo',
60
+ standalone: true,
61
+ imports: [...HlmAccordionImports],
62
+ template: `...`,
63
+ })
64
+ export class DemoComponent {}
65
+ ```
66
+
67
+ NgModule-based consumer — import the module:
68
+
69
+ ```ts
70
+ import { NgModule } from '@angular/core';
71
+ import { HlmAccordionModule } from '@egose/shadcn-theme-ng/accordion';
72
+
73
+ @NgModule({ imports: [HlmAccordionModule] })
74
+ export class DemoModule {}
25
75
  ```
26
76
 
27
- This command will compile your project, and the build artifacts will be placed in the `dist/` directory.
77
+ ## Anatomy / Structure
28
78
 
29
- ### Publishing the Library
79
+ ```html
80
+ <!-- hlm-accordion OR any element with hlmAccordion -->
81
+ <hlm-accordion type="single" orientation="vertical">
82
+ <!-- hlm-accordion-item OR [hlmAccordionItem] OR brn-accordion-item[hlm] -->
83
+ <hlm-accordion-item>
84
+ <!-- any element with hlmAccordionTrigger -->
85
+ <button hlmAccordionTrigger>
86
+ Section title
87
+ <!-- chevron icon (either attribute spelling works) -->
88
+ <ng-icon hlmAccIcon name="lucideChevronDown" />
89
+ </button>
90
+ <!-- content element -->
91
+ <hlm-accordion-content>
92
+ <p>Collapsible body.</p>
93
+ </hlm-accordion-content>
94
+ </hlm-accordion-item>
95
+ </hlm-accordion>
96
+ ```
30
97
 
31
- Once the project is built, you can publish your library by following these steps:
98
+ Real selectors (from source):
32
99
 
33
- 1. Navigate to the `dist` directory:
100
+ | Class | Selector(s) | Kind |
101
+ | --------------------- | ----------------------------------------------------------------- | --------- |
102
+ | `HlmAccordion` | `[hlmAccordion], hlm-accordion` | Directive |
103
+ | `HlmAccordionItem` | `[hlmAccordionItem], brn-accordion-item[hlm], hlm-accordion-item` | Directive |
104
+ | `HlmAccordionTrigger` | `[hlmAccordionTrigger]` | Directive |
105
+ | `HlmAccordionContent` | `hlm-accordion-content` | Component |
106
+ | `HlmAccordionIcon` | `ng-icon[egAccordionIcon], ng-icon[hlmAccIcon]` | Directive |
34
107
 
35
- ```bash
36
- cd dist/accordion
37
- ```
108
+ ## API reference
38
109
 
39
- 2. Run the `npm publish` command to publish your library to the npm registry:
40
- ```bash
41
- npm publish
42
- ```
110
+ ### `HlmAccordion` — `[hlmAccordion], hlm-accordion`
43
111
 
44
- ## Running unit tests
112
+ Thin directive wrapper around `BrnAccordion` (inputs forwarded via `hostDirectives`).
45
113
 
46
- To execute unit tests with the [Karma](https://karma-runner.github.io) test runner, use the following command:
114
+ | Input | Type | Default | Description |
115
+ | ------------- | --------------------------- | --------------- | --------------------------------------------------------------------------- |
116
+ | `type` | forwarded to `BrnAccordion` | (brain default) | `'single'` or `'multiple'` open-item behavior. |
117
+ | `orientation` | forwarded to `BrnAccordion` | (brain default) | `'horizontal'` renders the root as `flex-row`, anything else as `flex-col`. |
118
+ | `class` | `ClassValue` | `''` | Extra classes merged via `hlm()`. |
47
119
 
48
- ```bash
49
- ng test
120
+ ### `HlmAccordionItem` — `[hlmAccordionItem], brn-accordion-item[hlm], hlm-accordion-item`
121
+
122
+ Thin wrapper around `BrnAccordionItem`.
123
+
124
+ | Input | Type | Default | Description |
125
+ | ---------- | ------------------------------- | ------- | ----------------------------------------- |
126
+ | `isOpened` | forwarded to `BrnAccordionItem` | — | Whether this item starts/sets open state. |
127
+ | `class` | `ClassValue` | `''` | Extra classes merged via `hlm()`. |
128
+
129
+ ### `HlmAccordionTrigger` — `[hlmAccordionTrigger]`
130
+
131
+ Thin wrapper around `BrnAccordionTrigger` (no extra inputs — the whole `BrnAccordionTrigger`
132
+ surface is inherited through `hostDirectives`).
133
+
134
+ | Input | Type | Default | Description |
135
+ | ------- | ------------ | ------- | --------------------------------- |
136
+ | `class` | `ClassValue` | `''` | Extra classes merged via `hlm()`. |
137
+
138
+ ### `HlmAccordionContent` — `hlm-accordion-content`
139
+
140
+ Component **extending** `BrnAccordionContent`, so the `state()` signal (`'open' | 'closed'`) and
141
+ all brain behavior are inherited. The open state switches the host between
142
+ `grid-rows-[1fr]` and `hidden`; an inner `div[attr.inert]` keeps closed content out of the
143
+ tab order.
144
+
145
+ | Input | Type | Default | Description |
146
+ | ------- | ------------ | ------- | --------------------------------- |
147
+ | `class` | `ClassValue` | `''` | Extra classes merged via `hlm()`. |
148
+
149
+ ### `HlmAccordionIcon` — `ng-icon[egAccordionIcon], ng-icon[hlmAccIcon]`
150
+
151
+ Styling directive for the chevron `ng-icon` inside a trigger. It registers
152
+ `provideIcons({ lucideChevronDown })` and `provideHlmIconConfig({ size: 'sm' })`, and applies the
153
+ muted, small, animated sizing classes.
154
+
155
+ | Input | Type | Default | Description |
156
+ | ------- | ------------ | ------- | --------------------------------- |
157
+ | `class` | `ClassValue` | `''` | Extra classes merged via `hlm()`. |
158
+
159
+ > **Selector quirk (read from source):** the trigger stylesheet contains a
160
+ > `[&[data-state=open]>[egAccIcon]]:rotate-180` rule, but the icon directive itself matches
161
+ > `egAccordionIcon` / `hlmAccIcon`. If you want the chevron to rotate automatically on open, add a
162
+ > plain `egAccIcon` attribute to the icon element alongside the directive attribute
163
+ > (see the rotation example below).
164
+
165
+ ## Examples
166
+
167
+ ### 1. Basic single accordion
168
+
169
+ ```ts
170
+ import { Component } from '@angular/core';
171
+ import { HlmAccordionImports } from '@egose/shadcn-theme-ng/accordion';
172
+
173
+ @Component({
174
+ selector: 'app-accordion-basic',
175
+ standalone: true,
176
+ imports: [...HlmAccordionImports],
177
+ template: `
178
+ <hlm-accordion type="single">
179
+ <hlm-accordion-item>
180
+ <button hlmAccordionTrigger>
181
+ Is it accessible?
182
+ <ng-icon hlmAccIcon name="lucideChevronDown" />
183
+ </button>
184
+ <hlm-accordion-content>
185
+ <p>Yes. Triggers are real buttons and closed panels are inert.</p>
186
+ </hlm-accordion-content>
187
+ </hlm-accordion-item>
188
+ <hlm-accordion-item>
189
+ <button hlmAccordionTrigger>
190
+ Is it styled?
191
+ <ng-icon hlmAccIcon name="lucideChevronDown" />
192
+ </button>
193
+ <hlm-accordion-content>
194
+ <p>Yes. It follows the shadcn/ui accordion look.</p>
195
+ </hlm-accordion-content>
196
+ </hlm-accordion-item>
197
+ </hlm-accordion>
198
+ `,
199
+ })
200
+ export class AccordionBasicComponent {}
201
+ ```
202
+
203
+ ```html
204
+ <app-accordion-basic />
50
205
  ```
51
206
 
52
- ## Running end-to-end tests
207
+ ### 2. Multiple open panels + attribute selectors on native elements
53
208
 
54
- For end-to-end (e2e) testing, run:
209
+ `HlmAccordion` also works as an attribute on a `div`, and items accept the long
210
+ `brn-accordion-item[hlm]` spelling for interop with raw brain templates.
55
211
 
56
- ```bash
57
- ng e2e
212
+ ```ts
213
+ import { Component } from '@angular/core';
214
+ import { HlmAccordionImports } from '@egose/shadcn-theme-ng/accordion';
215
+
216
+ @Component({
217
+ selector: 'app-accordion-multiple',
218
+ standalone: true,
219
+ imports: [...HlmAccordionImports],
220
+ template: `
221
+ <div hlmAccordion type="multiple">
222
+ <div hlmAccordionItem>
223
+ <button hlmAccordionTrigger>
224
+ Shipping
225
+ <ng-icon egAccordionIcon name="lucideChevronDown" />
226
+ </button>
227
+ <hlm-accordion-content><p>Ships worldwide.</p></hlm-accordion-content>
228
+ </div>
229
+ <div hlmAccordionItem>
230
+ <button hlmAccordionTrigger>
231
+ Returns
232
+ <ng-icon egAccordionIcon name="lucideChevronDown" />
233
+ </button>
234
+ <hlm-accordion-content><p>30-day returns.</p></hlm-accordion-content>
235
+ </div>
236
+ </div>
237
+ `,
238
+ })
239
+ export class AccordionMultipleComponent {}
240
+ ```
241
+
242
+ ### 3. Pre-opened item via `isOpened`
243
+
244
+ ```ts
245
+ import { Component } from '@angular/core';
246
+ import { HlmAccordionImports } from '@egose/shadcn-theme-ng/accordion';
247
+
248
+ @Component({
249
+ selector: 'app-accordion-open',
250
+ standalone: true,
251
+ imports: [...HlmAccordionImports],
252
+ template: `
253
+ <hlm-accordion type="single">
254
+ <hlm-accordion-item [isOpened]="true">
255
+ <button hlmAccordionTrigger>
256
+ Open by default
257
+ <ng-icon hlmAccIcon name="lucideChevronDown" />
258
+ </button>
259
+ <hlm-accordion-content>
260
+ <p>This panel renders expanded on first paint.</p>
261
+ </hlm-accordion-content>
262
+ </hlm-accordion-item>
263
+ <hlm-accordion-item>
264
+ <button hlmAccordionTrigger>
265
+ Closed by default
266
+ <ng-icon hlmAccIcon name="lucideChevronDown" />
267
+ </button>
268
+ <hlm-accordion-content><p>Opens on click.</p></hlm-accordion-content>
269
+ </hlm-accordion-item>
270
+ </hlm-accordion>
271
+ `,
272
+ })
273
+ export class AccordionOpenComponent {}
274
+ ```
275
+
276
+ ### 4. Chevron that rotates on open
277
+
278
+ The stylesheet rotates a child carrying a bare `egAccIcon` attribute when the trigger reports
279
+ `data-state="open"`. Combine it with the icon directive so you keep both the sizing and the
280
+ rotation:
281
+
282
+ ```ts
283
+ import { Component } from '@angular/core';
284
+ import { HlmAccordionImports } from '@egose/shadcn-theme-ng/accordion';
285
+
286
+ @Component({
287
+ selector: 'app-accordion-rotate',
288
+ standalone: true,
289
+ imports: [...HlmAccordionImports],
290
+ template: `
291
+ <hlm-accordion type="single">
292
+ @for (faq of faqs; track faq.q) {
293
+ <hlm-accordion-item>
294
+ <button hlmAccordionTrigger>
295
+ {{ faq.q }}
296
+ <ng-icon hlmAccIcon egAccIcon name="lucideChevronDown" />
297
+ </button>
298
+ <hlm-accordion-content>
299
+ <p>{{ faq.a }}</p>
300
+ </hlm-accordion-content>
301
+ </hlm-accordion-item>
302
+ }
303
+ </hlm-accordion>
304
+ `,
305
+ })
306
+ export class AccordionRotateComponent {
307
+ readonly faqs = [
308
+ { q: 'What is shadcn?', a: 'A set of re-usable UI patterns.' },
309
+ { q: 'What is spartan-ng?', a: 'Headless Angular primitives (brain) plus styled (helm) components.' },
310
+ ];
311
+ }
58
312
  ```
59
313
 
60
- Angular CLI does not come with an end-to-end testing framework by default. You can choose one that suits your needs.
314
+ ### 5. Data-driven FAQ with custom classes
315
+
316
+ Every piece accepts a `class` input merged through `hlm()`, so per-item tweaks compose cleanly:
317
+
318
+ ```ts
319
+ import { Component, signal } from '@angular/core';
320
+ import { HlmAccordionImports } from '@egose/shadcn-theme-ng/accordion';
321
+
322
+ @Component({
323
+ selector: 'app-accordion-faq',
324
+ standalone: true,
325
+ imports: [...HlmAccordionImports],
326
+ template: `
327
+ <hlm-accordion type="single" class="tw:rounded-lg tw:border tw:px-4">
328
+ @for (faq of faqs(); track faq.q) {
329
+ <hlm-accordion-item class="tw:last:border-b-0">
330
+ <button hlmAccordionTrigger class="tw:text-base">
331
+ {{ faq.q }}
332
+ <ng-icon hlmAccIcon name="lucideChevronDown" />
333
+ </button>
334
+ <hlm-accordion-content class="tw:text-muted-foreground">
335
+ <p>{{ faq.a }}</p>
336
+ @if (faq.link) {
337
+ <a class="tw:underline" [href]="faq.link">Learn more</a>
338
+ }
339
+ </hlm-accordion-content>
340
+ </hlm-accordion-item>
341
+ }
342
+ </hlm-accordion>
343
+ `,
344
+ })
345
+ export class AccordionFaqComponent {
346
+ readonly faqs = signal([
347
+ { q: 'How do I install?', a: 'npm install @egose/shadcn-theme-ng', link: '' },
348
+ { q: 'Which Tailwind setup?', a: 'Pick the plain or tw: variant.', link: '' },
349
+ ]);
350
+ }
351
+ ```
352
+
353
+ ### 6. Horizontal orientation
354
+
355
+ `HlmAccordion` reads the brain `orientation()` signal: `'horizontal'` switches the root to
356
+ `flex-row`, anything else stays `flex-col`.
357
+
358
+ ```ts
359
+ import { Component } from '@angular/core';
360
+ import { HlmAccordionImports } from '@egose/shadcn-theme-ng/accordion';
361
+
362
+ @Component({
363
+ selector: 'app-accordion-horizontal',
364
+ standalone: true,
365
+ imports: [...HlmAccordionImports],
366
+ template: `
367
+ <hlm-accordion type="multiple" orientation="horizontal" class="tw:gap-2">
368
+ <hlm-accordion-item class="tw:border tw:rounded-md tw:px-3">
369
+ <button hlmAccordionTrigger>A <ng-icon hlmAccIcon name="lucideChevronDown" /></button>
370
+ <hlm-accordion-content><p>First column.</p></hlm-accordion-content>
371
+ </hlm-accordion-item>
372
+ <hlm-accordion-item class="tw:border tw:rounded-md tw:px-3">
373
+ <button hlmAccordionTrigger>B <ng-icon hlmAccIcon name="lucideChevronDown" /></button>
374
+ <hlm-accordion-content><p>Second column.</p></hlm-accordion-content>
375
+ </hlm-accordion-item>
376
+ </hlm-accordion>
377
+ `,
378
+ })
379
+ export class AccordionHorizontalComponent {}
380
+ ```
381
+
382
+ ## Accessibility notes
383
+
384
+ - Triggers are native `<button>` elements enhanced by `BrnAccordionTrigger`: keyboard focus,
385
+ `Enter`/`Space` activation, and arrow-key navigation between items come from the brain primitive.
386
+ - `HlmAccordionContent` marks its inner wrapper `inert` while closed so hidden content is removed
387
+ from the tab order and assistive-technology traversal.
388
+ - The icon is decorative (`pointer-events-none`); keep the trigger label as real text so screen
389
+ readers announce the section name. If you add `sr-only` helper text, put it inside the trigger,
390
+ not the icon.
391
+ - `HlmAccordionIcon` sets the icon size through `provideHlmIconConfig({ size: 'sm' })` — overriding
392
+ the global icon config locally, so surrounding icons are unaffected.
393
+
394
+ ## Theming / CSS variables
395
+
396
+ Styling is class-based (`hlm()` + Tailwind tokens such as `border-border`, `text-muted-foreground`,
397
+ `ring-ring/50`); no component-specific CSS variables are declared. Pass `class` to any piece to
398
+ extend the look, and configure the shadcn theme tokens globally as described in the
399
+ [package README](../../README.md).
61
400
 
62
- ## Additional Resources
401
+ ## Related subpaths
63
402
 
64
- For more information on using the Angular CLI, including detailed command references, visit the [Angular CLI Overview and Command Reference](https://angular.dev/tools/cli) page.
403
+ - `@egose/shadcn-theme-ng/icon` — `provideHlmIconConfig`, `HlmIcon` (icon sizing used by the trigger icon)
404
+ - `@egose/shadcn-theme-ng/collapsible` — single-region expand/collapse primitive
405
+ - `@egose/shadcn-theme-ng/separator` — dividers between accordion items
406
+ - `@egose/shadcn-theme-ng/typography` — prose styling for rich accordion bodies