@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,64 +1,351 @@
1
- # FormSelect
1
+ # Form Select (`@egose/shadcn-theme-ng/form-select`)
2
2
 
3
- This project was generated using [Angular CLI](https://github.com/angular/angular-cli) version 20.3.0.
3
+ `EgFormSelect` is a reactive-forms wrapper around the shadcn/ui _Select_ composition (spartan-ng `BrnSelect` + `HlmSelect` parts). It renders a label, a single- or multi-select dropdown bound with `formControlName`, and error/hint text — the Angular equivalent of shadcn/ui's `<FormField> + <Select>` pattern for picking one option (or many) from a list.
4
4
 
5
- ## Code scaffolding
5
+ > **Ships as:** `@egose/shadcn-theme-ng/form-select` (plain Tailwind) and `@egose/shadcn-theme-ng-tw/form-select` (`tw:`-prefixed variant). See the [package README](../../README.md) for installation, peer dependencies, and the Tailwind-variant contract. Do not publish this project directory independently.
6
6
 
7
- Angular CLI includes powerful code scaffolding tools. To generate a new component, run:
7
+ ## Installation
8
8
 
9
9
  ```bash
10
- ng generate component component-name
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
11
15
  ```
12
16
 
13
- For a complete list of available schematics (such as `components`, `directives`, or `pipes`), run:
17
+ Peer dependencies (Angular, CDK, `@spartan-ng/brain`, `rxjs`) are documented in the [package README](../../README.md#peer-dependencies). This subpath additionally pulls in `@egose/shadcn-theme-ng/select` at build time (already re-exported through the select subpath — no extra install needed).
14
18
 
15
- ```bash
16
- ng generate --help
19
+ ```ts
20
+ import { EgFormSelect } from '@egose/shadcn-theme-ng/form-select';
21
+ // tw variant:
22
+ // import { EgFormSelect } from '@egose/shadcn-theme-ng-tw/form-select';
17
23
  ```
18
24
 
19
- ## Building
25
+ ## Imports
20
26
 
21
- To build the library, run:
27
+ The public API (`src/public-api.ts`) exports exactly one symbol — the standalone component. There is no `*Imports` array and no `*Module` for this subpath; import the component class directly.
22
28
 
23
- ```bash
24
- ng build form-select
29
+ ```ts
30
+ import { EgFormSelect } from '@egose/shadcn-theme-ng/form-select';
31
+
32
+ @Component({
33
+ standalone: true,
34
+ imports: [ReactiveFormsModule, EgFormSelect],
35
+ template: `
36
+ <form [formGroup]="form">
37
+ <eg-form-select controlName="country" label="Country" [options]="countries" placeholder="Select…" />
38
+ </form>
39
+ `,
40
+ })
41
+ export class MyForm {}
25
42
  ```
26
43
 
27
- This command will compile your project, and the build artifacts will be placed in the `dist/` directory.
44
+ Requirements:
28
45
 
29
- ### Publishing the Library
46
+ - Must sit inside a `<form [formGroup]>` (it injects `FormGroupDirective` and provides `ControlContainer`).
47
+ - `controlName` is required — forwarded as `[formControlName]` to the inner `brn-select` / `brn-select-multiple`.
48
+ - Single mode binds `string`; multi mode (`multiple`) binds `string[]`.
30
49
 
31
- Once the project is built, you can publish your library by following these steps:
50
+ ## Anatomy / Structure
32
51
 
33
- 1. Navigate to the `dist` directory:
52
+ ```html
53
+ <eg-form-select controlName="country" label="Country" [options]="countries">
54
+ <!-- rendered internally (single mode) -->
55
+ <hlm-form-field>
56
+ <label hlmLabel for="<effectiveId>">Country <span>*</span></label>
57
+ <brn-select hlmSelect formControlName="country">
58
+ <hlm-select-trigger buttonId="<effectiveId>" ariaDescribedby="…">
59
+ <hlm-select-value placeholder="Select…" />
60
+ </hlm-select-trigger>
61
+ <hlm-select-content>
62
+ <hlm-select-label>Fruits</hlm-select-label>
63
+ <hlm-select-item value="apple">Apple</hlm-select-item>
64
+ </hlm-select-content>
65
+ </brn-select>
66
+ <hlm-error id="<effectiveId>-error">…</hlm-error>
67
+ <hlm-hint id="<effectiveId>-hint">…</hlm-hint>
68
+ </hlm-form-field>
69
+ </eg-form-select>
70
+ ```
34
71
 
35
- ```bash
36
- cd dist/form-select
37
- ```
72
+ In multi mode the inner `brn-select` becomes `brn-select-multiple`; everything else is identical. Real selectors: `eg-form-select`, `hlm-form-field`, `label[hlmLabel]`, `brn-select[hlmSelect]` / `brn-select-multiple[hlmSelect]`, `hlm-select-trigger`, `hlm-select-value`, `hlm-select-content`, `hlm-select-label`, `hlm-select-item`, `hlm-error`, `hlm-hint`.
38
73
 
39
- 2. Run the `npm publish` command to publish your library to the npm registry:
40
- ```bash
41
- npm publish
42
- ```
74
+ ## API reference
43
75
 
44
- ## Running unit tests
76
+ ### `eg-form-select` — `EgFormSelect`
45
77
 
46
- To execute unit tests with the [Karma](https://karma-runner.github.io) test runner, use the following command:
78
+ | Input | Type | Default | Description |
79
+ | --------------------- | --------------------- | ----------- | --------------------------------------------------------------------------------------------------------- |
80
+ | `label` | `string \| undefined` | `undefined` | Field label rendered as `<label hlmLabel>` bound to the trigger button id. |
81
+ | `controlName` | `string` | `''` | **Required.** Control name in the parent `FormGroup`; forwarded as `formControlName`. |
82
+ | `controlId` | `string \| undefined` | `undefined` | Explicit id; falls back to `id`, then generated `eg-form-select-…`. |
83
+ | `id` | `string \| undefined` | `undefined` | Alias for an explicit id (same fallback chain). Forwarded as `buttonId` to the select trigger. |
84
+ | `error` | `string \| undefined` | `undefined` | Error text rendered in `<hlm-error>`. |
85
+ | `hint` | `string \| undefined` | `undefined` | Hint text rendered in `<hlm-hint>`. |
86
+ | `placeholder` | `string` | `''` | Placeholder forwarded to `<hlm-select-value>`. |
87
+ | `disabled` | `boolean` | `false` | Forwarded as `wrapperDisabled` to `<hlm-select-trigger>`. |
88
+ | `required` | `boolean` | `false` | Renders a red `*` next to the label (pair with `Validators.required`). |
89
+ | `multiple` | `boolean` | `false` | When `true`, renders `brn-select-multiple` (value is `string[]`). |
90
+ | `options` | `SelectOption[]` | `[]` | `{ value: string; label: string }[]` rendered as `<hlm-select-item>` rows. Local interface, not exported. |
91
+ | `optionsLabel` | `string \| undefined` | `undefined` | Optional group heading rendered once as `<hlm-select-label>`. |
92
+ | `class` (`userClass`) | `ClassValue` | `''` | Extra host classes (merged over `tw:flex tw:flex-col`). |
93
+ | `labelClass` | `string` | `''` | Extra label classes (merged over `tw:mb-1 tw:gap-0`). |
94
+ | `selectClass` | `string` | `''` | Extra trigger classes (merged over `tw:w-full`). |
95
+ | `errorClass` | `string` | `''` | Extra error classes (merged over `tw:mt-0`). |
96
+ | `hintClass` | `string` | `''` | Extra hint classes (merged over `tw:mt-0`). |
47
97
 
48
- ```bash
49
- ng test
98
+ No outputs. Readonly computeds/methods: `effectiveId()`, `errorId()`, `hintId()`, `describedBy(): string | null` (error id when invalid + dirty/touched, else hint id, else `null`).
99
+
100
+ ## Examples
101
+
102
+ ### 1. Basic single select
103
+
104
+ ```ts
105
+ import { Component } from '@angular/core';
106
+ import { FormControl, FormGroup, ReactiveFormsModule } from '@angular/forms';
107
+ import { EgFormSelect } from '@egose/shadcn-theme-ng/form-select';
108
+
109
+ @Component({
110
+ standalone: true,
111
+ imports: [ReactiveFormsModule, EgFormSelect],
112
+ template: `
113
+ <form [formGroup]="form" (ngSubmit)="save()">
114
+ <eg-form-select controlName="fruit" label="Fruit" placeholder="Select a fruit" [options]="fruits" />
115
+ <button type="submit">Save</button>
116
+ </form>
117
+ `,
118
+ })
119
+ export class BasicExample {
120
+ readonly form = new FormGroup({
121
+ fruit: new FormControl<string>('', { nonNullable: true }),
122
+ });
123
+ readonly fruits = [
124
+ { value: 'apple', label: 'Apple' },
125
+ { value: 'banana', label: 'Banana' },
126
+ { value: 'cherry', label: 'Cherry' },
127
+ ];
128
+
129
+ save() {
130
+ console.log(this.form.value.fruit); // e.g. 'banana'
131
+ }
132
+ }
50
133
  ```
51
134
 
52
- ## Running end-to-end tests
135
+ ### 2. Grouped options with `optionsLabel`
53
136
 
54
- For end-to-end (e2e) testing, run:
137
+ ```ts
138
+ import { Component } from '@angular/core';
139
+ import { FormControl, FormGroup, ReactiveFormsModule } from '@angular/forms';
140
+ import { EgFormSelect } from '@egose/shadcn-theme-ng/form-select';
55
141
 
56
- ```bash
57
- ng e2e
142
+ @Component({
143
+ standalone: true,
144
+ imports: [ReactiveFormsModule, EgFormSelect],
145
+ template: `
146
+ <form [formGroup]="form">
147
+ <eg-form-select
148
+ controlName="city"
149
+ label="City"
150
+ placeholder="Select a city"
151
+ optionsLabel="Germany"
152
+ [options]="cities"
153
+ hint="Grouped under one heading"
154
+ />
155
+ </form>
156
+ `,
157
+ })
158
+ export class GroupedExample {
159
+ readonly form = new FormGroup({
160
+ city: new FormControl<string>('', { nonNullable: true }),
161
+ });
162
+ readonly cities = [
163
+ { value: 'berlin', label: 'Berlin' },
164
+ { value: 'munich', label: 'Munich' },
165
+ { value: 'hamburg', label: 'Hamburg' },
166
+ ];
167
+ }
168
+ ```
169
+
170
+ > Note: `optionsLabel` renders a single `<hlm-select-label>` heading above all options. For multiple groups, use the raw `HlmSelect*` parts from `@egose/shadcn-theme-ng/select` instead.
171
+
172
+ ### 3. Multi-select (`multiple`)
173
+
174
+ ```ts
175
+ import { Component } from '@angular/core';
176
+ import { FormControl, FormGroup, ReactiveFormsModule } from '@angular/forms';
177
+ import { EgFormSelect } from '@egose/shadcn-theme-ng/form-select';
178
+
179
+ @Component({
180
+ standalone: true,
181
+ imports: [ReactiveFormsModule, EgFormSelect],
182
+ template: `
183
+ <form [formGroup]="form">
184
+ <eg-form-select
185
+ controlName="toppings"
186
+ label="Toppings"
187
+ placeholder="Pick toppings"
188
+ [multiple]="true"
189
+ [options]="toppings"
190
+ hint="Hold Ctrl/Cmd or tap to toggle several"
191
+ />
192
+ <p>Selected: {{ form.value.toppings?.join(', ') || 'none' }}</p>
193
+ </form>
194
+ `,
195
+ })
196
+ export class MultiExample {
197
+ readonly form = new FormGroup({
198
+ toppings: new FormControl<string[]>([], { nonNullable: true }),
199
+ });
200
+ readonly toppings = [
201
+ { value: 'cheese', label: 'Extra cheese' },
202
+ { value: 'mushrooms', label: 'Mushrooms' },
203
+ { value: 'olives', label: 'Olives' },
204
+ ];
205
+ }
58
206
  ```
59
207
 
60
- Angular CLI does not come with an end-to-end testing framework by default. You can choose one that suits your needs.
208
+ ### 4. Required + validation error
209
+
210
+ ```ts
211
+ import { Component } from '@angular/core';
212
+ import { FormControl, FormGroup, ReactiveFormsModule, Validators } from '@angular/forms';
213
+ import { EgFormSelect } from '@egose/shadcn-theme-ng/form-select';
214
+
215
+ @Component({
216
+ standalone: true,
217
+ imports: [ReactiveFormsModule, EgFormSelect],
218
+ template: `
219
+ <form [formGroup]="form" (ngSubmit)="submit()">
220
+ <eg-form-select
221
+ controlName="country"
222
+ label="Country"
223
+ placeholder="Select a country"
224
+ [options]="countries"
225
+ error="Country is required"
226
+ required
227
+ />
228
+ <button type="submit">Continue</button>
229
+ </form>
230
+ `,
231
+ })
232
+ export class RequiredExample {
233
+ readonly form = new FormGroup({
234
+ country: new FormControl<string>('', { nonNullable: true, validators: Validators.required }),
235
+ });
236
+ readonly countries = [
237
+ { value: 'de', label: 'Germany' },
238
+ { value: 'fr', label: 'France' },
239
+ ];
240
+
241
+ submit() {
242
+ if (this.form.invalid) {
243
+ this.form.markAllAsTouched(); // reveals the <hlm-error>
244
+ return;
245
+ }
246
+ }
247
+ }
248
+ ```
249
+
250
+ ### 5. Disabled + empty-options state
251
+
252
+ ```ts
253
+ import { Component, signal } from '@angular/core';
254
+ import { FormControl, FormGroup, ReactiveFormsModule } from '@angular/forms';
255
+ import { EgFormSelect } from '@egose/shadcn-theme-ng/form-select';
256
+
257
+ @Component({
258
+ standalone: true,
259
+ imports: [ReactiveFormsModule, EgFormSelect],
260
+ template: `
261
+ <form [formGroup]="form">
262
+ <eg-form-select
263
+ controlName="plan"
264
+ label="Plan"
265
+ placeholder="Select a plan"
266
+ [options]="plans()"
267
+ [disabled]="loading()"
268
+ hint="Options arrive asynchronously"
269
+ />
270
+ <button type="button" (click)="load()">Load plans</button>
271
+ </form>
272
+ `,
273
+ })
274
+ export class DisabledExample {
275
+ readonly form = new FormGroup({
276
+ plan: new FormControl<string>('', { nonNullable: true }),
277
+ });
278
+ readonly loading = signal(true);
279
+ readonly plans = signal<{ value: string; label: string }[]>([]);
280
+
281
+ load() {
282
+ setTimeout(() => {
283
+ this.plans.set([
284
+ { value: 'free', label: 'Free' },
285
+ { value: 'pro', label: 'Pro' },
286
+ ]);
287
+ this.loading.set(false);
288
+ }, 800);
289
+ }
290
+ }
291
+ ```
292
+
293
+ ### 6. Programmatic control + custom ids/classes
294
+
295
+ ```ts
296
+ import { Component } from '@angular/core';
297
+ import { FormControl, FormGroup, ReactiveFormsModule } from '@angular/forms';
298
+ import { EgFormSelect } from '@egose/shadcn-theme-ng/form-select';
299
+
300
+ @Component({
301
+ standalone: true,
302
+ imports: [ReactiveFormsModule, EgFormSelect],
303
+ template: `
304
+ <form [formGroup]="form">
305
+ <eg-form-select
306
+ #roleField
307
+ controlName="role"
308
+ controlId="user-role"
309
+ label="Role"
310
+ placeholder="Select a role"
311
+ [options]="roles"
312
+ class="tw:max-w-sm"
313
+ selectClass="tw:h-11"
314
+ />
315
+ <div class="tw:flex tw:gap-2">
316
+ <button type="button" (click)="form.controls.role.setValue('admin')">Make admin</button>
317
+ <button type="button" (click)="form.controls.role.reset()">Reset</button>
318
+ </div>
319
+ <p>Trigger id: {{ roleField.effectiveId() }}</p>
320
+ </form>
321
+ `,
322
+ })
323
+ export class ProgrammaticExample {
324
+ readonly form = new FormGroup({
325
+ role: new FormControl<string>('editor', { nonNullable: true }),
326
+ });
327
+ readonly roles = [
328
+ { value: 'admin', label: 'Admin' },
329
+ { value: 'editor', label: 'Editor' },
330
+ { value: 'viewer', label: 'Viewer' },
331
+ ];
332
+ }
333
+ ```
334
+
335
+ ## Accessibility notes
336
+
337
+ - The `<label [for]>` targets the trigger button (`buttonId`), so clicking the label opens the listbox.
338
+ - `aria-describedby` on the trigger points at the error element when invalid + dirty/touched, else the hint element — screen readers announce the right message without extra wiring.
339
+ - The dropdown itself is a spartan-ng listbox (roving `aria-activedescendant`, Escape to close, type-ahead). Keep option `label`s distinct and avoid stuffing status text into them.
340
+ - `required` only decorates the label with `*`; add `Validators.required` so the invalid state (and error announcement) actually triggers.
341
+
342
+ ## Theming / CSS variables
343
+
344
+ No component-specific CSS variables; visuals come from the shared theme tokens via the `HlmSelect*` parts. Use `selectClass` / `labelClass` / `errorClass` / `hintClass` / `class` to adjust sizing and spacing.
61
345
 
62
- ## Additional Resources
346
+ ## Related subpaths
63
347
 
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.
348
+ - `@egose/shadcn-theme-ng/select` — raw `HlmSelect`, `HlmSelectTrigger`, `HlmSelectValue`, `HlmSelectContent`, `HlmSelectItem`, `HlmSelectLabel` for custom layouts and grouped sections.
349
+ - `@egose/shadcn-theme-ng/form-field` — `HlmFormField`, `HlmError`, `HlmHint`, `HlmFormIdGenerator`.
350
+ - `@egose/shadcn-theme-ng/label` — `HlmLabel`.
351
+ - `@egose/shadcn-theme-ng/form-searchable-multiselect` — searchable checkbox-popover alternative for long option lists.
@@ -1,15 +1,17 @@
1
1
  import * as i0 from '@angular/core';
2
- import { input, computed, Component } from '@angular/core';
2
+ import { inject, input, computed, Component } from '@angular/core';
3
3
  import * as i1 from '@angular/forms';
4
- import { ReactiveFormsModule, FormGroupDirective, ControlContainer } from '@angular/forms';
5
- import { HlmFormField, HlmError, HlmHint } from '@egose/shadcn-theme-ng/form-field';
4
+ import { FormGroupDirective, ReactiveFormsModule, ControlContainer } from '@angular/forms';
5
+ import { HlmFormIdGenerator, HlmFormField, HlmError, HlmHint } from '@egose/shadcn-theme-ng/form-field';
6
6
  import { HlmLabel } from '@egose/shadcn-theme-ng/label';
7
7
  import { hlm } from '@egose/shadcn-theme-ng/utils';
8
8
  import { BrnSelectImports } from '@spartan-ng/brain/select';
9
9
  import * as i2 from '@egose/shadcn-theme-ng/select';
10
- import { HlmSelectImports, HlmSelect, HlmSelectTrigger, HlmSelectValue, HlmSelectContent, HlmSelectItem, HlmSelectLabel, HlmSelectPlaceholder } from '@egose/shadcn-theme-ng/select';
10
+ import { HlmSelectImports, HlmSelect, HlmSelectTrigger, HlmSelectValue, HlmSelectContent, HlmSelectItem, HlmSelectLabel } from '@egose/shadcn-theme-ng/select';
11
11
 
12
12
  class EgFormSelect {
13
+ formGroupDirective = inject(FormGroupDirective);
14
+ generatedId = inject(HlmFormIdGenerator).generate('eg-form-select');
13
15
  label = input(undefined, /* @ts-ignore */
14
16
  ...(ngDevMode ? [{ debugName: "label" }] : /* istanbul ignore next */ []));
15
17
  controlId = input(undefined, /* @ts-ignore */
@@ -21,7 +23,7 @@ class EgFormSelect {
21
23
  hint = input(undefined, /* @ts-ignore */
22
24
  ...(ngDevMode ? [{ debugName: "hint" }] : /* istanbul ignore next */ []));
23
25
  // HTML/select attributes
24
- id = input(crypto.randomUUID(), /* @ts-ignore */
26
+ id = input(undefined, /* @ts-ignore */
25
27
  ...(ngDevMode ? [{ debugName: "id" }] : /* istanbul ignore next */ []));
26
28
  placeholder = input('', /* @ts-ignore */
27
29
  ...(ngDevMode ? [{ debugName: "placeholder" }] : /* istanbul ignore next */ []));
@@ -29,6 +31,20 @@ class EgFormSelect {
29
31
  ...(ngDevMode ? [{ debugName: "disabled" }] : /* istanbul ignore next */ []));
30
32
  required = input(false, /* @ts-ignore */
31
33
  ...(ngDevMode ? [{ debugName: "required" }] : /* istanbul ignore next */ []));
34
+ effectiveId = computed(() => this.controlId() || this.id() || this.generatedId, /* @ts-ignore */
35
+ ...(ngDevMode ? [{ debugName: "effectiveId" }] : /* istanbul ignore next */ []));
36
+ errorId = computed(() => `${this.effectiveId()}-error`, /* @ts-ignore */
37
+ ...(ngDevMode ? [{ debugName: "errorId" }] : /* istanbul ignore next */ []));
38
+ hintId = computed(() => `${this.effectiveId()}-hint`, /* @ts-ignore */
39
+ ...(ngDevMode ? [{ debugName: "hintId" }] : /* istanbul ignore next */ []));
40
+ describedBy() {
41
+ const control = this.formGroupDirective.form.get(this.controlName());
42
+ return this.error() && control?.invalid && (control.dirty || control.touched)
43
+ ? this.errorId()
44
+ : this.hint()
45
+ ? this.hintId()
46
+ : null;
47
+ }
32
48
  // Select-specific
33
49
  multiple = input(false, /* @ts-ignore */
34
50
  ...(ngDevMode ? [{ debugName: "multiple" }] : /* istanbul ignore next */ []));
@@ -47,92 +63,26 @@ class EgFormSelect {
47
63
  hintClass = input('', /* @ts-ignore */
48
64
  ...(ngDevMode ? [{ debugName: "hintClass" }] : /* istanbul ignore next */ []));
49
65
  // Computed classes
50
- $userClass = computed(() => hlm('flex flex-col', this.userClass()), /* @ts-ignore */
66
+ $userClass = computed(() => hlm("flex flex-col", this.userClass()), /* @ts-ignore */
51
67
  ...(ngDevMode ? [{ debugName: "$userClass" }] : /* istanbul ignore next */ []));
52
- $labelClass = computed(() => hlm('mb-1 gap-0', this.labelClass()), /* @ts-ignore */
68
+ $labelClass = computed(() => hlm("mb-1 gap-0", this.labelClass()), /* @ts-ignore */
53
69
  ...(ngDevMode ? [{ debugName: "$labelClass" }] : /* istanbul ignore next */ []));
54
- $selectClass = computed(() => hlm('w-full', this.selectClass()), /* @ts-ignore */
70
+ $selectClass = computed(() => hlm("w-full", this.selectClass()), /* @ts-ignore */
55
71
  ...(ngDevMode ? [{ debugName: "$selectClass" }] : /* istanbul ignore next */ []));
56
- $errorClass = computed(() => hlm('mt-0', this.errorClass()), /* @ts-ignore */
72
+ $errorClass = computed(() => hlm("mt-0", this.errorClass()), /* @ts-ignore */
57
73
  ...(ngDevMode ? [{ debugName: "$errorClass" }] : /* istanbul ignore next */ []));
58
- $hintClass = computed(() => hlm('mt-0', this.hintClass()), /* @ts-ignore */
74
+ $hintClass = computed(() => hlm("mt-0", this.hintClass()), /* @ts-ignore */
59
75
  ...(ngDevMode ? [{ debugName: "$hintClass" }] : /* istanbul ignore next */ []));
60
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.7", ngImport: i0, type: EgFormSelect, deps: [], target: i0.ɵɵFactoryTarget.Component });
61
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.7", type: EgFormSelect, isStandalone: true, selector: "eg-form-select", inputs: { label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, controlId: { classPropertyName: "controlId", publicName: "controlId", isSignal: true, isRequired: false, transformFunction: null }, controlName: { classPropertyName: "controlName", publicName: "controlName", isSignal: true, isRequired: false, transformFunction: null }, error: { classPropertyName: "error", publicName: "error", isSignal: true, isRequired: false, transformFunction: null }, hint: { classPropertyName: "hint", publicName: "hint", isSignal: true, isRequired: false, transformFunction: null }, id: { classPropertyName: "id", publicName: "id", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, required: { classPropertyName: "required", publicName: "required", isSignal: true, isRequired: false, transformFunction: null }, multiple: { classPropertyName: "multiple", publicName: "multiple", isSignal: true, isRequired: false, transformFunction: null }, options: { classPropertyName: "options", publicName: "options", isSignal: true, isRequired: false, transformFunction: null }, optionsLabel: { classPropertyName: "optionsLabel", publicName: "optionsLabel", isSignal: true, isRequired: false, transformFunction: null }, userClass: { classPropertyName: "userClass", publicName: "class", isSignal: true, isRequired: false, transformFunction: null }, labelClass: { classPropertyName: "labelClass", publicName: "labelClass", isSignal: true, isRequired: false, transformFunction: null }, selectClass: { classPropertyName: "selectClass", publicName: "selectClass", isSignal: true, isRequired: false, transformFunction: null }, errorClass: { classPropertyName: "errorClass", publicName: "errorClass", isSignal: true, isRequired: false, transformFunction: null }, hintClass: { classPropertyName: "hintClass", publicName: "hintClass", isSignal: true, isRequired: false, transformFunction: null } }, host: { classAttribute: "w-full" }, providers: [{ provide: ControlContainer, useExisting: FormGroupDirective }], ngImport: i0, template: `
62
- @let lbl = label();
63
- @let cid = controlId();
64
- @let cnm = controlName();
65
- @let err = error();
66
- @let hnt = hint();
67
- @let rqrd = required();
68
-
69
- <hlm-form-field>
70
- @if (lbl) {
71
- <span hlmLabel [class]="$labelClass()"
72
- >{{ lbl }}
73
- @if (rqrd) {
74
- <span class="text-red-500">*</span>
75
- }
76
- </span>
77
- }
78
-
79
- @if (multiple()) {
80
- <brn-select-multiple hlmSelect [id]="cid || id()" [formControlName]="cnm">
81
- <hlm-select-trigger [class]="$selectClass()">
82
- <hlm-select-value [placeholder]="placeholder()" />
83
- </hlm-select-trigger>
84
-
85
- <hlm-select-content>
86
- @if (options().length) {
87
- @if (optionsLabel()) {
88
- <hlm-select-label>{{ optionsLabel() }}</hlm-select-label>
89
- }
90
- @for (option of options(); track option.value) {
91
- <hlm-select-item [value]="option.value">{{ option.label }}</hlm-select-item>
92
- }
93
- }
94
- </hlm-select-content>
95
- </brn-select-multiple>
96
- } @else {
97
- <brn-select hlmSelect [id]="cid || id()" [formControlName]="cnm">
98
- <hlm-select-trigger [class]="$selectClass()">
99
- <hlm-select-value [placeholder]="placeholder()" />
100
- </hlm-select-trigger>
101
-
102
- <hlm-select-content>
103
- @if (options().length) {
104
- @if (optionsLabel()) {
105
- <hlm-select-label>{{ optionsLabel() }}</hlm-select-label>
106
- }
107
- @for (option of options(); track option.value) {
108
- <hlm-select-item [value]="option.value">{{ option.label }}</hlm-select-item>
109
- }
110
- }
111
- </hlm-select-content>
112
- </brn-select>
113
- }
114
-
115
- @if (err) {
116
- <hlm-error [class]="$errorClass()">
117
- {{ err }}
118
- </hlm-error>
119
- }
120
-
121
- @if (hnt) {
122
- <hlm-hint [class]="$hintClass()">
123
- {{ hnt }}
124
- </hlm-hint>
125
- }
126
- </hlm-form-field>
127
- `, isInline: true, dependencies: [{ kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "component", type: HlmFormField, selector: "hlm-form-field", inputs: ["class"] }, { kind: "directive", type: HlmError, selector: "hlm-error", inputs: ["class"] }, { kind: "directive", type: HlmHint, selector: "hlm-hint", inputs: ["class"] }, { kind: "directive", type: HlmLabel, selector: "[hlmLabel]", inputs: ["class"] }, { kind: "directive", type: i2.HlmSelect, selector: "[hlmSelect],hlm-select" }, { kind: "component", type: i2.HlmSelectContent, selector: "hlm-select-content", inputs: ["showScroll"] }, { kind: "component", type: i2.HlmSelectItem, selector: "hlm-select-item" }, { kind: "directive", type: i2.HlmSelectLabel, selector: "[hlmSelectLabel],hlm-select-label" }, { kind: "component", type: i2.HlmSelectTrigger, selector: "hlm-select-trigger", inputs: ["class", "buttonId", "size", "forceInvalid"] }, { kind: "directive", type: i2.HlmSelectValue, selector: "[hlmSelectValue],hlm-select-value" }] });
76
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: EgFormSelect, deps: [], target: i0.ɵɵFactoryTarget.Component });
77
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.3", type: EgFormSelect, isStandalone: true, selector: "eg-form-select", inputs: { label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, controlId: { classPropertyName: "controlId", publicName: "controlId", isSignal: true, isRequired: false, transformFunction: null }, controlName: { classPropertyName: "controlName", publicName: "controlName", isSignal: true, isRequired: false, transformFunction: null }, error: { classPropertyName: "error", publicName: "error", isSignal: true, isRequired: false, transformFunction: null }, hint: { classPropertyName: "hint", publicName: "hint", isSignal: true, isRequired: false, transformFunction: null }, id: { classPropertyName: "id", publicName: "id", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, required: { classPropertyName: "required", publicName: "required", isSignal: true, isRequired: false, transformFunction: null }, multiple: { classPropertyName: "multiple", publicName: "multiple", isSignal: true, isRequired: false, transformFunction: null }, options: { classPropertyName: "options", publicName: "options", isSignal: true, isRequired: false, transformFunction: null }, optionsLabel: { classPropertyName: "optionsLabel", publicName: "optionsLabel", isSignal: true, isRequired: false, transformFunction: null }, userClass: { classPropertyName: "userClass", publicName: "class", isSignal: true, isRequired: false, transformFunction: null }, labelClass: { classPropertyName: "labelClass", publicName: "labelClass", isSignal: true, isRequired: false, transformFunction: null }, selectClass: { classPropertyName: "selectClass", publicName: "selectClass", isSignal: true, isRequired: false, transformFunction: null }, errorClass: { classPropertyName: "errorClass", publicName: "errorClass", isSignal: true, isRequired: false, transformFunction: null }, hintClass: { classPropertyName: "hintClass", publicName: "hintClass", isSignal: true, isRequired: false, transformFunction: null } }, host: { classAttribute: "w-full" }, providers: [{ provide: ControlContainer, useExisting: FormGroupDirective }], ngImport: i0, template: "\n @let lbl = label();\n @let cnm = controlName();\n @let err = error();\n @let hnt = hint();\n @let rqrd = required();\n\n <hlm-form-field>\n @if (lbl) {\n <label hlmLabel [for]=\"effectiveId()\" [class]=\"$labelClass()\"\n >{{ lbl }}\n @if (rqrd) {\n <span class=\"text-red-500\">*</span>\n }\n </label>\n }\n\n @if (multiple()) {\n <brn-select-multiple hlmSelect [formControlName]=\"cnm\">\n <hlm-select-trigger\n [buttonId]=\"effectiveId()\"\n [ariaDescribedby]=\"describedBy()\"\n [wrapperDisabled]=\"disabled()\"\n [class]=\"$selectClass()\"\n >\n <hlm-select-value [placeholder]=\"placeholder()\" />\n </hlm-select-trigger>\n\n <hlm-select-content>\n @if (options().length) {\n @if (optionsLabel()) {\n <hlm-select-label>{{ optionsLabel() }}</hlm-select-label>\n }\n @for (option of options(); track option.value) {\n <hlm-select-item [value]=\"option.value\">{{ option.label }}</hlm-select-item>\n }\n }\n </hlm-select-content>\n </brn-select-multiple>\n } @else {\n <brn-select hlmSelect [formControlName]=\"cnm\">\n <hlm-select-trigger\n [buttonId]=\"effectiveId()\"\n [ariaDescribedby]=\"describedBy()\"\n [wrapperDisabled]=\"disabled()\"\n [class]=\"$selectClass()\"\n >\n <hlm-select-value [placeholder]=\"placeholder()\" />\n </hlm-select-trigger>\n\n <hlm-select-content>\n @if (options().length) {\n @if (optionsLabel()) {\n <hlm-select-label>{{ optionsLabel() }}</hlm-select-label>\n }\n @for (option of options(); track option.value) {\n <hlm-select-item [value]=\"option.value\">{{ option.label }}</hlm-select-item>\n }\n }\n </hlm-select-content>\n </brn-select>\n }\n\n @if (err) {\n <hlm-error [id]=\"errorId()\" [class]=\"$errorClass()\">\n {{ err }}\n </hlm-error>\n }\n\n @if (hnt) {\n <hlm-hint [id]=\"hintId()\" [class]=\"$hintClass()\">\n {{ hnt }}\n </hlm-hint>\n }\n </hlm-form-field>\n ", isInline: true, dependencies: [{ kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "component", type: HlmFormField, selector: "hlm-form-field", inputs: ["class"] }, { kind: "directive", type: HlmError, selector: "hlm-error", inputs: ["class"] }, { kind: "directive", type: HlmHint, selector: "hlm-hint", inputs: ["class"] }, { kind: "directive", type: HlmLabel, selector: "[hlmLabel]", inputs: ["class"] }, { kind: "directive", type: i2.HlmSelect, selector: "[hlmSelect],hlm-select" }, { kind: "component", type: i2.HlmSelectContent, selector: "hlm-select-content", inputs: ["showScroll"] }, { kind: "component", type: i2.HlmSelectItem, selector: "hlm-select-item" }, { kind: "directive", type: i2.HlmSelectLabel, selector: "[hlmSelectLabel],hlm-select-label" }, { kind: "component", type: i2.HlmSelectTrigger, selector: "hlm-select-trigger", inputs: ["class", "buttonId", "ariaDescribedby", "wrapperDisabled", "size", "forceInvalid"] }, { kind: "directive", type: i2.HlmSelectValue, selector: "[hlmSelectValue],hlm-select-value" }] });
128
78
  }
129
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.7", ngImport: i0, type: EgFormSelect, decorators: [{
79
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: EgFormSelect, decorators: [{
130
80
  type: Component,
131
81
  args: [{
132
82
  selector: 'eg-form-select',
133
83
  standalone: true,
134
84
  host: {
135
- class: 'w-full',
85
+ class: "w-full",
136
86
  },
137
87
  imports: [
138
88
  ReactiveFormsModule,
@@ -148,76 +98,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.7", ngImpor
148
98
  HlmSelectContent,
149
99
  HlmSelectItem,
150
100
  HlmSelectLabel,
151
- HlmSelectPlaceholder,
152
101
  ],
153
102
  providers: [{ provide: ControlContainer, useExisting: FormGroupDirective }],
154
- template: `
155
- @let lbl = label();
156
- @let cid = controlId();
157
- @let cnm = controlName();
158
- @let err = error();
159
- @let hnt = hint();
160
- @let rqrd = required();
161
-
162
- <hlm-form-field>
163
- @if (lbl) {
164
- <span hlmLabel [class]="$labelClass()"
165
- >{{ lbl }}
166
- @if (rqrd) {
167
- <span class="text-red-500">*</span>
168
- }
169
- </span>
170
- }
171
-
172
- @if (multiple()) {
173
- <brn-select-multiple hlmSelect [id]="cid || id()" [formControlName]="cnm">
174
- <hlm-select-trigger [class]="$selectClass()">
175
- <hlm-select-value [placeholder]="placeholder()" />
176
- </hlm-select-trigger>
177
-
178
- <hlm-select-content>
179
- @if (options().length) {
180
- @if (optionsLabel()) {
181
- <hlm-select-label>{{ optionsLabel() }}</hlm-select-label>
182
- }
183
- @for (option of options(); track option.value) {
184
- <hlm-select-item [value]="option.value">{{ option.label }}</hlm-select-item>
185
- }
186
- }
187
- </hlm-select-content>
188
- </brn-select-multiple>
189
- } @else {
190
- <brn-select hlmSelect [id]="cid || id()" [formControlName]="cnm">
191
- <hlm-select-trigger [class]="$selectClass()">
192
- <hlm-select-value [placeholder]="placeholder()" />
193
- </hlm-select-trigger>
194
-
195
- <hlm-select-content>
196
- @if (options().length) {
197
- @if (optionsLabel()) {
198
- <hlm-select-label>{{ optionsLabel() }}</hlm-select-label>
199
- }
200
- @for (option of options(); track option.value) {
201
- <hlm-select-item [value]="option.value">{{ option.label }}</hlm-select-item>
202
- }
203
- }
204
- </hlm-select-content>
205
- </brn-select>
206
- }
207
-
208
- @if (err) {
209
- <hlm-error [class]="$errorClass()">
210
- {{ err }}
211
- </hlm-error>
212
- }
213
-
214
- @if (hnt) {
215
- <hlm-hint [class]="$hintClass()">
216
- {{ hnt }}
217
- </hlm-hint>
218
- }
219
- </hlm-form-field>
220
- `,
103
+ template: "\n @let lbl = label();\n @let cnm = controlName();\n @let err = error();\n @let hnt = hint();\n @let rqrd = required();\n\n <hlm-form-field>\n @if (lbl) {\n <label hlmLabel [for]=\"effectiveId()\" [class]=\"$labelClass()\"\n >{{ lbl }}\n @if (rqrd) {\n <span class=\"text-red-500\">*</span>\n }\n </label>\n }\n\n @if (multiple()) {\n <brn-select-multiple hlmSelect [formControlName]=\"cnm\">\n <hlm-select-trigger\n [buttonId]=\"effectiveId()\"\n [ariaDescribedby]=\"describedBy()\"\n [wrapperDisabled]=\"disabled()\"\n [class]=\"$selectClass()\"\n >\n <hlm-select-value [placeholder]=\"placeholder()\" />\n </hlm-select-trigger>\n\n <hlm-select-content>\n @if (options().length) {\n @if (optionsLabel()) {\n <hlm-select-label>{{ optionsLabel() }}</hlm-select-label>\n }\n @for (option of options(); track option.value) {\n <hlm-select-item [value]=\"option.value\">{{ option.label }}</hlm-select-item>\n }\n }\n </hlm-select-content>\n </brn-select-multiple>\n } @else {\n <brn-select hlmSelect [formControlName]=\"cnm\">\n <hlm-select-trigger\n [buttonId]=\"effectiveId()\"\n [ariaDescribedby]=\"describedBy()\"\n [wrapperDisabled]=\"disabled()\"\n [class]=\"$selectClass()\"\n >\n <hlm-select-value [placeholder]=\"placeholder()\" />\n </hlm-select-trigger>\n\n <hlm-select-content>\n @if (options().length) {\n @if (optionsLabel()) {\n <hlm-select-label>{{ optionsLabel() }}</hlm-select-label>\n }\n @for (option of options(); track option.value) {\n <hlm-select-item [value]=\"option.value\">{{ option.label }}</hlm-select-item>\n }\n }\n </hlm-select-content>\n </brn-select>\n }\n\n @if (err) {\n <hlm-error [id]=\"errorId()\" [class]=\"$errorClass()\">\n {{ err }}\n </hlm-error>\n }\n\n @if (hnt) {\n <hlm-hint [id]=\"hintId()\" [class]=\"$hintClass()\">\n {{ hnt }}\n </hlm-hint>\n }\n </hlm-form-field>\n ",
221
104
  }]
222
105
  }], propDecorators: { label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], controlId: [{ type: i0.Input, args: [{ isSignal: true, alias: "controlId", required: false }] }], controlName: [{ type: i0.Input, args: [{ isSignal: true, alias: "controlName", required: false }] }], error: [{ type: i0.Input, args: [{ isSignal: true, alias: "error", required: false }] }], hint: [{ type: i0.Input, args: [{ isSignal: true, alias: "hint", required: false }] }], id: [{ type: i0.Input, args: [{ isSignal: true, alias: "id", required: false }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], required: [{ type: i0.Input, args: [{ isSignal: true, alias: "required", required: false }] }], multiple: [{ type: i0.Input, args: [{ isSignal: true, alias: "multiple", required: false }] }], options: [{ type: i0.Input, args: [{ isSignal: true, alias: "options", required: false }] }], optionsLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "optionsLabel", required: false }] }], userClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }], labelClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "labelClass", required: false }] }], selectClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "selectClass", required: false }] }], errorClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "errorClass", required: false }] }], hintClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "hintClass", required: false }] }] } });
223
106
 
@@ -230,4 +113,4 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.7", ngImpor
230
113
  */
231
114
 
232
115
  export { EgFormSelect };
233
- //# sourceMappingURL=form-select.mjs.map
116
+