@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/button/README.md CHANGED
@@ -1,64 +1,483 @@
1
- # Button
1
+ # Button (`@egose/shadcn-theme-ng/button`)
2
2
 
3
- This project was generated using [Angular CLI](https://github.com/angular/angular-cli) version 20.2.0.
3
+ The shadcn/ui Button: a consistently styled clickable control for actions, links-that-look-like
4
+ buttons, and form submits — with tones, sizes, outline appearances, icon slots, and a built-in
5
+ loading spinner.
4
6
 
5
- ## Code scaffolding
7
+ This subpath exports **two** controls over the headless `BrnButton` from
8
+ `@spartan-ng/brain/button`:
6
9
 
7
- Angular CLI includes powerful code scaffolding tools. To generate a new component, run:
10
+ - `HlmButton` (`button[hlmButton], a[hlmButton]`) — the full-featured component: `variant`,
11
+ `size`, `appearance`, `loading` (overlay spinner via `HlmSpinner`), `icon` template + position,
12
+ `disabled`, `type`, and `class` merging through `buttonVariants` (`cva`) + `hlm()`.
13
+ - `HlmBtn` (`button[hlmBtn], a[hlmBtn]`, `exportAs: hlmBtn`) — a thin `BrnButton` wrapper with only
14
+ `variant` / `size` / `type` (defaults injectable via `provideBrnButtonConfig`). Used internally
15
+ by footer-style consumers (e.g. `alert-dialog`) and handy when you need the tones without the
16
+ spinner/icon machinery.
17
+
18
+ > **Ships as:** `@egose/shadcn-theme-ng/button` and `@egose/shadcn-theme-ng-tw/button`
19
+ > (the `tw:`-prefixed Tailwind variant). Both expose the identical TypeScript surface; only the
20
+ > emitted Tailwind class strings differ. See the [package README](../../README.md) for install
21
+ > steps, peer dependencies, and Tailwind setup. Do not publish this project directory independently.
22
+
23
+ ## Installation
8
24
 
9
25
  ```bash
10
- ng generate component component-name
26
+ # Plain Tailwind (no prefix)
27
+ npm install @egose/shadcn-theme-ng
28
+
29
+ # tw:-prefixed Tailwind variant
30
+ npm install @egose/shadcn-theme-ng-tw
11
31
  ```
12
32
 
13
- For a complete list of available schematics (such as `components`, `directives`, or `pipes`), run:
33
+ Peer dependencies (Angular, `@spartan-ng/brain`, `@ng-icons/*`, `rxjs`, …) are documented in the
34
+ [package README](../../README.md#peer-dependencies). This subpath additionally relies at runtime on
35
+ `@egose/shadcn-theme-ng/utils` (`hlm()`) and `@egose/shadcn-theme-ng/spinner` (`HlmSpinner`,
36
+ used by the `HlmButton` loading state).
14
37
 
15
- ```bash
16
- ng generate --help
38
+ ## Imports
39
+
40
+ All symbols are exported from the subpath root (`projects/button/src/public-api.ts`):
41
+
42
+ ```ts
43
+ import {
44
+ HlmButton,
45
+ HlmBtn,
46
+ buttonVariants,
47
+ provideBrnButtonConfig,
48
+ injectBrnButtonConfig,
49
+ HlmButtonImports, // [HlmButton, HlmBtn]
50
+ HlmButtonModule,
51
+ type ButtonVariants,
52
+ type VariantType,
53
+ type SizeType,
54
+ type AppearanceType,
55
+ type BrnButtonConfig,
56
+ } from '@egose/shadcn-theme-ng/button';
57
+ // tw variant: replace with '@egose/shadcn-theme-ng-tw/button'
17
58
  ```
18
59
 
19
- ## Building
60
+ Standalone component — spread the `*Imports` array (both controls):
20
61
 
21
- To build the library, run:
62
+ ```ts
63
+ import { Component } from '@angular/core';
64
+ import { HlmButtonImports } from '@egose/shadcn-theme-ng/button';
22
65
 
23
- ```bash
24
- ng build button
66
+ @Component({
67
+ selector: 'app-demo',
68
+ standalone: true,
69
+ imports: [...HlmButtonImports],
70
+ template: `...`,
71
+ })
72
+ export class DemoComponent {}
25
73
  ```
26
74
 
27
- This command will compile your project, and the build artifacts will be placed in the `dist/` directory.
75
+ NgModule-based consumer — import the module:
28
76
 
29
- ### Publishing the Library
77
+ ```ts
78
+ import { NgModule } from '@angular/core';
79
+ import { HlmButtonModule } from '@egose/shadcn-theme-ng/button';
30
80
 
31
- Once the project is built, you can publish your library by following these steps:
81
+ @NgModule({ imports: [HlmButtonModule] })
82
+ export class DemoModule {}
83
+ ```
32
84
 
33
- 1. Navigate to the `dist` directory:
85
+ Global defaults — provide a `BrnButtonConfig` once (consumed by `HlmBtn`):
34
86
 
35
- ```bash
36
- cd dist/button
37
- ```
87
+ ```ts
88
+ import { Component } from '@angular/core';
89
+ import { HlmButtonImports, provideBrnButtonConfig } from '@egose/shadcn-theme-ng/button';
38
90
 
39
- 2. Run the `npm publish` command to publish your library to the npm registry:
40
- ```bash
41
- npm publish
42
- ```
91
+ @Component({
92
+ selector: 'app-shell',
93
+ standalone: true,
94
+ imports: [...HlmButtonImports],
95
+ providers: [provideBrnButtonConfig({ variant: 'secondary', size: 'sm' })],
96
+ template: `...`,
97
+ })
98
+ export class ShellComponent {}
99
+ ```
43
100
 
44
- ## Running unit tests
101
+ ## Anatomy / Structure
45
102
 
46
- To execute unit tests with the [Karma](https://karma-runner.github.io) test runner, use the following command:
103
+ ```html
104
+ <!-- full-featured -->
105
+ <button hlmButton variant="primary" size="default" appearance="solid">Save</button>
106
+ <a hlmButton variant="outline" href="/docs">Docs</a>
47
107
 
48
- ```bash
49
- ng test
108
+ <!-- thin wrapper -->
109
+ <button hlmBtn variant="ghost" size="sm">Cancel</button>
50
110
  ```
51
111
 
52
- ## Running end-to-end tests
112
+ Real selectors (from source):
53
113
 
54
- For end-to-end (e2e) testing, run:
114
+ | Class | Selector(s) | Kind |
115
+ | ----------- | ------------------------------------------------ | --------- |
116
+ | `HlmButton` | `button[hlmButton], a[hlmButton]` | Component |
117
+ | `HlmBtn` | `button[hlmBtn], a[hlmBtn]` (`exportAs: hlmBtn`) | Directive |
55
118
 
56
- ```bash
57
- ng e2e
119
+ `HlmButton` loading template (from source): when `loading()` is true, the projected content is
120
+ kept invisible for sizing while an absolutely centered `<hlm-spinner>` overlays it; otherwise the
121
+ content renders in a flex row with the optional `icon()` template on the `left`/`right`.
122
+
123
+ ## API reference
124
+
125
+ ### `HlmButton` — `button[hlmButton], a[hlmButton]`
126
+
127
+ | Input | Type | Default | Description |
128
+ | ------------------------------ | ----------------------------------- | ----------- | -------------------------------------------------------------------------------------------------------------------------- |
129
+ | `variant` | `VariantType` | `'primary'` | Semantic color tone, plus legacy `default`, `outline`, `link`, and `ghost` variants (15 values). |
130
+ | `size` | `SizeType` | `'default'` | Height/padding scale (13 values, see below). |
131
+ | `appearance` | `AppearanceType` | `'solid'` | `'solid'`, `'outline'` (theme background + tone border/text), `'outline-filled'` (fills on hover), `'ghost'`, or `'link'`. |
132
+ | `loading` | `boolean` | `false` | Shows the spinner overlay; sets `aria-busy`, forces `disabled`, adds `pointer-events-none`. |
133
+ | `icon` | `TemplateRef<unknown> \| undefined` | `undefined` | Icon template rendered beside the label. |
134
+ | `iconPosition` | `'left' \| 'right'` | `'left'` | Which side the `icon()` renders on. |
135
+ | `disabled` | `boolean` | `false` | Disables the control (also forwarded to `BrnButton`). |
136
+ | `type` | `'button' \| 'submit' \| 'reset'` | `'button'` | Native button type (reflected as `type` attr). |
137
+ | `class` (alias of `userClass`) | `ClassValue` | `''` | Extra classes merged via `hlm()`. |
138
+ | `spinnerUserClass` | `ClassValue` | `''` | Extra classes for the loading `<hlm-spinner>` (defaults to the button's current text color). |
139
+
140
+ | Method | Signature | Description |
141
+ | ---------- | --------------------------------- | ----------------------------------- |
142
+ | `setClass` | `setClass(classes: string): void` | Imperatively appends extra classes. |
143
+
144
+ `variant` values: `default` · `primary` · `secondary` · `success` · `warning` · `danger` ·
145
+ `info` · `light` · `dark` · `accent` · `destructive` · `muted` · `outline` · `link` · `ghost`.
146
+
147
+ `size` values: `xs` · `sm` · `default` · `lg` · `icon` · `icon-xs` · `icon-sm` · `icon-lg` ·
148
+ `compact-xs` · `compact-sm` · `compact-default` · `compact-lg` · `compact-icon`.
149
+
150
+ `appearance` values: `solid` · `outline` · `outline-filled` · `ghost` · `link`.
151
+
152
+ Prefer a semantic `variant` with an independent `appearance`, for example
153
+ `variant="success" appearance="ghost"` or `variant="danger" appearance="link"`.
154
+ `ghost` is transparent with a subtle tone-colored hover background; `link` is transparent
155
+ with an underline on hover. Both have no border or shadow.
156
+ Legacy `variant="outline"`, `variant="link"`, and `variant="ghost"` remain supported;
157
+ `default` remains an alias for the primary color. The legacy ghost variant retains its
158
+ light-colored hover treatment.
159
+
160
+ ### `HlmBtn` — `button[hlmBtn], a[hlmBtn]`
161
+
162
+ Thin wrapper: only `variant` / `size` / `type` (+ `class`), no `appearance`, `loading`, or icon
163
+ support. Its `variant`/`size` defaults come from `injectBrnButtonConfig()` (global default
164
+ `{ variant: 'default', size: 'default' }`, overridable per subtree with
165
+ `provideBrnButtonConfig()`).
166
+
167
+ | Input | Type | Default | Description |
168
+ | ------------------------------ | --------------------------------- | ----------------------------- | ------------------- |
169
+ | `variant` | `ButtonVariants['variant']` | injected config (`'default'`) | Tone. |
170
+ | `size` | `ButtonVariants['size']` | injected config (`'default'`) | Size. |
171
+ | `type` | `'button' \| 'submit' \| 'reset'` | `'button'` | Native button type. |
172
+ | `class` (alias of `userClass`) | `ClassValue` | `''` | Extra classes. |
173
+
174
+ | Method | Signature | Description |
175
+ | ---------- | --------------------------------- | ----------------------------------- |
176
+ | `setClass` | `setClass(classes: string): void` | Imperatively appends extra classes. |
177
+
178
+ ### Config helpers (`button.token.ts`)
179
+
180
+ | Symbol | Signature | Description |
181
+ | ------------------------ | ----------------------------------------------------- | ------------------------------------------------------------ |
182
+ | `BrnButtonConfig` | `{ variant; size }` | Shape of the button defaults object. |
183
+ | `provideBrnButtonConfig` | `(config: Partial<BrnButtonConfig>) => ValueProvider` | Provide subtree defaults for `HlmBtn`. |
184
+ | `injectBrnButtonConfig` | `() => BrnButtonConfig` | Read the effective config (falls back to built-in defaults). |
185
+
186
+ Exported styling/types: `buttonVariants` (`cva` table — reuse for custom hosts), `ButtonVariants`,
187
+ `VariantType`, `SizeType`, `AppearanceType`.
188
+
189
+ ## Examples
190
+
191
+ ### 1. Basic usage
192
+
193
+ ```ts
194
+ import { Component } from '@angular/core';
195
+ import { HlmButtonImports } from '@egose/shadcn-theme-ng/button';
196
+
197
+ @Component({
198
+ selector: 'app-button-basic',
199
+ standalone: true,
200
+ imports: [...HlmButtonImports],
201
+ template: `
202
+ <div class="tw:flex tw:gap-2">
203
+ <button hlmButton>Primary</button>
204
+ <button hlmBtn variant="secondary">Thin wrapper</button>
205
+ <a hlmButton variant="outline" href="/docs">Docs link</a>
206
+ </div>
207
+ `,
208
+ })
209
+ export class ButtonBasicComponent {}
210
+ ```
211
+
212
+ ```html
213
+ <app-button-basic />
214
+ ```
215
+
216
+ ### 2. All variants and sizes
217
+
218
+ ```ts
219
+ import { Component } from '@angular/core';
220
+ import { HlmButton, type VariantType, type SizeType } from '@egose/shadcn-theme-ng/button';
221
+
222
+ @Component({
223
+ selector: 'app-button-matrix',
224
+ standalone: true,
225
+ imports: [HlmButton],
226
+ template: `
227
+ <div class="tw:flex tw:flex-wrap tw:gap-2">
228
+ @for (v of variants; track v) {
229
+ <button hlmButton [variant]="v">{{ v }}</button>
230
+ }
231
+ </div>
232
+ <div class="tw:mt-4 tw:flex tw:flex-wrap tw:items-center tw:gap-2">
233
+ @for (s of sizes; track s) {
234
+ <button hlmButton variant="secondary" [size]="s">{{ s }}</button>
235
+ }
236
+ </div>
237
+ `,
238
+ })
239
+ export class ButtonMatrixComponent {
240
+ readonly variants: VariantType[] = [
241
+ 'default',
242
+ 'primary',
243
+ 'secondary',
244
+ 'success',
245
+ 'warning',
246
+ 'danger',
247
+ 'info',
248
+ 'light',
249
+ 'dark',
250
+ 'accent',
251
+ 'destructive',
252
+ 'muted',
253
+ 'outline',
254
+ 'link',
255
+ 'ghost',
256
+ ];
257
+ readonly sizes: SizeType[] = [
258
+ 'xs',
259
+ 'sm',
260
+ 'default',
261
+ 'lg',
262
+ 'icon',
263
+ 'compact-xs',
264
+ 'compact-sm',
265
+ 'compact-default',
266
+ 'compact-lg',
267
+ ];
268
+ }
269
+ ```
270
+
271
+ ### 3. Outline appearances + icon buttons
272
+
273
+ ```ts
274
+ import { Component } from '@angular/core';
275
+ import { NgIcon, provideIcons } from '@ng-icons/core';
276
+ import { lucidePlus, lucideTrash } from '@ng-icons/lucide';
277
+ import { HlmButton } from '@egose/shadcn-theme-ng/button';
278
+ import { HlmIcon } from '@egose/shadcn-theme-ng/icon';
279
+
280
+ @Component({
281
+ selector: 'app-button-appearance',
282
+ standalone: true,
283
+ imports: [HlmButton, NgIcon, HlmIcon],
284
+ providers: [provideIcons({ lucidePlus, lucideTrash })],
285
+ template: `
286
+ <div class="tw:flex tw:flex-wrap tw:items-center tw:gap-2">
287
+ <button hlmButton variant="success" appearance="outline">Outline</button>
288
+ <button hlmButton variant="destructive" appearance="outline-filled">Outline-filled (hover me)</button>
289
+ <button hlmButton variant="success" appearance="ghost">Ghost</button>
290
+ <button hlmButton variant="danger" appearance="link">Link appearance</button>
291
+ <button hlmButton size="icon" aria-label="Create">
292
+ <ng-icon hlm name="lucidePlus" />
293
+ </button>
294
+ <button hlmButton variant="destructive" size="icon-sm" aria-label="Delete">
295
+ <ng-icon hlm name="lucideTrash" size="sm" />
296
+ </button>
297
+ </div>
298
+ `,
299
+ })
300
+ export class ButtonAppearanceComponent {}
301
+ ```
302
+
303
+ ### 4. Loading state with `HlmButton` (async submit)
304
+
305
+ `loading` overlays a tone-matched spinner, keeps the button width stable, sets `aria-busy`, and
306
+ blocks interaction until done:
307
+
308
+ ```ts
309
+ import { Component, signal } from '@angular/core';
310
+ import { HlmButton } from '@egose/shadcn-theme-ng/button';
311
+
312
+ @Component({
313
+ selector: 'app-button-loading',
314
+ standalone: true,
315
+ imports: [HlmButton],
316
+ template: `
317
+ <form (ngSubmit)="submit()">
318
+ <button hlmButton type="submit" [loading]="saving()">Save changes</button>
319
+ <button hlmButton variant="ghost" type="button" [disabled]="saving()">Cancel</button>
320
+ </form>
321
+ `,
322
+ })
323
+ export class ButtonLoadingComponent {
324
+ readonly saving = signal(false);
325
+
326
+ async submit() {
327
+ this.saving.set(true);
328
+ try {
329
+ await fetch('/api/save', { method: 'POST' });
330
+ } finally {
331
+ this.saving.set(false);
332
+ }
333
+ }
334
+ }
58
335
  ```
59
336
 
60
- Angular CLI does not come with an end-to-end testing framework by default. You can choose one that suits your needs.
337
+ ### 5. Icon templates with `icon` / `iconPosition`
338
+
339
+ ```ts
340
+ import { Component } from '@angular/core';
341
+ import { NgIcon, provideIcons } from '@ng-icons/core';
342
+ import { lucideArrowLeft, lucideArrowRight } from '@ng-icons/lucide';
343
+ import { HlmButton } from '@egose/shadcn-theme-ng/button';
344
+
345
+ @Component({
346
+ selector: 'app-button-icons',
347
+ standalone: true,
348
+ imports: [HlmButton, NgIcon],
349
+ providers: [provideIcons({ lucideArrowLeft, lucideArrowRight })],
350
+ template: `
351
+ <ng-template #backIcon><ng-icon name="lucideArrowLeft" /></ng-template>
352
+ <ng-template #nextIcon><ng-icon name="lucideArrowRight" /></ng-template>
353
+
354
+ <div class="tw:flex tw:gap-2">
355
+ <button hlmButton variant="outline" [icon]="backIcon" iconPosition="left">Back</button>
356
+ <button hlmButton [icon]="nextIcon" iconPosition="right">Next</button>
357
+ </div>
358
+ `,
359
+ })
360
+ export class ButtonIconsComponent {}
361
+ ```
362
+
363
+ ### 6. Reactive form submit + global `HlmBtn` defaults
364
+
365
+ ```ts
366
+ import { Component } from '@angular/core';
367
+ import { FormControl, FormGroup, ReactiveFormsModule, Validators } from '@angular/forms';
368
+ import { HlmButtonImports, provideBrnButtonConfig } from '@egose/shadcn-theme-ng/button';
369
+
370
+ @Component({
371
+ selector: 'app-button-form',
372
+ standalone: true,
373
+ imports: [...HlmButtonImports, ReactiveFormsModule],
374
+ // Every hlmBtn in this subtree defaults to compact secondary unless overridden.
375
+ providers: [provideBrnButtonConfig({ variant: 'secondary', size: 'compact-default' })],
376
+ template: `
377
+ <form [formGroup]="form" (ngSubmit)="submit()" class="tw:flex tw:flex-col tw:gap-3">
378
+ <input formControlName="name" placeholder="Project name" />
379
+ <div class="tw:flex tw:gap-2">
380
+ <button hlmButton [disabled]="form.invalid || saving">Create project</button>
381
+ <button hlmBtn type="button" (click)="form.reset()">Reset</button>
382
+ </div>
383
+ </form>
384
+ `,
385
+ })
386
+ export class ButtonFormComponent {
387
+ readonly form = new FormGroup({ name: new FormControl('', { validators: Validators.required, nonNullable: true }) });
388
+ saving = false;
389
+
390
+ submit() {
391
+ if (this.form.invalid) return;
392
+ this.saving = true;
393
+ setTimeout(() => (this.saving = false), 800);
394
+ }
395
+ }
396
+ ```
397
+
398
+ ## Accessibility notes
399
+
400
+ - These are native `<button>` / `<a>` elements enhanced by `BrnButton`: keyboard focus,
401
+ `Enter`/`Space` activation, and `disabled` semantics work out of the box. Never render a
402
+ `div` with `hlmButton` — the selector only matches `button`/`a` for exactly this reason.
403
+ - `loading` sets `aria-busy="true"` and disables the control; announce completion with adjacent
404
+ text or a toast (see `.../sonner`) since the spinner itself is silent.
405
+ - Icon-only buttons (`size="icon*"`) **must** have an `aria-label`. Keep visible labels verb-led
406
+ and unique per context ("Delete project", not "Delete" × 5).
407
+ - `disabled` uses `pointer-events-none` + reduced opacity — pair disabled states with a visible
408
+ explanation (e.g. "Complete the required fields") rather than leaving users guessing.
409
+
410
+ ## Theming / CSS variables
411
+
412
+ Buttons use shared semantic Tailwind color tokens, so the consumer controls their palette in
413
+ global CSS. Define each tone and its `-foreground` partner: `primary`, `secondary`, `success`,
414
+ `warning`, `danger`, `info`, `light`, `dark`, `accent`, `destructive`, and `muted`. Also provide
415
+ `background` for outline surfaces and `ring` for keyboard focus.
416
+
417
+ For example, add these mappings to your Tailwind v4 stylesheet (alongside the package source
418
+ scan described in the package README):
419
+
420
+ ```css
421
+ @theme inline {
422
+ --color-primary: var(--primary);
423
+ --color-primary-foreground: var(--primary-foreground);
424
+ --color-success: var(--success);
425
+ --color-success-foreground: var(--success-foreground);
426
+ --color-background: hsl(var(--background));
427
+ --color-ring: hsl(var(--ring));
428
+ /* Map the remaining semantic tones in the same way. */
429
+ }
430
+
431
+ :root {
432
+ --primary: #228be6;
433
+ --primary-foreground: #ffffff;
434
+ --success: #28a745;
435
+ --success-foreground: #ffffff;
436
+ --background: 0 0% 100%;
437
+ --ring: 0 0% 3.9%;
438
+ }
439
+
440
+ .dark {
441
+ --primary: #74c0fc;
442
+ --primary-foreground: #102a43;
443
+ --success: #75b798;
444
+ --success-foreground: #0a3622;
445
+ --background: 0 0% 3.9%;
446
+ --ring: 0 0% 83.1%;
447
+ }
448
+
449
+ .brand-theme {
450
+ --primary: #7950f2;
451
+ --primary-foreground: #ffffff;
452
+ }
453
+ ```
454
+
455
+ The semantic palette variables above contain complete CSS colors; `background` and `ring`
456
+ use HSL channels with `hsl(...)` mappings. `@theme inline` ensures a `.dark` or `.brand-theme`
457
+ ancestor can override colors for just its subtree. The example app's `src/styles.css` supplies
458
+ the full light/dark palette. Keep the existing `prefix(tw)` import when using the `-tw` package;
459
+ the `@theme` token names stay unprefixed.
460
+
461
+ ```html
462
+ <section class="brand-theme">
463
+ <button hlmButton variant="primary" appearance="outline">Branded outline</button>
464
+ <button hlmButton variant="success" appearance="ghost">Save changes</button>
465
+ </section>
466
+ ```
467
+
468
+ Adding a CSS token such as `--color-brand` does **not** register `variant="brand"`;
469
+ variant names remain a fixed typed API. Customize an existing semantic token or supply
470
+ utility classes through `class` instead.
471
+
472
+ `class` overrides are merged after the variant/appearance styles; `setClass()` appends
473
+ imperative overrides. The loading spinner inherits the button's resolved text color, and
474
+ `spinnerUserClass` can override it. For custom hosts, use
475
+ `hlm(buttonVariants({ variant: 'success', appearance: 'outline' }), customClasses)`;
476
+ the shared variant function includes all appearance styles.
61
477
 
62
- ## Additional Resources
478
+ ## Related subpaths
63
479
 
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.
480
+ - `@egose/shadcn-theme-ng/spinner` — the loader rendered in the `loading` state
481
+ - `@egose/shadcn-theme-ng/badge` — counts/status chips composed inside buttons
482
+ - `@egose/shadcn-theme-ng/button-group` — joined button rows
483
+ - `@egose/shadcn-theme-ng/alert-dialog` — footer `hlmAlertDialogAction` / `hlmAlertDialogCancel` (built on `HlmBtn`)