@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
@@ -1,11 +1,513 @@
1
- # Combobox
1
+ # Combobox (`@egose/shadcn-theme-ng/combobox`)
2
2
 
3
- This project was generated using [Angular CLI](https://github.com/angular/angular-cli).
3
+ A filterable select / autocomplete-dropdown — the Angular port of shadcn/ui `Combobox`. Single mode (`HlmCombobox`) and multi mode (`HlmComboboxMultiple`) wrap `@spartan-ng/brain/combobox` + `@spartan-ng/brain/popover` host directives, with two anchor styles: a button-like `hlm-combobox-trigger` and an input-like `hlm-combobox-input` (or free-form `hlm-combobox-chips` + `hlm-combobox-chip` tag lists). The dropdown is built from `hlm-combobox-content` + `hlm-combobox-portal` + `hlm-combobox-list` + `hlm-combobox-item` + group/label/empty/status/separator/value-template primitives.
4
4
 
5
- ## Building
5
+ Ships as `@egose/shadcn-theme-ng/combobox` and `@egose/shadcn-theme-ng-tw/combobox` (the `tw:`-prefixed variant). See the [package README](../../README.md) for install, peer dependencies, and Tailwind setup. Do not publish this project directory independently — it is consumed via the published subpath only.
6
6
 
7
- To build the library, run:
7
+ ## Installation
8
8
 
9
9
  ```bash
10
- ng build combobox
10
+ # Plain Tailwind (no prefix):
11
+ npm install @egose/shadcn-theme-ng
12
+
13
+ # Or the tw:-prefixed variant:
14
+ npm install @egose/shadcn-theme-ng-tw
15
+ ```
16
+
17
+ Peers are listed in the [package README](../../README.md). This subpath declares `@angular/common`, `@angular/core`, and `@spartan-ng/brain` as peers (see `projects/combobox/package.json`).
18
+
19
+ ## Imports
20
+
21
+ ```ts
22
+ import {
23
+ HlmCombobox,
24
+ HlmComboboxMultiple,
25
+ HlmComboboxTrigger,
26
+ HlmComboboxInput,
27
+ HlmComboboxContent,
28
+ HlmComboboxPortal,
29
+ HlmComboboxList,
30
+ HlmComboboxItem,
31
+ HlmComboboxGroup,
32
+ HlmComboboxLabel,
33
+ HlmComboboxEmpty,
34
+ HlmComboboxStatus,
35
+ HlmComboboxSeparator,
36
+ HlmComboboxPlaceholder,
37
+ HlmComboboxValue,
38
+ HlmComboboxValues,
39
+ HlmComboboxValueTemplate,
40
+ HlmComboboxChips,
41
+ HlmComboboxChip,
42
+ HlmComboboxChipInput,
43
+ HlmComboboxImports,
44
+ HlmComboboxModule,
45
+ } from '@egose/shadcn-theme-ng/combobox';
46
+ // tw variant:
47
+ // import { ... } from '@egose/shadcn-theme-ng-tw/combobox';
48
+ ```
49
+
50
+ > `HlmComboboxChipRemove` (`button[hlmComboboxChipRemove]`) exists in source but is **not** exported from `public-api.ts` — it is rendered internally by `hlm-combobox-chip` when `showRemove` is true.
51
+
52
+ Standalone:
53
+
54
+ ```ts
55
+ import { Component } from '@angular/core';
56
+ import { HlmComboboxImports } from '@egose/shadcn-theme-ng/combobox';
57
+
58
+ @Component({
59
+ selector: 'app-demo',
60
+ standalone: true,
61
+ imports: [...HlmComboboxImports],
62
+ template: `...`,
63
+ })
64
+ export class DemoComponent {}
65
+ ```
66
+
67
+ NgModule:
68
+
69
+ ```ts
70
+ import { NgModule } from '@angular/core';
71
+ import { HlmComboboxModule } from '@egose/shadcn-theme-ng/combobox';
72
+
73
+ @NgModule({ imports: [HlmComboboxModule] })
74
+ export class DemoModule {}
75
+ ```
76
+
77
+ ## Anatomy / Structure
78
+
79
+ ```html
80
+ <!-- Single, button trigger -->
81
+ <hlm-combobox [value]="value" [search]="search" (valueChange)="value = $event" (searchChange)="search = $event">
82
+ <hlm-combobox-trigger>Select fruit…</hlm-combobox-trigger>
83
+ <hlm-combobox-content *hlmComboboxPortal>
84
+ <hlm-combobox-list>
85
+ <hlm-combobox-item value="apple">Apple</hlm-combobox-item>
86
+ <hlm-combobox-item value="banana">Banana</hlm-combobox-item>
87
+ </hlm-combobox-list>
88
+ <div hlmComboboxEmpty>No results.</div>
89
+ </hlm-combobox-content>
90
+ </hlm-combobox>
91
+
92
+ <!-- Single, input trigger with clear button -->
93
+ <hlm-combobox [value]="v" (valueChange)="v = $event">
94
+ <hlm-combobox-input placeholder="Search…" [showClear]="true" />
95
+ <hlm-combobox-content *hlmComboboxPortal>
96
+ <hlm-combobox-list>
97
+ <div hlmComboboxGroup>
98
+ <span hlmComboboxLabel>Fruits</span>
99
+ <hlm-combobox-item value="apple">Apple</hlm-combobox-item>
100
+ </div>
101
+ </hlm-combobox-list>
102
+ </hlm-combobox-content>
103
+ </hlm-combobox>
104
+
105
+ <!-- Multi, chips anchor -->
106
+ <hlm-combobox-multiple [value]="selected" (valueChange)="selected = $event">
107
+ <hlm-combobox-chips>
108
+ @for (v of selected; track v) {
109
+ <hlm-combobox-chip [value]="v">{{ v }}</hlm-combobox-chip>
110
+ }
111
+ <input hlmComboboxChipInput placeholder="Pick…" />
112
+ </hlm-combobox-chips>
113
+ <hlm-combobox-content *hlmComboboxPortal>
114
+ <hlm-combobox-list>
115
+ <hlm-combobox-item value="a">A</hlm-combobox-item>
116
+ </hlm-combobox-list>
117
+ </hlm-combobox-content>
118
+ </hlm-combobox-multiple>
119
+ ```
120
+
121
+ Real selectors:
122
+
123
+ | Class | Selector |
124
+ | -------------------------- | -------------------------------------------------------------- |
125
+ | `HlmCombobox` | `[hlmCombobox]`, `hlm-combobox` |
126
+ | `HlmComboboxMultiple` | `[hlmComboboxMultiple]`, `hlm-combobox-multiple` |
127
+ | `HlmComboboxTrigger` | `hlm-combobox-trigger` (element only) |
128
+ | `HlmComboboxInput` | `hlm-combobox-input` (element only) |
129
+ | `HlmComboboxItem` | `hlm-combobox-item` (element only) |
130
+ | `HlmComboboxContent` | `[hlmComboboxContent]`, `hlm-combobox-content` |
131
+ | `HlmComboboxList` | `[hlmComboboxList]` |
132
+ | `HlmComboboxGroup` | `[hlmComboboxGroup]` |
133
+ | `HlmComboboxLabel` | `[hlmComboboxLabel]` |
134
+ | `HlmComboboxEmpty` | `[hlmComboboxEmpty]`, `hlm-combobox-empty` |
135
+ | `HlmComboboxStatus` | `[hlmComboboxStatus]`, `hlm-combobox-status` |
136
+ | `HlmComboboxSeparator` | `[hlmComboboxSeparator]` |
137
+ | `HlmComboboxPlaceholder` | `[hlmComboboxPlaceholder]`, `hlm-combobox-placeholder` |
138
+ | `HlmComboboxValue` | `[hlmComboboxValue]`, `hlm-combobox-value` |
139
+ | `HlmComboboxValues` | `[hlmComboboxValues]` |
140
+ | `HlmComboboxValueTemplate` | `[hlmComboboxValueTemplate]` |
141
+ | `HlmComboboxChips` | `[hlmComboboxChips]`, `hlm-combobox-chips` |
142
+ | `HlmComboboxChip` | `hlm-combobox-chip` (element only) |
143
+ | `HlmComboboxChipInput` | `input[hlmComboboxChipInput]` (input only) |
144
+ | `HlmComboboxPortal` | `[hlmComboboxPortal]` (use as `*hlmComboboxPortal` on content) |
145
+
146
+ ## API reference
147
+
148
+ ### `HlmCombobox` / `HlmComboboxMultiple` (roots)
149
+
150
+ Both provide `provideBrnPopoverConfig({ align: 'start', sideOffset: 6 })` and `provideBrnPopoverDefaultOptions({ role: null })`.
151
+
152
+ | Brain input (`BrnCombobox` / `BrnComboboxMultiple`) | Description |
153
+ | --------------------------------------------------- | ------------------------------------------------------------------------------------ |
154
+ | `autoHighlight` | Auto-highlight first match as the search changes. |
155
+ | `disabled` | Locks trigger + list. |
156
+ | `filter` | Custom filter fn (default substring match). Set to `null` for server-filtered lists. |
157
+ | `search` | Controlled search text. |
158
+ | `value` | Controlled value (single: item; multiple: array). |
159
+ | `itemToString` | `(item) => string` label mapper for object values. |
160
+ | `filterOptions` | Extra filter configuration object. |
161
+ | `isItemEqualToValue` | Equality predicate for object values. |
162
+
163
+ | Brain output | Description |
164
+ | -------------- | ------------------------------ |
165
+ | `searchChange` | Emitted on search-text change. |
166
+ | `valueChange` | Emitted on selection change. |
167
+
168
+ Popover passthrough (via `BrnPopover` hostDirective): inputs `align`, `closeOnOutsidePointerEvents`, `sideOffset`, `state`, `offsetX`; outputs `stateChanged`, `closed`.
169
+
170
+ ### `HlmComboboxTrigger` (`hlm-combobox-trigger`)
171
+
172
+ Renders an `hlmBtn`-styled `<button>` (`brnComboboxTrigger` + anchor + popover-trigger) with a chevron.
173
+
174
+ | Input | Type | Default | Description |
175
+ | --------------------- | --------------------------- | ------------------------------- | --------------------------------------------------------------------- |
176
+ | `class` (`userClass`) | `ClassValue` | `''` | Merged onto the button. Placeholder text dims via `data-placeholder`. |
177
+ | `buttonId` | `string` | auto (`hlm-combobox-trigger-N`) | Button id. |
178
+ | `variant` | `ButtonVariants['variant']` | `'outline'` | `HlmBtn` variant. |
179
+ | `forceInvalid` | `boolean` | `false` | Force error ring regardless of form state. |
180
+
181
+ ### `HlmComboboxInput` (`hlm-combobox-input`)
182
+
183
+ Input-group anchor with chevron trigger + optional clear button.
184
+
185
+ | Input | Type | Default | Description |
186
+ | -------------------------------------- | ---------------------- | ----------------------------- | ------------------------------------------------------------- |
187
+ | `inputId` | `string` | auto (`hlm-combobox-input-N`) | Input id. |
188
+ | `placeholder` | `string` | `''` | Placeholder. |
189
+ | `showTrigger` | `boolean` | `true` | Show the chevron popover button. |
190
+ | `showClear` | `boolean` | `false` | Show the `*brnComboboxClear` X button when a value exists. |
191
+ | `forceInvalid` | `boolean` | `false` | Force error ring. |
192
+ | `aria-invalid` (`ariaInvalidOverride`) | `boolean \| undefined` | `undefined` | Manual override; unset = auto-detect from parent error state. |
193
+
194
+ ### Items / list / groups
195
+
196
+ | Directive | Brain inputs | Notes |
197
+ | ---------------------- | --------------------------- | ---------------------------------------------------------------------- |
198
+ | `HlmComboboxItem` | `id`, `disabled`, `value` | Shows `lucideCheck` at `end-2` when `active`. |
199
+ | `HlmComboboxList` | `id` | Scroll container (`max-h-72`-ish). |
200
+ | `HlmComboboxGroup` | (none, `BrnComboboxGroup`) | `data-hidden` hides empty groups. |
201
+ | `HlmComboboxLabel` | `id` | Muted `text-xs` group heading. |
202
+ | `HlmComboboxEmpty` | (none, `BrnComboboxEmpty`) | Shown only when the content is `data-empty` (`group-data-empty:flex`). |
203
+ | `HlmComboboxStatus` | (none, `BrnComboboxStatus`) | Loading/status row (`"Loading…"`, counts). |
204
+ | `HlmComboboxSeparator` | `orientation` | 1px `bg-border` divider. |
205
+
206
+ ### Values / placeholders / chips
207
+
208
+ | Directive | Notes |
209
+ | -------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------- |
210
+ | `HlmComboboxPlaceholder` | Visible when no value (`data-hidden` hides it once selected). |
211
+ | `HlmComboboxValue` (`inputs: ['placeholder']`) | Value display wrapper. |
212
+ | `HlmComboboxValues` | Multi-value container (brain). |
213
+ | `HlmComboboxValueTemplate` | Custom selected-value template marker (brain). |
214
+ | `HlmComboboxChips` (`input forceInvalid=false`) | Wrap-around anchor (`BrnComboboxAnchor` + popover-trigger) for tag UIs; reflects `data-matches-spartan-invalid`. |
215
+ | `HlmComboboxChip` (`input showRemove=true`) | Tag pill with internal remove button. |
216
+ | `HlmComboboxChipInput` (`inputs id, aria-invalid`) | The free-text `<input>` inside chips. |
217
+ | `HlmComboboxContent` | Popover panel (`w-(--brn-combobox-width)`, `max-h-72`). Pair with `*hlmComboboxPortal`. |
218
+ | `HlmComboboxPortal` (`inputs context, class`) | Structural portal directive — `*hlmComboboxPortal` teleports content to the popover overlay. |
219
+
220
+ ## Examples
221
+
222
+ ### 1. Basic single combobox (button trigger)
223
+
224
+ ```ts
225
+ import { Component, signal } from '@angular/core';
226
+ import { HlmComboboxImports } from '@egose/shadcn-theme-ng/combobox';
227
+
228
+ const FRUITS = ['Apple', 'Banana', 'Blueberry', 'Grapes', 'Pineapple'];
229
+
230
+ @Component({
231
+ selector: 'app-basic-combobox',
232
+ standalone: true,
233
+ imports: [...HlmComboboxImports],
234
+ template: `
235
+ <hlm-combobox [value]="value()" (valueChange)="value.set($event)">
236
+ <hlm-combobox-trigger>{{ value() ?? 'Select fruit…' }}</hlm-combobox-trigger>
237
+ <hlm-combobox-content *hlmComboboxPortal>
238
+ <hlm-combobox-list>
239
+ @for (f of FRUITS; track f) {
240
+ <hlm-combobox-item [value]="f">{{ f }}</hlm-combobox-item>
241
+ }
242
+ </hlm-combobox-list>
243
+ <div hlmComboboxEmpty>No fruit found.</div>
244
+ </hlm-combobox-content>
245
+ </hlm-combobox>
246
+ <p class="mt-2 text-sm">Value: {{ value() ?? 'none' }}</p>
247
+ `,
248
+ })
249
+ export class BasicComboboxComponent {
250
+ readonly value = signal<string | undefined>(undefined);
251
+ protected readonly FRUITS = FRUITS;
252
+ }
253
+ ```
254
+
255
+ ### 2. Searchable input trigger with clear button + groups
256
+
257
+ ```ts
258
+ import { Component, signal } from '@angular/core';
259
+ import { HlmComboboxImports } from '@egose/shadcn-theme-ng/combobox';
260
+
261
+ @Component({
262
+ selector: 'app-grouped-combobox',
263
+ standalone: true,
264
+ imports: [...HlmComboboxImports],
265
+ template: `
266
+ <hlm-combobox
267
+ [value]="value()"
268
+ [search]="search()"
269
+ (valueChange)="value.set($event)"
270
+ (searchChange)="search.set($event)"
271
+ >
272
+ <hlm-combobox-input placeholder="Search timezone…" [showClear]="true" />
273
+ <hlm-combobox-content *hlmComboboxPortal>
274
+ <hlm-combobox-list>
275
+ <div hlmComboboxGroup>
276
+ <span hlmComboboxLabel>Americas</span>
277
+ @for (tz of americas; track tz) {
278
+ <hlm-combobox-item [value]="tz">{{ tz }}</hlm-combobox-item>
279
+ }
280
+ </div>
281
+ <div hlmComboboxSeparator></div>
282
+ <div hlmComboboxGroup>
283
+ <span hlmComboboxLabel>Europe</span>
284
+ @for (tz of europe; track tz) {
285
+ <hlm-combobox-item [value]="tz">{{ tz }}</hlm-combobox-item>
286
+ }
287
+ </div>
288
+ </hlm-combobox-list>
289
+ <div hlmComboboxEmpty>No timezone found.</div>
290
+ </hlm-combobox-content>
291
+ </hlm-combobox>
292
+ `,
293
+ })
294
+ export class GroupedComboboxComponent {
295
+ readonly value = signal<string | undefined>(undefined);
296
+ readonly search = signal('');
297
+ readonly americas = ['America/New_York', 'America/Chicago', 'America/Los_Angeles'];
298
+ readonly europe = ['Europe/London', 'Europe/Berlin', 'Europe/Bucharest'];
299
+ }
11
300
  ```
301
+
302
+ ### 3. Multi-select with removable chips
303
+
304
+ ```ts
305
+ import { Component, signal } from '@angular/core';
306
+ import { HlmComboboxImports } from '@egose/shadcn-theme-ng/combobox';
307
+
308
+ @Component({
309
+ selector: 'app-multi-combobox',
310
+ standalone: true,
311
+ imports: [...HlmComboboxImports],
312
+ template: `
313
+ <hlm-combobox-multiple [value]="selected()" (valueChange)="selected.set($event ?? [])">
314
+ <hlm-combobox-chips>
315
+ @for (v of selected(); track v) {
316
+ <hlm-combobox-chip [value]="v">{{ v }}</hlm-combobox-chip>
317
+ }
318
+ <input hlmComboboxChipInput placeholder="Add tag…" />
319
+ </hlm-combobox-chips>
320
+ <hlm-combobox-content *hlmComboboxPortal>
321
+ <hlm-combobox-list>
322
+ @for (opt of options; track opt) {
323
+ <hlm-combobox-item [value]="opt">{{ opt }}</hlm-combobox-item>
324
+ }
325
+ </hlm-combobox-list>
326
+ <div hlmComboboxEmpty>Nothing left to add.</div>
327
+ </hlm-combobox-content>
328
+ </hlm-combobox-multiple>
329
+ <p class="mt-2 text-sm">{{ selected().length }} selected</p>
330
+ `,
331
+ })
332
+ export class MultiComboboxComponent {
333
+ readonly selected = signal<string[]>(['Angular']);
334
+ readonly options = ['Angular', 'React', 'Vue', 'Svelte', 'Solid'];
335
+ }
336
+ ```
337
+
338
+ ### 4. Disabled + invalid + custom filter states
339
+
340
+ ```ts
341
+ import { Component, signal } from '@angular/core';
342
+ import { HlmComboboxImports } from '@egose/shadcn-theme-ng/combobox';
343
+
344
+ @Component({
345
+ selector: 'app-states-combobox',
346
+ standalone: true,
347
+ imports: [...HlmComboboxImports],
348
+ template: `
349
+ <div class="space-y-4">
350
+ <hlm-combobox [disabled]="true">
351
+ <hlm-combobox-trigger>Disabled</hlm-combobox-trigger>
352
+ </hlm-combobox>
353
+
354
+ <hlm-combobox [value]="v()" (valueChange)="v.set($event)">
355
+ <hlm-combobox-trigger [forceInvalid]="submitted() && !v()">Pick (required)</hlm-combobox-trigger>
356
+ <hlm-combobox-content *hlmComboboxPortal>
357
+ <hlm-combobox-list>
358
+ <hlm-combobox-item value="a">Option A</hlm-combobox-item>
359
+ <hlm-combobox-item value="b" [disabled]="true">Option B (disabled item)</hlm-combobox-item>
360
+ </hlm-combobox-list>
361
+ </hlm-combobox-content>
362
+ </hlm-combobox>
363
+ <button type="button" (click)="submitted.set(true)">Submit</button>
364
+
365
+ <!-- Case-insensitive startsWith filter -->
366
+ <hlm-combobox [filter]="startsWith" [value]="v2()" (valueChange)="v2.set($event)">
367
+ <hlm-combobox-input placeholder="startsWith filter…" />
368
+ <hlm-combobox-content *hlmComboboxPortal>
369
+ <hlm-combobox-list>
370
+ <hlm-combobox-item value="apple">apple</hlm-combobox-item>
371
+ <hlm-combobox-item value="apricot">apricot</hlm-combobox-item>
372
+ <hlm-combobox-item value="banana">banana</hlm-combobox-item>
373
+ </hlm-combobox-list>
374
+ </hlm-combobox-content>
375
+ </hlm-combobox>
376
+ </div>
377
+ `,
378
+ })
379
+ export class StatesComboboxComponent {
380
+ readonly v = signal<string | undefined>(undefined);
381
+ readonly v2 = signal<string | undefined>(undefined);
382
+ readonly submitted = signal(false);
383
+ readonly startsWith = (item: string, search: string) => item.toLowerCase().startsWith(search.toLowerCase());
384
+ }
385
+ ```
386
+
387
+ ### 5. Object values (`itemToString` + equality) with custom value template
388
+
389
+ ```ts
390
+ import { Component, signal } from '@angular/core';
391
+ import { HlmComboboxImports } from '@egose/shadcn-theme-ng/combobox';
392
+
393
+ interface User {
394
+ id: number;
395
+ name: string;
396
+ email: string;
397
+ }
398
+
399
+ @Component({
400
+ selector: 'app-object-combobox',
401
+ standalone: true,
402
+ imports: [...HlmComboboxImports],
403
+ template: `
404
+ <hlm-combobox
405
+ [value]="assignee()"
406
+ [itemToString]="toName"
407
+ [isItemEqualToValue]="byId"
408
+ (valueChange)="assignee.set($event)"
409
+ >
410
+ <hlm-combobox-trigger>
411
+ <span hlmComboboxValue [placeholder]="'Assign to…'">
412
+ {{ assignee()?.name ?? 'Assign to…' }}
413
+ </span>
414
+ </hlm-combobox-trigger>
415
+ <hlm-combobox-content *hlmComboboxPortal>
416
+ <hlm-combobox-list>
417
+ @for (u of users; track u.id) {
418
+ <hlm-combobox-item [value]="u">
419
+ <span class="flex flex-col">
420
+ <span>{{ u.name }}</span>
421
+ <span class="text-muted-foreground text-xs">{{ u.email }}</span>
422
+ </span>
423
+ </hlm-combobox-item>
424
+ }
425
+ </hlm-combobox-list>
426
+ <div hlmComboboxEmpty>No users.</div>
427
+ </hlm-combobox-content>
428
+ </hlm-combobox>
429
+ `,
430
+ })
431
+ export class ObjectComboboxComponent {
432
+ readonly users: User[] = [
433
+ { id: 1, name: 'Ada Lovelace', email: 'ada@example.com' },
434
+ { id: 2, name: 'Grace Hopper', email: 'grace@example.com' },
435
+ ];
436
+ readonly assignee = signal<User | undefined>(undefined);
437
+ readonly toName = (u: User | undefined) => u?.name ?? '';
438
+ readonly byId = (a: User, b: User) => a.id === b.id;
439
+ }
440
+ ```
441
+
442
+ ### 6. Async search (server filtering + status row)
443
+
444
+ Set `[filter]="null"` to disable client filtering, then feed options from your own observable/signal.
445
+
446
+ ```ts
447
+ import { Component, signal } from '@angular/core';
448
+ import { HlmComboboxImports } from '@egose/shadcn-theme-ng/combobox';
449
+
450
+ @Component({
451
+ selector: 'app-async-combobox',
452
+ standalone: true,
453
+ imports: [...HlmComboboxImports],
454
+ template: `
455
+ <hlm-combobox
456
+ [filter]="null"
457
+ [search]="search()"
458
+ [value]="value()"
459
+ (searchChange)="onSearch($event)"
460
+ (valueChange)="value.set($event)"
461
+ >
462
+ <hlm-combobox-input placeholder="Search repos…" />
463
+ <hlm-combobox-content *hlmComboboxPortal>
464
+ @if (loading()) {
465
+ <div hlmComboboxStatus>Searching…</div>
466
+ }
467
+ <hlm-combobox-list>
468
+ @for (r of results(); track r) {
469
+ <hlm-combobox-item [value]="r">{{ r }}</hlm-combobox-item>
470
+ }
471
+ </hlm-combobox-list>
472
+ @if (!loading() && results().length === 0) {
473
+ <div hlmComboboxEmpty>No repositories found.</div>
474
+ }
475
+ </hlm-combobox-content>
476
+ </hlm-combobox>
477
+ `,
478
+ })
479
+ export class AsyncComboboxComponent {
480
+ readonly search = signal('');
481
+ readonly value = signal<string | undefined>(undefined);
482
+ readonly results = signal<string[]>([]);
483
+ readonly loading = signal(false);
484
+
485
+ async onSearch(q: string) {
486
+ this.search.set(q);
487
+ this.loading.set(true);
488
+ // Simulate a debounced fetch — replace with HttpClient in real apps:
489
+ await new Promise((r) => setTimeout(r, 250));
490
+ const ALL = ['shadcn-theme', 'spartan-ng', 'angular', 'ember-tracker'];
491
+ this.results.set(ALL.filter((r) => r.includes(q.toLowerCase())));
492
+ this.loading.set(false);
493
+ }
494
+ }
495
+ ```
496
+
497
+ ## Accessibility notes
498
+
499
+ - Anchors are real controls: trigger is a `<button>`, input mode is a real `<input>`, chips mode keeps a focusable text input — keyboard users can always reach and operate the list.
500
+ - Items expose active/highlighted + disabled states via brain directives; keep the `lucideCheck` selected indicator (it is `aria-hidden`, state comes from semantics, not the icon).
501
+ - `HlmComboboxEmpty` / `HlmComboboxStatus` give screen-reader users feedback for no-results and loading — always render one of them.
502
+ - Label the control: `hlm-combobox-trigger` content, `placeholder`, or an external `<label [for]="inputId">`. The popover defaults to `role: null` (list semantics come from the combobox directives) — do not add a redundant dialog role.
503
+
504
+ ## Theming / CSS variables
505
+
506
+ No component-specific CSS variables. The panel width tracks the anchor (`w-(--brn-combobox-width)`), with `bg-popover` / `text-popover-foreground`, `ring-foreground/10`, `max-h-72` scrolling, and `data-open`/`data-closed` enter/exit animations. Invalid states use `border-destructive` / `ring-destructive/20` via `forceInvalid` or the parent spartan error state.
507
+
508
+ ## Related subpaths
509
+
510
+ - `@egose/shadcn-theme-ng/popover` — underlying overlay positioning (`align`, `sideOffset`).
511
+ - `@egose/shadcn-theme-ng/input-group` — powers `hlm-combobox-input` chrome (chevron/clear addons).
512
+ - `@egose/shadcn-theme-ng/button` — trigger button variants.
513
+ - `@egose/shadcn-theme-ng/command` — command-palette alternative for action search (vs item picking).