@egose/shadcn-theme-ng-tw 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 (244) hide show
  1. package/README.md +130 -13
  2. package/accordion/README.md +376 -34
  3. package/accordion/fesm2022/accordion.mjs +20 -20
  4. package/alert/README.md +343 -34
  5. package/alert/fesm2022/alert.mjs +18 -18
  6. package/alert-dialog/README.md +471 -5
  7. package/alert-dialog/fesm2022/alert-dialog.mjs +48 -48
  8. package/alert-dialog/types/alert-dialog.d.ts +1 -1
  9. package/aspect-ratio/README.md +272 -5
  10. package/aspect-ratio/fesm2022/aspect-ratio.mjs +9 -9
  11. package/autocomplete/README.md +473 -34
  12. package/autocomplete/fesm2022/autocomplete.mjs +54 -54
  13. package/autocomplete/types/autocomplete.d.ts +1 -1
  14. package/avatar/README.md +357 -5
  15. package/avatar/fesm2022/avatar.mjs +32 -32
  16. package/badge/README.md +289 -34
  17. package/badge/fesm2022/badge.mjs +4 -4
  18. package/basic-alert/README.md +324 -34
  19. package/basic-alert/fesm2022/basic-alert.mjs +4 -4
  20. package/basic-alert/types/basic-alert.d.ts +1 -1
  21. package/breadcrumb/README.md +406 -5
  22. package/breadcrumb/fesm2022/breadcrumb.mjs +34 -34
  23. package/button/README.md +453 -34
  24. package/button/fesm2022/button.mjs +96 -118
  25. package/button/types/button.d.ts +7 -10
  26. package/button-group/README.md +318 -5
  27. package/button-group/fesm2022/button-group.mjs +20 -20
  28. package/calendar/README.md +328 -34
  29. package/calendar/fesm2022/calendar.mjs +154 -154
  30. package/card/README.md +331 -5
  31. package/card/fesm2022/card.mjs +33 -33
  32. package/carousel/README.md +333 -5
  33. package/carousel/fesm2022/carousel.mjs +47 -44
  34. package/carousel/types/carousel.d.ts +1 -1
  35. package/checkbox/README.md +291 -34
  36. package/checkbox/fesm2022/checkbox.mjs +22 -20
  37. package/checkbox/types/checkbox.d.ts +5 -4
  38. package/collapsible/README.md +332 -5
  39. package/collapsible/fesm2022/collapsible.mjs +15 -15
  40. package/combobox/README.md +507 -5
  41. package/combobox/fesm2022/combobox.mjs +95 -92
  42. package/combobox/types/combobox.d.ts +1 -1
  43. package/command/README.md +435 -5
  44. package/command/fesm2022/command.mjs +56 -56
  45. package/confirmation-dialog/README.md +272 -34
  46. package/confirmation-dialog/fesm2022/confirmation-dialog.mjs +13 -12
  47. package/confirmation-dialog/types/confirmation-dialog.d.ts +9 -5
  48. package/context-menu/README.md +366 -5
  49. package/context-menu/fesm2022/context-menu.mjs +9 -9
  50. package/date-picker/README.md +436 -34
  51. package/date-picker/fesm2022/date-picker.mjs +79 -68
  52. package/date-picker/types/date-picker.d.ts +8 -4
  53. package/dialog/README.md +419 -34
  54. package/dialog/fesm2022/dialog.mjs +48 -48
  55. package/drawer/README.md +395 -5
  56. package/drawer/fesm2022/drawer.mjs +45 -45
  57. package/dropdown-menu/README.md +417 -5
  58. package/dropdown-menu/fesm2022/dropdown-menu.mjs +85 -73
  59. package/dropdown-menu/types/dropdown-menu.d.ts +4 -0
  60. package/empty/README.md +329 -5
  61. package/empty/fesm2022/empty.mjs +31 -31
  62. package/field/README.md +385 -5
  63. package/field/fesm2022/field.mjs +59 -59
  64. package/field/types/field.d.ts +1 -1
  65. package/form-checkbox/README.md +283 -34
  66. package/form-checkbox/fesm2022/form-checkbox.mjs +37 -19
  67. package/form-checkbox/types/form-checkbox.d.ts +7 -1
  68. package/form-date-picker/README.md +293 -34
  69. package/form-date-picker/fesm2022/form-date-picker.mjs +59 -24
  70. package/form-date-picker/types/form-date-picker.d.ts +7 -1
  71. package/form-field/README.md +327 -34
  72. package/form-field/fesm2022/form-field.mjs +30 -16
  73. package/form-field/types/form-field.d.ts +28 -20
  74. package/form-field-simple/README.md +311 -34
  75. package/form-field-simple/fesm2022/form-field-simple.mjs +4 -4
  76. package/form-searchable-multiselect/README.md +332 -34
  77. package/form-searchable-multiselect/fesm2022/form-searchable-multiselect.mjs +41 -21
  78. package/form-searchable-multiselect/types/form-searchable-multiselect.d.ts +8 -2
  79. package/form-select/README.md +321 -34
  80. package/form-select/fesm2022/form-select.mjs +62 -29
  81. package/form-select/types/form-select.d.ts +7 -1
  82. package/form-text-input/README.md +342 -34
  83. package/form-text-input/fesm2022/form-text-input.mjs +43 -55
  84. package/form-text-input/types/form-text-input.d.ts +9 -12
  85. package/form-textarea/README.md +318 -34
  86. package/form-textarea/fesm2022/form-textarea.mjs +42 -23
  87. package/form-textarea/types/form-textarea.d.ts +8 -1
  88. package/hover-card/README.md +256 -5
  89. package/hover-card/fesm2022/hover-card.mjs +19 -19
  90. package/icon/README.md +210 -34
  91. package/icon/fesm2022/icon.mjs +8 -8
  92. package/input/README.md +240 -34
  93. package/input/fesm2022/input.mjs +17 -12
  94. package/input/types/input.d.ts +2 -1
  95. package/input-group/README.md +335 -5
  96. package/input-group/fesm2022/input-group.mjs +37 -37
  97. package/input-group/types/input-group.d.ts +3 -3
  98. package/input-otp/README.md +375 -5
  99. package/input-otp/fesm2022/input-otp.mjs +27 -27
  100. package/item/README.md +385 -5
  101. package/item/fesm2022/item.mjs +54 -54
  102. package/kbd/README.md +291 -5
  103. package/kbd/fesm2022/kbd.mjs +13 -13
  104. package/label/README.md +243 -34
  105. package/label/fesm2022/label.mjs +9 -9
  106. package/label/types/label.d.ts +1 -1
  107. package/layout-simple/README.md +174 -44
  108. package/layout-simple/fesm2022/layout-simple.mjs +917 -398
  109. package/layout-simple/types/layout-simple.d.ts +180 -129
  110. package/menu/README.md +418 -0
  111. package/menu/fesm2022/menu.mjs +461 -0
  112. package/menu/package.json +24 -0
  113. package/menu/types/menu.d.ts +137 -0
  114. package/menubar/README.md +343 -5
  115. package/menubar/fesm2022/menubar.mjs +13 -13
  116. package/native-select/README.md +323 -5
  117. package/native-select/fesm2022/native-select.mjs +19 -19
  118. package/navigation-menu/README.md +369 -5
  119. package/navigation-menu/fesm2022/navigation-menu.mjs +37 -37
  120. package/package.json +183 -154
  121. package/pagination/README.md +388 -5
  122. package/pagination/fesm2022/pagination.mjs +63 -63
  123. package/popover/README.md +302 -34
  124. package/popover/fesm2022/popover.mjs +30 -30
  125. package/progress/README.md +311 -5
  126. package/progress/fesm2022/progress.mjs +13 -13
  127. package/radio-group/README.md +335 -34
  128. package/radio-group/fesm2022/radio-group.mjs +26 -19
  129. package/resizable/README.md +269 -5
  130. package/resizable/fesm2022/resizable.mjs +19 -19
  131. package/scroll-area/README.md +233 -5
  132. package/scroll-area/fesm2022/scroll-area.mjs +9 -9
  133. package/searchable-multiselect/README.md +294 -34
  134. package/searchable-multiselect/fesm2022/searchable-multiselect.mjs +63 -16
  135. package/searchable-multiselect/types/searchable-multiselect.d.ts +8 -2
  136. package/select/README.md +408 -34
  137. package/select/fesm2022/select.mjs +80 -72
  138. package/select/types/select.d.ts +3 -1
  139. package/separator/README.md +193 -34
  140. package/separator/fesm2022/separator.mjs +9 -9
  141. package/separator/types/separator.d.ts +1 -1
  142. package/sheet/README.md +282 -34
  143. package/sheet/fesm2022/sheet.mjs +30 -30
  144. package/sidebar/README.md +457 -5
  145. package/sidebar/fesm2022/sidebar.mjs +136 -134
  146. package/sidebar/types/sidebar.d.ts +3 -3
  147. package/skeleton/README.md +217 -5
  148. package/skeleton/fesm2022/skeleton.mjs +9 -9
  149. package/slider/README.md +273 -5
  150. package/slider/fesm2022/slider.mjs +29 -25
  151. package/sonner/README.md +317 -34
  152. package/sonner/fesm2022/sonner.mjs +9 -9
  153. package/spinner/README.md +255 -34
  154. package/spinner/fesm2022/spinner.mjs +8 -8
  155. package/switch/README.md +281 -34
  156. package/switch/fesm2022/switch.mjs +12 -14
  157. package/table/README.md +423 -5
  158. package/table/fesm2022/table.mjs +41 -41
  159. package/tabs/README.md +382 -34
  160. package/tabs/fesm2022/tabs.mjs +48 -38
  161. package/textarea/README.md +282 -5
  162. package/textarea/fesm2022/textarea.mjs +9 -9
  163. package/toggle/README.md +270 -5
  164. package/toggle/fesm2022/toggle.mjs +14 -14
  165. package/toggle-group/README.md +340 -5
  166. package/toggle-group/fesm2022/toggle-group.mjs +13 -13
  167. package/toggle-group/types/toggle-group.d.ts +13 -7
  168. package/tooltip/README.md +240 -34
  169. package/tooltip/fesm2022/tooltip.mjs +14 -14
  170. package/typography/README.md +271 -5
  171. package/typography/fesm2022/typography.mjs +53 -53
  172. package/typography/types/typography.d.ts +12 -12
  173. package/utils/README.md +274 -34
  174. package/utils/fesm2022/utils.mjs +68 -44
  175. package/accordion/fesm2022/accordion.mjs.map +0 -1
  176. package/alert/fesm2022/alert.mjs.map +0 -1
  177. package/alert-dialog/fesm2022/alert-dialog.mjs.map +0 -1
  178. package/aspect-ratio/fesm2022/aspect-ratio.mjs.map +0 -1
  179. package/autocomplete/fesm2022/autocomplete.mjs.map +0 -1
  180. package/avatar/fesm2022/avatar.mjs.map +0 -1
  181. package/badge/fesm2022/badge.mjs.map +0 -1
  182. package/basic-alert/fesm2022/basic-alert.mjs.map +0 -1
  183. package/breadcrumb/fesm2022/breadcrumb.mjs.map +0 -1
  184. package/button/fesm2022/button.mjs.map +0 -1
  185. package/button-group/fesm2022/button-group.mjs.map +0 -1
  186. package/calendar/fesm2022/calendar.mjs.map +0 -1
  187. package/card/fesm2022/card.mjs.map +0 -1
  188. package/carousel/fesm2022/carousel.mjs.map +0 -1
  189. package/checkbox/fesm2022/checkbox.mjs.map +0 -1
  190. package/collapsible/fesm2022/collapsible.mjs.map +0 -1
  191. package/combobox/fesm2022/combobox.mjs.map +0 -1
  192. package/command/fesm2022/command.mjs.map +0 -1
  193. package/confirmation-dialog/fesm2022/confirmation-dialog.mjs.map +0 -1
  194. package/context-menu/fesm2022/context-menu.mjs.map +0 -1
  195. package/date-picker/fesm2022/date-picker.mjs.map +0 -1
  196. package/dialog/fesm2022/dialog.mjs.map +0 -1
  197. package/drawer/fesm2022/drawer.mjs.map +0 -1
  198. package/dropdown-menu/fesm2022/dropdown-menu.mjs.map +0 -1
  199. package/empty/fesm2022/empty.mjs.map +0 -1
  200. package/field/fesm2022/field.mjs.map +0 -1
  201. package/form-checkbox/fesm2022/form-checkbox.mjs.map +0 -1
  202. package/form-date-picker/fesm2022/form-date-picker.mjs.map +0 -1
  203. package/form-field/fesm2022/form-field.mjs.map +0 -1
  204. package/form-field-simple/fesm2022/form-field-simple.mjs.map +0 -1
  205. package/form-searchable-multiselect/fesm2022/form-searchable-multiselect.mjs.map +0 -1
  206. package/form-select/fesm2022/form-select.mjs.map +0 -1
  207. package/form-text-input/fesm2022/form-text-input.mjs.map +0 -1
  208. package/form-textarea/fesm2022/form-textarea.mjs.map +0 -1
  209. package/hover-card/fesm2022/hover-card.mjs.map +0 -1
  210. package/icon/fesm2022/icon.mjs.map +0 -1
  211. package/input/fesm2022/input.mjs.map +0 -1
  212. package/input-group/fesm2022/input-group.mjs.map +0 -1
  213. package/input-otp/fesm2022/input-otp.mjs.map +0 -1
  214. package/item/fesm2022/item.mjs.map +0 -1
  215. package/kbd/fesm2022/kbd.mjs.map +0 -1
  216. package/label/fesm2022/label.mjs.map +0 -1
  217. package/layout-simple/fesm2022/layout-simple.mjs.map +0 -1
  218. package/menubar/fesm2022/menubar.mjs.map +0 -1
  219. package/native-select/fesm2022/native-select.mjs.map +0 -1
  220. package/navigation-menu/fesm2022/navigation-menu.mjs.map +0 -1
  221. package/pagination/fesm2022/pagination.mjs.map +0 -1
  222. package/popover/fesm2022/popover.mjs.map +0 -1
  223. package/progress/fesm2022/progress.mjs.map +0 -1
  224. package/radio-group/fesm2022/radio-group.mjs.map +0 -1
  225. package/resizable/fesm2022/resizable.mjs.map +0 -1
  226. package/scroll-area/fesm2022/scroll-area.mjs.map +0 -1
  227. package/searchable-multiselect/fesm2022/searchable-multiselect.mjs.map +0 -1
  228. package/select/fesm2022/select.mjs.map +0 -1
  229. package/separator/fesm2022/separator.mjs.map +0 -1
  230. package/sheet/fesm2022/sheet.mjs.map +0 -1
  231. package/sidebar/fesm2022/sidebar.mjs.map +0 -1
  232. package/skeleton/fesm2022/skeleton.mjs.map +0 -1
  233. package/slider/fesm2022/slider.mjs.map +0 -1
  234. package/sonner/fesm2022/sonner.mjs.map +0 -1
  235. package/spinner/fesm2022/spinner.mjs.map +0 -1
  236. package/switch/fesm2022/switch.mjs.map +0 -1
  237. package/table/fesm2022/table.mjs.map +0 -1
  238. package/tabs/fesm2022/tabs.mjs.map +0 -1
  239. package/textarea/fesm2022/textarea.mjs.map +0 -1
  240. package/toggle/fesm2022/toggle.mjs.map +0 -1
  241. package/toggle-group/fesm2022/toggle-group.mjs.map +0 -1
  242. package/tooltip/fesm2022/tooltip.mjs.map +0 -1
  243. package/typography/fesm2022/typography.mjs.map +0 -1
  244. package/utils/fesm2022/utils.mjs.map +0 -1
@@ -1,11 +1,329 @@
1
- # NativeSelect
1
+ # Native Select (`@egose/shadcn-theme-ng/native-select`)
2
2
 
3
- This project was generated using [Angular CLI](https://github.com/angular/angular-cli).
3
+ Zero-dependency HTML `<select>` with shadcn styling (shadcn/ui `native-select` equivalent). No overlay, no CDK menu, no listbox emulation — a real `<select>` inside a positioning wrapper with a chevron icon, wired as an Angular `ControlValueAccessor` and a spartan-ng `BrnFieldControl`/`BrnLabelable` so it participates in `formControl`/`ngModel`, `hlm-label` association, and field error states.
4
4
 
5
- ## Building
5
+ Ships as `@egose/shadcn-theme-ng/native-select` and `@egose/shadcn-theme-ng-tw/native-select` (tw: variant). See the [package README](../../README.md) for installation, peer dependencies, Tailwind setup, and testing. Do not publish this project directory independently.
6
6
 
7
- To build the library, run:
7
+ ## Installation
8
8
 
9
9
  ```bash
10
- ng build native-select
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
+ Peer dependencies are inherited from the package root (see [package README](../../README.md)). This subpath itself declares `@angular/common`, `@angular/core`, `@spartan-ng/brain` as peers plus a `tslib` runtime dependency; at runtime it also uses `@ng-icons/lucide` (`lucideChevronDown`), `@spartan-ng/brain/field`, and `@spartan-ng/brain/forms` types. No extra install step is needed beyond the package install above.
18
+
19
+ ## Imports
20
+
21
+ Real exported symbols (from `src/public-api.ts`):
22
+
23
+ ```ts
24
+ import {
25
+ HlmNativeSelect, // component: hlm-native-select (CVA)
26
+ HlmNativeSelectOption, // directive: option[hlmNativeSelectOption]
27
+ HlmNativeSelectOptGroup, // directive: optgroup[hlmNativeSelectOptGroup]
28
+ HLM_NATIVE_SELECT_VALUE_ACCESSOR, // NG_VALUE_ACCESSOR provider const
29
+ HlmNativeSelectImports, // readonly [HlmNativeSelect, HlmNativeSelectOption, HlmNativeSelectOptGroup]
30
+ HlmNativeSelectModule, // NgModule wrapping HlmNativeSelectImports
31
+ } from '@egose/shadcn-theme-ng/native-select';
32
+ ```
33
+
34
+ Standalone usage:
35
+
36
+ ```ts
37
+ import { Component } from '@angular/core';
38
+ import { HlmNativeSelectImports } from '@egose/shadcn-theme-ng/native-select';
39
+
40
+ @Component({
41
+ selector: 'app-demo',
42
+ standalone: true,
43
+ imports: [...HlmNativeSelectImports],
44
+ template: `
45
+ <hlm-native-select>
46
+ <option hlmNativeSelectOption value="apple">Apple</option>
47
+ </hlm-native-select>
48
+ `,
49
+ })
50
+ export class DemoComponent {}
51
+ ```
52
+
53
+ NgModule usage:
54
+
55
+ ```ts
56
+ import { NgModule } from '@angular/core';
57
+ import { HlmNativeSelectModule } from '@egose/shadcn-theme-ng/native-select';
58
+
59
+ @NgModule({ imports: [HlmNativeSelectModule] })
60
+ export class DemoModule {}
61
+ ```
62
+
63
+ For the `tw:` build, swap the specifier to `@egose/shadcn-theme-ng-tw/native-select`. Symbol names are identical.
64
+
65
+ ## Anatomy / Structure
66
+
67
+ ```html
68
+ <hlm-native-select>
69
+ <option hlmNativeSelectOption value="">Choose a fruit…</option>
70
+ <optgroup hlmNativeSelectOptGroup label="Citrus">
71
+ <option hlmNativeSelectOption value="orange">Orange</option>
72
+ <option hlmNativeSelectOption value="lemon">Lemon</option>
73
+ </optgroup>
74
+ <option hlmNativeSelectOption value="apple">Apple</option>
75
+ </hlm-native-select>
76
+
77
+ <!-- sizes + classes -->
78
+ <hlm-native-select size="sm" selectClass="tw:w-48" selectIconClass="tw:text-primary">
79
+ <option hlmNativeSelectOption value="s">Small</option>
80
+ </hlm-native-select>
81
+ ```
82
+
83
+ Rendered DOM: the host (`data-slot="native-select-wrapper"`, `group/native-select relative w-fit`) projects your options into an inner native `<select data-slot="native-select">` plus an absolutely-positioned `lucideChevronDown` icon (`data-slot="native-select-icon"`). The inner select carries `data-size`, `data-invalid`, `data-dirty`, `data-touched`, and `data-matches-spartan-invalid` attributes for styling hooks.
84
+
85
+ | Class | Selector | Role |
86
+ | ------------------------- | ----------------------------------- | ------------------------------------------------------------------------------------------ |
87
+ | `HlmNativeSelect` | `hlm-native-select` | Wrapper + CVA + chevron |
88
+ | `HlmNativeSelectOption` | `option[hlmNativeSelectOption]` | Styled `<option>` (`bg-[Canvas] text-[CanvasText]` so dropdown lists stay native-readable) |
89
+ | `HlmNativeSelectOptGroup` | `optgroup[hlmNativeSelectOptGroup]` | Styled `<optgroup>` (same Canvas treatment) |
90
+
91
+ ## API reference
92
+
93
+ ### `HlmNativeSelect` (`hlm-native-select`, implements `ControlValueAccessor`)
94
+
95
+ | Member | Kind | Type / Default | Notes |
96
+ | ------------------------------------------------ | ------------- | --------------------------------------- | ------------------------------------------------------------------------------------------------- |
97
+ | `selectId` | input | `string`, auto `hlm-native-select-${n}` | Applied as the inner `<select>`'s `id`; also exposed as `labelableId` for `hlm-label` association |
98
+ | `selectClass` | input | `ClassValue`, `''` | Merged over the inner select classes |
99
+ | `selectIconClass` | input | `ClassValue`, `''` | Merged over the chevron icon classes |
100
+ | `size` | input | `'sm' \| 'default'`, `'default'` | Reflected as `data-size` on host + select; `sm` → `h-8` instead of `h-9` |
101
+ | `disabled` | input | `boolean`, `false` (boolean coercion) | Initial disabled; reactive forms override via `setDisabledState` into `_disabled` linked signal |
102
+ | `forceInvalid` | input | `boolean`, `false` (boolean coercion) | Forces `data-matches-spartan-invalid` styling |
103
+ | `ariaInvalidOverride` (alias `aria-invalid`) | input | `boolean \| undefined`, `undefined` | Manual `aria-invalid`; defaults to the parent `BrnFieldControl.invalid` state |
104
+ | `valueInput` (alias `value`) | input | `string \| undefined \| null`, `''` | One-way value; mirrored into the `value` linked signal |
105
+ | `value` | linked signal | `string \| undefined \| null` | Current value; bound to the select's `[value]` |
106
+ | `valueChange` | output | `string \| undefined \| null` | Emitted on native `change` alongside the CVA callback |
107
+ | `labelableId` | property | = `selectId` | `BrnLabelable` contract for label association |
108
+ | `writeValue(v)` | CVA method | | Sets `value` |
109
+ | `registerOnChange(fn)` / `registerOnTouched(fn)` | CVA methods | | Stored as `_onChange` / `_onTouched`; invoked on `change` / `change`+`blur` |
110
+ | `setDisabledState(isDisabled)` | CVA method | | Sets `_disabled` |
111
+
112
+ Host directives: `BrnFieldControl` (provides `invalid`/`touched`/`dirty`/`spartanInvalid` read by the template). Providers: `NG_VALUE_ACCESSOR` (`HLM_NATIVE_SELECT_VALUE_ACCESSOR`), `provideIcons({ lucideChevronDown })`, `provideBrnLabelable(HlmNativeSelect)`.
113
+
114
+ ### `HlmNativeSelectOption` / `HlmNativeSelectOptGroup`
115
+
116
+ No inputs/outputs/methods. Pure styling directives setting `data-slot` (`native-select-option` / `native-select-optgroup`).
117
+
118
+ ## Examples
119
+
120
+ ### 1. Basic uncontrolled select
121
+
122
+ ```ts
123
+ import { Component } from '@angular/core';
124
+ import { HlmNativeSelectImports } from '@egose/shadcn-theme-ng/native-select';
125
+
126
+ @Component({
127
+ selector: 'app-native-basic',
128
+ standalone: true,
129
+ imports: [...HlmNativeSelectImports],
130
+ template: `
131
+ <hlm-native-select (valueChange)="onChange($event)">
132
+ <option hlmNativeSelectOption value="">Choose a fruit…</option>
133
+ <option hlmNativeSelectOption value="apple">Apple</option>
134
+ <option hlmNativeSelectOption value="banana">Banana</option>
135
+ </hlm-native-select>
136
+ <p class="tw:text-sm tw:text-muted-foreground">Picked: {{ picked ?? 'nothing' }}</p>
137
+ `,
138
+ })
139
+ export class NativeBasicComponent {
140
+ picked: string | null | undefined;
141
+
142
+ onChange(value: string | null | undefined): void {
143
+ this.picked = value;
144
+ }
145
+ }
11
146
  ```
147
+
148
+ ### 2. Sizes and optgroups
149
+
150
+ ```ts
151
+ import { Component } from '@angular/core';
152
+ import { HlmNativeSelectImports } from '@egose/shadcn-theme-ng/native-select';
153
+
154
+ @Component({
155
+ selector: 'app-native-groups',
156
+ standalone: true,
157
+ imports: [...HlmNativeSelectImports],
158
+ template: `
159
+ <div class="tw:flex tw:flex-col tw:gap-4 tw:max-w-xs">
160
+ <hlm-native-select size="sm">
161
+ <option hlmNativeSelectOption value="s">Small</option>
162
+ <option hlmNativeSelectOption value="m">Medium</option>
163
+ </hlm-native-select>
164
+
165
+ <hlm-native-select size="default">
166
+ <option hlmNativeSelectOption value="">Choose a citrus…</option>
167
+ <optgroup hlmNativeSelectOptGroup label="Citrus">
168
+ <option hlmNativeSelectOption value="orange">Orange</option>
169
+ <option hlmNativeSelectOption value="lemon">Lemon</option>
170
+ </optgroup>
171
+ <optgroup hlmNativeSelectOptGroup label="Berries">
172
+ <option hlmNativeSelectOption value="strawberry">Strawberry</option>
173
+ <option hlmNativeSelectOption value="blueberry">Blueberry</option>
174
+ </optgroup>
175
+ </hlm-native-select>
176
+ </div>
177
+ `,
178
+ })
179
+ export class NativeGroupsComponent {}
180
+ ```
181
+
182
+ ### 3. Reactive form + label
183
+
184
+ ```ts
185
+ import { Component } from '@angular/core';
186
+ import { ReactiveFormsModule, FormControl, FormGroup, Validators } from '@angular/forms';
187
+ import { HlmNativeSelectImports } from '@egose/shadcn-theme-ng/native-select';
188
+ import { HlmLabelImports } from '@egose/shadcn-theme-ng/label';
189
+
190
+ @Component({
191
+ selector: 'app-native-reactive',
192
+ standalone: true,
193
+ imports: [ReactiveFormsModule, ...HlmNativeSelectImports, ...HlmLabelImports],
194
+ template: `
195
+ <form [formGroup]="form" class="tw:grid tw:gap-1.5 tw:max-w-xs">
196
+ <label hlmLabel for="country">Country</label>
197
+ <hlm-native-select selectId="country" formControlName="country">
198
+ <option hlmNativeSelectOption value="">Select…</option>
199
+ <option hlmNativeSelectOption value="de">Germany</option>
200
+ <option hlmNativeSelectOption value="fr">France</option>
201
+ <option hlmNativeSelectOption value="jp">Japan</option>
202
+ </hlm-native-select>
203
+ @if (form.controls.country.touched && form.controls.country.invalid) {
204
+ <p class="tw:text-sm tw:text-destructive">Country is required.</p>
205
+ }
206
+ <button type="button" (click)="disable()">Toggle disabled</button>
207
+ </form>
208
+ `,
209
+ })
210
+ export class NativeReactiveComponent {
211
+ readonly form = new FormGroup({
212
+ country: new FormControl('', { validators: [Validators.required], nonNullable: true }),
213
+ });
214
+
215
+ disable(): void {
216
+ const c = this.form.controls.country;
217
+ c.disabled ? c.enable() : c.disable();
218
+ }
219
+ }
220
+ ```
221
+
222
+ ### 4. Template-driven (`ngModel`) + two-way `value`
223
+
224
+ ```ts
225
+ import { Component } from '@angular/core';
226
+ import { FormsModule } from '@angular/forms';
227
+ import { HlmNativeSelectImports } from '@egose/shadcn-theme-ng/native-select';
228
+
229
+ @Component({
230
+ selector: 'app-native-ngmodel',
231
+ standalone: true,
232
+ imports: [FormsModule, ...HlmNativeSelectImports],
233
+ template: `
234
+ <hlm-native-select [(ngModel)]="flavor">
235
+ <option hlmNativeSelectOption value="vanilla">Vanilla</option>
236
+ <option hlmNativeSelectOption value="chocolate">Chocolate</option>
237
+ <option hlmNativeSelectOption value="mint">Mint</option>
238
+ </hlm-native-select>
239
+ <p class="tw:text-sm">Flavor: {{ flavor }}</p>
240
+
241
+ <!-- one-way value input + valueChange output (no forms): -->
242
+ <hlm-native-select [value]="flavor" (valueChange)="flavor = $event ?? ''">
243
+ <option hlmNativeSelectOption value="vanilla">Vanilla</option>
244
+ <option hlmNativeSelectOption value="chocolate">Chocolate</option>
245
+ </hlm-native-select>
246
+ `,
247
+ })
248
+ export class NativeNgModelComponent {
249
+ flavor = 'vanilla';
250
+ }
251
+ ```
252
+
253
+ ### 5. Async options, invalid, and disabled states
254
+
255
+ ```ts
256
+ import { Component, signal, OnInit } from '@angular/core';
257
+ import { HlmNativeSelectImports } from '@egose/shadcn-theme-ng/native-select';
258
+
259
+ @Component({
260
+ selector: 'app-native-async',
261
+ standalone: true,
262
+ imports: [...HlmNativeSelectImports],
263
+ template: `
264
+ <div class="tw:grid tw:gap-4 tw:max-w-xs">
265
+ <hlm-native-select [value]="selected()" (valueChange)="selected.set($event ?? '')">
266
+ <option hlmNativeSelectOption value="">Loading…</option>
267
+ @for (c of cities(); track c) {
268
+ <option hlmNativeSelectOption [value]="c">{{ c }}</option>
269
+ }
270
+ </hlm-native-select>
271
+
272
+ <hlm-native-select [forceInvalid]="true" value="bad">
273
+ <option hlmNativeSelectOption value="bad">Forced invalid</option>
274
+ <option hlmNativeSelectOption value="good">Good</option>
275
+ </hlm-native-select>
276
+
277
+ <hlm-native-select [disabled]="true" value="locked">
278
+ <option hlmNativeSelectOption value="locked">Disabled</option>
279
+ </hlm-native-select>
280
+ </div>
281
+ `,
282
+ })
283
+ export class NativeAsyncComponent implements OnInit {
284
+ readonly cities = signal<string[]>([]);
285
+ readonly selected = signal('');
286
+
287
+ async ngOnInit(): Promise<void> {
288
+ await new Promise((r) => setTimeout(r, 300));
289
+ this.cities.set(['Berlin', 'Paris', 'Tokyo']);
290
+ }
291
+ }
292
+ ```
293
+
294
+ ### 6. Custom widths and icon tint
295
+
296
+ ```ts
297
+ import { Component } from '@angular/core';
298
+ import { HlmNativeSelectImports } from '@egose/shadcn-theme-ng/native-select';
299
+
300
+ @Component({
301
+ selector: 'app-native-styled',
302
+ standalone: true,
303
+ imports: [...HlmNativeSelectImports],
304
+ template: `
305
+ <hlm-native-select selectClass="tw:w-56" selectIconClass="tw:text-primary" size="sm">
306
+ <option hlmNativeSelectOption value="a">Compact tinted chevron</option>
307
+ <option hlmNativeSelectOption value="b">Option B</option>
308
+ </hlm-native-select>
309
+ `,
310
+ })
311
+ export class NativeStyledComponent {}
312
+ ```
313
+
314
+ ## Accessibility notes
315
+
316
+ - A native `<select>` gives you listbox semantics, keyboard support (arrows/typeahead), and mobile pickers for free — prefer it over a custom dropdown when the option list is simple.
317
+ - Associate with `<label hlmLabel for="…">` matching `selectId` (or nest contextually); invalid state flows to `aria-invalid` automatically via `BrnFieldControl` unless overridden with `aria-invalid`.
318
+ - Keep the first `<option>` a real placeholder with `value=""` when a choice is required, and validate accordingly.
319
+ - `forceInvalid` is visual + `data-*` styling; still set form errors so screen readers announce the problem.
320
+
321
+ ## Theming / CSS variables
322
+
323
+ No theming inputs. The select uses `border-input`, `ring-ring`, `bg-muted`-adjacent tokens with dark-mode (`dark:bg-input/30`) and invalid (`border-destructive ring-destructive`) treatments. Extend via `selectClass` / `selectIconClass` (merged after base classes).
324
+
325
+ ## Related subpaths
326
+
327
+ - `@egose/shadcn-theme-ng/select` — custom overlay select for searchable/rich options; use native-select when a plain `<select>` suffices.
328
+ - `@egose/shadcn-theme-ng/label` — label association via `selectId`/`labelableId`.
329
+ - `@egose/shadcn-theme-ng/form-field` — field wrapper with error display that reads the same `BrnFieldControl` state.
@@ -19,11 +19,11 @@ class HlmNativeSelect {
19
19
  ...(ngDevMode ? [{ debugName: "selectId" }] : /* istanbul ignore next */ []));
20
20
  selectClass = input('', /* @ts-ignore */
21
21
  ...(ngDevMode ? [{ debugName: "selectClass" }] : /* istanbul ignore next */ []));
22
- _computedSelectClass = computed(() => hlm('border-input placeholder:text-muted-foreground selection:bg-primary selection:text-primary-foreground dark:bg-input/30 dark:hover:bg-input/50 focus-visible:border-ring focus-visible:ring-ring/50 data-[matches-spartan-invalid=true]:ring-destructive/20 dark:data-[matches-spartan-invalid=true]:ring-destructive/40 data-[matches-spartan-invalid=true]:border-destructive dark:data-[matches-spartan-invalid=true]:border-destructive/50 h-9 w-full min-w-0 appearance-none rounded-md border bg-transparent py-1 ps-2.5 pe-8 text-sm shadow-xs transition-[color,box-shadow] select-none focus-visible:ring-3 data-[matches-spartan-invalid=true]:ring-3 data-[size=sm]:h-8 outline-none disabled:pointer-events-none disabled:cursor-not-allowed', this.selectClass()), /* @ts-ignore */
22
+ _computedSelectClass = computed(() => hlm('tw:border-input tw:placeholder:text-muted-foreground tw:selection:bg-primary tw:selection:text-primary-foreground tw:dark:bg-input/30 tw:dark:hover:bg-input/50 tw:focus-visible:border-ring tw:focus-visible:ring-ring/50 tw:data-[matches-spartan-invalid=true]:ring-destructive/20 tw:dark:data-[matches-spartan-invalid=true]:ring-destructive/40 tw:data-[matches-spartan-invalid=true]:border-destructive tw:dark:data-[matches-spartan-invalid=true]:border-destructive/50 tw:h-9 tw:w-full tw:min-w-0 tw:appearance-none tw:rounded-md tw:border tw:bg-transparent tw:py-1 tw:ps-2.5 tw:pe-8 tw:text-sm tw:shadow-xs tw:transition-[color,box-shadow] tw:select-none tw:focus-visible:ring-3 tw:data-[matches-spartan-invalid=true]:ring-3 tw:data-[size=sm]:h-8 tw:outline-none tw:disabled:pointer-events-none tw:disabled:cursor-not-allowed', this.selectClass()), /* @ts-ignore */
23
23
  ...(ngDevMode ? [{ debugName: "_computedSelectClass" }] : /* istanbul ignore next */ []));
24
24
  selectIconClass = input('', /* @ts-ignore */
25
25
  ...(ngDevMode ? [{ debugName: "selectIconClass" }] : /* istanbul ignore next */ []));
26
- _computedSelectIconClass = computed(() => hlm('text-muted-foreground end-2.5 top-1/2 -translate-y-1/2 text-[length:--spacing(4)] pointer-events-none absolute select-none', this.selectIconClass()), /* @ts-ignore */
26
+ _computedSelectIconClass = computed(() => hlm('tw:text-muted-foreground tw:end-2.5 tw:top-1/2 tw:-translate-y-1/2 tw:text-[length:--spacing(4)] tw:pointer-events-none tw:absolute tw:select-none', this.selectIconClass()), /* @ts-ignore */
27
27
  ...(ngDevMode ? [{ debugName: "_computedSelectIconClass" }] : /* istanbul ignore next */ []));
28
28
  size = input('default', /* @ts-ignore */
29
29
  ...(ngDevMode ? [{ debugName: "size" }] : /* istanbul ignore next */ []));
@@ -50,7 +50,7 @@ class HlmNativeSelect {
50
50
  _spartanInvalid = computed(() => this.forceInvalid() || this._fieldControl?.spartanInvalid(), /* @ts-ignore */
51
51
  ...(ngDevMode ? [{ debugName: "_spartanInvalid" }] : /* istanbul ignore next */ []));
52
52
  constructor() {
53
- classes(() => 'group/native-select relative w-fit has-[select:disabled]:opacity-50');
53
+ classes(() => 'tw:group/native-select tw:relative tw:w-fit tw:has-[select:disabled]:opacity-50');
54
54
  }
55
55
  _valueChanged(event) {
56
56
  const value = event.target.value;
@@ -75,8 +75,8 @@ class HlmNativeSelect {
75
75
  setDisabledState(isDisabled) {
76
76
  this._disabled.set(isDisabled);
77
77
  }
78
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.7", ngImport: i0, type: HlmNativeSelect, deps: [], target: i0.ɵɵFactoryTarget.Component });
79
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "22.0.7", type: HlmNativeSelect, isStandalone: true, selector: "hlm-native-select", inputs: { selectId: { classPropertyName: "selectId", publicName: "selectId", isSignal: true, isRequired: false, transformFunction: null }, selectClass: { classPropertyName: "selectClass", publicName: "selectClass", isSignal: true, isRequired: false, transformFunction: null }, selectIconClass: { classPropertyName: "selectIconClass", publicName: "selectIconClass", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, forceInvalid: { classPropertyName: "forceInvalid", publicName: "forceInvalid", isSignal: true, isRequired: false, transformFunction: null }, ariaInvalidOverride: { classPropertyName: "ariaInvalidOverride", publicName: "aria-invalid", isSignal: true, isRequired: false, transformFunction: null }, valueInput: { classPropertyName: "valueInput", publicName: "value", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { valueChange: "valueChange" }, host: { attributes: { "data-slot": "native-select-wrapper" }, properties: { "attr.data-size": "size()" } }, providers: [
78
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: HlmNativeSelect, deps: [], target: i0.ɵɵFactoryTarget.Component });
79
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "22.1.3", type: HlmNativeSelect, isStandalone: true, selector: "hlm-native-select", inputs: { selectId: { classPropertyName: "selectId", publicName: "selectId", isSignal: true, isRequired: false, transformFunction: null }, selectClass: { classPropertyName: "selectClass", publicName: "selectClass", isSignal: true, isRequired: false, transformFunction: null }, selectIconClass: { classPropertyName: "selectIconClass", publicName: "selectIconClass", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, forceInvalid: { classPropertyName: "forceInvalid", publicName: "forceInvalid", isSignal: true, isRequired: false, transformFunction: null }, ariaInvalidOverride: { classPropertyName: "ariaInvalidOverride", publicName: "aria-invalid", isSignal: true, isRequired: false, transformFunction: null }, valueInput: { classPropertyName: "valueInput", publicName: "value", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { valueChange: "valueChange" }, host: { attributes: { "data-slot": "native-select-wrapper" }, properties: { "attr.data-size": "size()" } }, providers: [
80
80
  HLM_NATIVE_SELECT_VALUE_ACCESSOR,
81
81
  provideIcons({ lucideChevronDown }),
82
82
  provideBrnLabelable(HlmNativeSelect),
@@ -107,7 +107,7 @@ class HlmNativeSelect {
107
107
  />
108
108
  `, isInline: true, dependencies: [{ kind: "component", type: NgIcon, selector: "ng-icon", inputs: ["name", "svg", "size", "strokeWidth", "color"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
109
109
  }
110
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.7", ngImport: i0, type: HlmNativeSelect, decorators: [{
110
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: HlmNativeSelect, decorators: [{
111
111
  type: Component,
112
112
  args: [{
113
113
  selector: 'hlm-native-select',
@@ -154,12 +154,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.7", ngImpor
154
154
 
155
155
  class HlmNativeSelectOptGroup {
156
156
  constructor() {
157
- classes(() => 'bg-[Canvas] text-[CanvasText]');
157
+ classes(() => 'tw:bg-[Canvas] tw:text-[CanvasText]');
158
158
  }
159
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.7", ngImport: i0, type: HlmNativeSelectOptGroup, deps: [], target: i0.ɵɵFactoryTarget.Directive });
160
- static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "22.0.7", type: HlmNativeSelectOptGroup, isStandalone: true, selector: "optgroup[hlmNativeSelectOptGroup]", host: { attributes: { "data-slot": "native-select-optgroup" } }, ngImport: i0 });
159
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: HlmNativeSelectOptGroup, deps: [], target: i0.ɵɵFactoryTarget.Directive });
160
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "22.1.3", type: HlmNativeSelectOptGroup, isStandalone: true, selector: "optgroup[hlmNativeSelectOptGroup]", host: { attributes: { "data-slot": "native-select-optgroup" } }, ngImport: i0 });
161
161
  }
162
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.7", ngImport: i0, type: HlmNativeSelectOptGroup, decorators: [{
162
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: HlmNativeSelectOptGroup, decorators: [{
163
163
  type: Directive,
164
164
  args: [{
165
165
  selector: 'optgroup[hlmNativeSelectOptGroup]',
@@ -169,12 +169,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.7", ngImpor
169
169
 
170
170
  class HlmNativeSelectOption {
171
171
  constructor() {
172
- classes(() => 'bg-[Canvas] text-[CanvasText]');
172
+ classes(() => 'tw:bg-[Canvas] tw:text-[CanvasText]');
173
173
  }
174
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.7", ngImport: i0, type: HlmNativeSelectOption, deps: [], target: i0.ɵɵFactoryTarget.Directive });
175
- static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "22.0.7", type: HlmNativeSelectOption, isStandalone: true, selector: "option[hlmNativeSelectOption]", host: { attributes: { "data-slot": "native-select-option" } }, ngImport: i0 });
174
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: HlmNativeSelectOption, deps: [], target: i0.ɵɵFactoryTarget.Directive });
175
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "22.1.3", type: HlmNativeSelectOption, isStandalone: true, selector: "option[hlmNativeSelectOption]", host: { attributes: { "data-slot": "native-select-option" } }, ngImport: i0 });
176
176
  }
177
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.7", ngImport: i0, type: HlmNativeSelectOption, decorators: [{
177
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: HlmNativeSelectOption, decorators: [{
178
178
  type: Directive,
179
179
  args: [{
180
180
  selector: 'option[hlmNativeSelectOption]',
@@ -187,11 +187,11 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.7", ngImpor
187
187
  */
188
188
  const HlmNativeSelectImports = [HlmNativeSelect, HlmNativeSelectOption, HlmNativeSelectOptGroup];
189
189
  class HlmNativeSelectModule {
190
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.7", ngImport: i0, type: HlmNativeSelectModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
191
- static ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "22.0.7", ngImport: i0, type: HlmNativeSelectModule, imports: [HlmNativeSelect, HlmNativeSelectOption, HlmNativeSelectOptGroup], exports: [HlmNativeSelect, HlmNativeSelectOption, HlmNativeSelectOptGroup] });
192
- static ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "22.0.7", ngImport: i0, type: HlmNativeSelectModule, imports: [HlmNativeSelect] });
190
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: HlmNativeSelectModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
191
+ static ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "22.1.3", ngImport: i0, type: HlmNativeSelectModule, imports: [HlmNativeSelect, HlmNativeSelectOption, HlmNativeSelectOptGroup], exports: [HlmNativeSelect, HlmNativeSelectOption, HlmNativeSelectOptGroup] });
192
+ static ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: HlmNativeSelectModule, imports: [HlmNativeSelect] });
193
193
  }
194
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.7", ngImport: i0, type: HlmNativeSelectModule, decorators: [{
194
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: HlmNativeSelectModule, decorators: [{
195
195
  type: NgModule,
196
196
  args: [{
197
197
  imports: [...HlmNativeSelectImports],
@@ -204,4 +204,4 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.7", ngImpor
204
204
  */
205
205
 
206
206
  export { HLM_NATIVE_SELECT_VALUE_ACCESSOR, HlmNativeSelect, HlmNativeSelectImports, HlmNativeSelectModule, HlmNativeSelectOptGroup, HlmNativeSelectOption };
207
- //# sourceMappingURL=native-select.mjs.map
207
+