@egose/shadcn-theme-ng 0.1.0 → 0.3.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.
- package/README.md +2 -2
- package/accordion/README.md +405 -2
- package/alert/README.md +372 -2
- package/alert-dialog/README.md +471 -5
- package/aspect-ratio/README.md +272 -5
- package/autocomplete/README.md +502 -2
- package/autocomplete/fesm2022/autocomplete.mjs +1 -1
- package/avatar/README.md +357 -5
- package/badge/README.md +318 -2
- package/basic-alert/README.md +353 -2
- package/breadcrumb/README.md +406 -5
- package/button/README.md +482 -2
- package/button/fesm2022/button.mjs +85 -107
- package/button/types/button.d.ts +5 -8
- package/button-group/README.md +318 -5
- package/calendar/README.md +357 -2
- package/card/README.md +331 -5
- package/carousel/README.md +333 -5
- package/carousel/fesm2022/carousel.mjs +4 -1
- package/checkbox/README.md +320 -2
- package/checkbox/fesm2022/checkbox.mjs +6 -7
- package/checkbox/types/checkbox.d.ts +1 -1
- package/collapsible/README.md +332 -5
- package/combobox/README.md +507 -5
- package/combobox/fesm2022/combobox.mjs +5 -2
- package/command/README.md +435 -5
- package/confirmation-dialog/README.md +301 -2
- package/context-menu/README.md +366 -5
- package/date-picker/README.md +469 -2
- package/date-picker/fesm2022/date-picker.mjs +150 -32
- package/date-picker/types/date-picker.d.ts +102 -9
- package/dialog/README.md +448 -2
- package/drawer/README.md +395 -5
- package/dropdown-menu/README.md +417 -5
- package/empty/README.md +329 -5
- package/field/README.md +385 -5
- package/form-autocomplete/README.md +177 -0
- package/form-autocomplete/fesm2022/form-autocomplete.mjs +125 -0
- package/form-autocomplete/package.json +24 -0
- package/form-autocomplete/types/form-autocomplete.d.ts +61 -0
- package/form-checkbox/README.md +322 -2
- package/form-checkbox/fesm2022/form-checkbox.mjs +22 -9
- package/form-checkbox/types/form-checkbox.d.ts +23 -4
- package/form-combobox/README.md +202 -0
- package/form-combobox/fesm2022/form-combobox.mjs +147 -0
- package/form-combobox/package.json +24 -0
- package/form-combobox/types/form-combobox.d.ts +73 -0
- package/form-date-picker/README.md +348 -2
- package/form-date-picker/fesm2022/form-date-picker.mjs +38 -12
- package/form-date-picker/types/form-date-picker.d.ts +17 -1
- package/form-date-picker-multi/README.md +191 -0
- package/form-date-picker-multi/fesm2022/form-date-picker-multi.mjs +129 -0
- package/form-date-picker-multi/package.json +24 -0
- package/form-date-picker-multi/types/form-date-picker-multi.d.ts +58 -0
- package/form-date-range-picker/README.md +253 -0
- package/form-date-range-picker/fesm2022/form-date-range-picker.mjs +130 -0
- package/form-date-range-picker/package.json +24 -0
- package/form-date-range-picker/types/form-date-range-picker.d.ts +55 -0
- package/form-field/README.md +356 -2
- package/form-field-simple/README.md +340 -2
- package/form-input-otp/README.md +194 -0
- package/form-input-otp/fesm2022/form-input-otp.mjs +106 -0
- package/form-input-otp/package.json +24 -0
- package/form-input-otp/types/form-input-otp.d.ts +58 -0
- package/form-month-year-picker/README.md +188 -0
- package/form-month-year-picker/fesm2022/form-month-year-picker.mjs +125 -0
- package/form-month-year-picker/package.json +24 -0
- package/form-month-year-picker/types/form-month-year-picker.d.ts +53 -0
- package/form-native-select/README.md +205 -0
- package/form-native-select/fesm2022/form-native-select.mjs +103 -0
- package/form-native-select/package.json +24 -0
- package/form-native-select/types/form-native-select.d.ts +57 -0
- package/form-phone-input/README.md +188 -0
- package/form-phone-input/fesm2022/form-phone-input.mjs +113 -0
- package/form-phone-input/package.json +24 -0
- package/form-phone-input/types/form-phone-input.d.ts +58 -0
- package/form-radio-group/README.md +198 -0
- package/form-radio-group/fesm2022/form-radio-group.mjs +111 -0
- package/form-radio-group/package.json +24 -0
- package/form-radio-group/types/form-radio-group.d.ts +63 -0
- package/form-searchable-multiselect/README.md +371 -2
- package/form-searchable-multiselect/fesm2022/form-searchable-multiselect.mjs +19 -10
- package/form-searchable-multiselect/types/form-searchable-multiselect.d.ts +18 -1
- package/form-select/README.md +360 -2
- package/form-select/fesm2022/form-select.mjs +20 -11
- package/form-select/types/form-select.d.ts +18 -1
- package/form-slider/README.md +182 -0
- package/form-slider/fesm2022/form-slider.mjs +106 -0
- package/form-slider/package.json +24 -0
- package/form-slider/types/form-slider.d.ts +60 -0
- package/form-switch/README.md +173 -0
- package/form-switch/fesm2022/form-switch.mjs +100 -0
- package/form-switch/package.json +24 -0
- package/form-switch/types/form-switch.d.ts +50 -0
- package/form-text-input/README.md +381 -2
- package/form-text-input/fesm2022/form-text-input.mjs +19 -10
- package/form-text-input/types/form-text-input.d.ts +18 -1
- package/form-textarea/README.md +357 -2
- package/form-textarea/fesm2022/form-textarea.mjs +19 -10
- package/form-textarea/types/form-textarea.d.ts +18 -1
- package/form-toggle/README.md +186 -0
- package/form-toggle/fesm2022/form-toggle.mjs +159 -0
- package/form-toggle/package.json +24 -0
- package/form-toggle/types/form-toggle.d.ts +82 -0
- package/form-toggle-group/README.md +176 -0
- package/form-toggle-group/fesm2022/form-toggle-group.mjs +116 -0
- package/form-toggle-group/package.json +24 -0
- package/form-toggle-group/types/form-toggle-group.d.ts +65 -0
- package/hover-card/README.md +256 -5
- package/icon/README.md +239 -2
- package/input/README.md +269 -2
- package/input-group/README.md +335 -5
- package/input-group/fesm2022/input-group.mjs +22 -12
- package/input-group/types/input-group.d.ts +4 -1
- package/input-otp/README.md +375 -5
- package/item/README.md +385 -5
- package/item/fesm2022/item.mjs +3 -3
- package/kbd/README.md +291 -5
- package/label/README.md +272 -2
- package/layout-simple/README.md +193 -2
- package/layout-simple/fesm2022/layout-simple.mjs +472 -236
- package/layout-simple/types/layout-simple.d.ts +174 -137
- package/menu/README.md +417 -2
- package/menubar/README.md +343 -5
- package/native-select/README.md +323 -5
- package/native-select/fesm2022/native-select.mjs +18 -6
- package/native-select/types/native-select.d.ts +7 -2
- package/navigation-menu/README.md +369 -5
- package/package.json +57 -1
- package/pagination/README.md +388 -5
- package/phone-input/README.md +114 -0
- package/phone-input/fesm2022/phone-input.mjs +191 -0
- package/phone-input/package.json +24 -0
- package/phone-input/types/phone-input.d.ts +67 -0
- package/popover/README.md +331 -2
- package/progress/README.md +311 -5
- package/radio-group/README.md +364 -2
- package/radio-group/fesm2022/radio-group.mjs +5 -1
- package/resizable/README.md +269 -5
- package/scroll-area/README.md +233 -5
- package/searchable-multiselect/README.md +323 -2
- package/select/README.md +437 -2
- package/separator/README.md +222 -2
- package/sheet/README.md +311 -2
- package/sidebar/README.md +457 -5
- package/skeleton/README.md +217 -5
- package/slider/README.md +273 -5
- package/slider/fesm2022/slider.mjs +3 -3
- package/sonner/README.md +346 -2
- package/spinner/README.md +284 -2
- package/switch/README.md +310 -2
- package/switch/fesm2022/switch.mjs +7 -5
- package/switch/types/switch.d.ts +2 -1
- package/table/README.md +423 -5
- package/tabs/README.md +411 -2
- package/tabs/fesm2022/tabs.mjs +2 -2
- package/textarea/README.md +282 -5
- package/toggle/README.md +270 -5
- package/toggle-group/README.md +340 -5
- package/tooltip/README.md +269 -2
- package/typography/README.md +271 -5
- package/utils/README.md +303 -2
package/checkbox/README.md
CHANGED
|
@@ -1,3 +1,321 @@
|
|
|
1
|
-
# Checkbox
|
|
1
|
+
# Checkbox (`@egose/shadcn-theme-ng/checkbox`)
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
A shadcn/ui-style checkbox — the Angular port of shadcn/ui `Checkbox`. A single standalone `hlm-checkbox` component wraps `BrnCheckbox` from `@spartan-ng/brain/checkbox`, renders the `lucideCheck` icon when checked, and fully implements `ControlValueAccessor`, so it works with `[(checked)]`, `[(ngModel)]`, and reactive `FormControl`s. Supports the tri-state `boolean | 'indeterminate'` model, separate `disabled` (form-aware) vs `wrapperDisabled` (visual-only) locks, and a `changed` output.
|
|
4
|
+
|
|
5
|
+
Ships as `@egose/shadcn-theme-ng/checkbox` and `@egose/shadcn-theme-ng-tw/checkbox` (the `tw:`-prefixed variant). See the [package README](../../README.md) for install, peer dependencies, and Tailwind setup. Do not publish this project directory independently — it is consumed via the published subpath only.
|
|
6
|
+
|
|
7
|
+
## Installation
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
# Plain Tailwind (no prefix):
|
|
11
|
+
npm install @egose/shadcn-theme-ng
|
|
12
|
+
|
|
13
|
+
# Or the tw:-prefixed variant:
|
|
14
|
+
npm install @egose/shadcn-theme-ng-tw
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
Peers are listed in the [package README](../../README.md). This subpath declares `@angular/common` and `@angular/core` as peers (see `projects/checkbox/package.json`); `FormsModule`/`ReactiveFormsModule` come from your app when you use form bindings.
|
|
18
|
+
|
|
19
|
+
## Imports
|
|
20
|
+
|
|
21
|
+
```ts
|
|
22
|
+
import {
|
|
23
|
+
HlmCheckbox,
|
|
24
|
+
HlmCheckboxImports,
|
|
25
|
+
HlmCheckboxModule,
|
|
26
|
+
HLM_CHECKBOX_VALUE_ACCESSOR,
|
|
27
|
+
} from '@egose/shadcn-theme-ng/checkbox';
|
|
28
|
+
// tw variant:
|
|
29
|
+
// import { ... } from '@egose/shadcn-theme-ng-tw/checkbox';
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
Standalone:
|
|
33
|
+
|
|
34
|
+
```ts
|
|
35
|
+
import { Component } from '@angular/core';
|
|
36
|
+
import { HlmCheckboxImports } from '@egose/shadcn-theme-ng/checkbox';
|
|
37
|
+
|
|
38
|
+
@Component({
|
|
39
|
+
selector: 'app-demo',
|
|
40
|
+
standalone: true,
|
|
41
|
+
imports: [...HlmCheckboxImports],
|
|
42
|
+
template: `<hlm-checkbox />`,
|
|
43
|
+
})
|
|
44
|
+
export class DemoComponent {}
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
NgModule:
|
|
48
|
+
|
|
49
|
+
```ts
|
|
50
|
+
import { NgModule } from '@angular/core';
|
|
51
|
+
import { HlmCheckboxModule } from '@egose/shadcn-theme-ng/checkbox';
|
|
52
|
+
|
|
53
|
+
@NgModule({ imports: [HlmCheckboxModule] })
|
|
54
|
+
export class DemoModule {}
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
## Anatomy / Structure
|
|
58
|
+
|
|
59
|
+
```html
|
|
60
|
+
<!-- Two-way model binding -->
|
|
61
|
+
<hlm-checkbox [(checked)]="accept" aria-label="Accept terms" />
|
|
62
|
+
|
|
63
|
+
<!-- With visible label -->
|
|
64
|
+
<div class="flex items-center gap-2">
|
|
65
|
+
<hlm-checkbox id="marketing" [(checked)]="marketing" />
|
|
66
|
+
<label for="marketing">Email me product updates</label>
|
|
67
|
+
</div>
|
|
68
|
+
|
|
69
|
+
<!-- Reactive form -->
|
|
70
|
+
<hlm-checkbox formControlName="accept" />
|
|
71
|
+
|
|
72
|
+
<!-- Template-driven -->
|
|
73
|
+
<hlm-checkbox name="accept" [(ngModel)]="accept" />
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
Real selector: `hlm-checkbox` (element only). The host renders `class="contents peer"` so sibling label/description selectors (`peer-*`) keep working; `id` / `aria-*` attributes are nulled on the host and forwarded to the inner `brn-checkbox` instead. Set a visible label with a native `<label for>` — the component does not render label text itself.
|
|
77
|
+
|
|
78
|
+
## API reference
|
|
79
|
+
|
|
80
|
+
### `HlmCheckbox` (`hlm-checkbox`)
|
|
81
|
+
|
|
82
|
+
| Input | Type | Default | Description |
|
|
83
|
+
| -------------------------------------- | ----------------------------------- | ------- | -------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
84
|
+
| `checked` | `model<boolean \| 'indeterminate'>` | `false` | Checked state. Two-way bindable (`[(checked)]`). `'indeterminate'` renders the checked icon; clicking it resolves to `true`. |
|
|
85
|
+
| `class` (`userClass`) | `ClassValue` | `''` | Extra classes merged into the box. |
|
|
86
|
+
| `id` | `string \| null` | `null` | Forwarded to inner `brn-checkbox`. Pair with `<label for>`. |
|
|
87
|
+
| `aria-label` (`ariaLabel`) | `string \| null` | `null` | Forwarded aria-label. |
|
|
88
|
+
| `aria-labelledby` (`ariaLabelledby`) | `string \| null` | `null` | Forwarded aria-labelledby. |
|
|
89
|
+
| `aria-describedby` (`ariaDescribedby`) | `string \| null` | `null` | Forwarded aria-describedby. |
|
|
90
|
+
| `name` | `string \| null` | `null` | Forwarded `name`. |
|
|
91
|
+
| `required` | `boolean` | `false` | Forwarded `required` (boolean-coerced). |
|
|
92
|
+
| `disabled` | `boolean` | `false` | Visual + interaction lock (boolean-coerced). Clicks are ignored. |
|
|
93
|
+
| `wrapperDisabled` | `boolean` | `false` | Additional visual/interaction lock that does **not** write to a reactive form control (unlike `setDisabledState`). Useful for preview-only states. |
|
|
94
|
+
|
|
95
|
+
| Signal | Type | Description |
|
|
96
|
+
| --------------- | ----------------- | ------------------------------------------------------------------------------------------------------------ |
|
|
97
|
+
| `disabledState` | `Signal<boolean>` | `disabled() \|\| wrapperDisabled() \|\| formDisabled()` — the effective lock. Host reflects `data-disabled`. |
|
|
98
|
+
|
|
99
|
+
| Output | Payload | Description |
|
|
100
|
+
| --------- | --------- | -------------------------------------------------------------------------------------------------------------- |
|
|
101
|
+
| `changed` | `boolean` | Emitted on user toggle with the new boolean (`!previous`). Note: toggling from `'indeterminate'` emits `true`. |
|
|
102
|
+
|
|
103
|
+
ControlValueAccessor: `writeValue(value)`, `registerOnChange`, `registerOnTouched`, `setDisabledState(isDisabled)` (writes `formDisabled`, hence `disabledState`). `HLM_CHECKBOX_VALUE_ACCESSOR` (`NG_VALUE_ACCESSOR`, `forwardRef(HlmCheckbox)`, `multi: true`) is provided on the component.
|
|
104
|
+
|
|
105
|
+
## Examples
|
|
106
|
+
|
|
107
|
+
### 1. Basic with label
|
|
108
|
+
|
|
109
|
+
```ts
|
|
110
|
+
import { Component, signal } from '@angular/core';
|
|
111
|
+
import { HlmCheckboxImports } from '@egose/shadcn-theme-ng/checkbox';
|
|
112
|
+
|
|
113
|
+
@Component({
|
|
114
|
+
selector: 'app-basic-checkbox',
|
|
115
|
+
standalone: true,
|
|
116
|
+
imports: [...HlmCheckboxImports],
|
|
117
|
+
template: `
|
|
118
|
+
<div class="flex items-center gap-2">
|
|
119
|
+
<hlm-checkbox id="terms" [(checked)]="accept" />
|
|
120
|
+
<label for="terms" class="text-sm">Accept terms and conditions</label>
|
|
121
|
+
</div>
|
|
122
|
+
<p class="mt-2 text-sm">Value: {{ accept() }}</p>
|
|
123
|
+
`,
|
|
124
|
+
})
|
|
125
|
+
export class BasicCheckboxComponent {
|
|
126
|
+
readonly accept = signal<boolean | 'indeterminate'>(false);
|
|
127
|
+
}
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
### 2. Reactive form with validation
|
|
131
|
+
|
|
132
|
+
`hlm-checkbox` is a `ControlValueAccessor` — `formControlName` just works, including `disable()`.
|
|
133
|
+
|
|
134
|
+
```ts
|
|
135
|
+
import { Component } from '@angular/core';
|
|
136
|
+
import { FormControl, FormGroup, ReactiveFormsModule, Validators } from '@angular/forms';
|
|
137
|
+
import { HlmCheckboxImports } from '@egose/shadcn-theme-ng/checkbox';
|
|
138
|
+
|
|
139
|
+
@Component({
|
|
140
|
+
selector: 'app-reactive-checkbox',
|
|
141
|
+
standalone: true,
|
|
142
|
+
imports: [ReactiveFormsModule, ...HlmCheckboxImports],
|
|
143
|
+
template: `
|
|
144
|
+
<form [formGroup]="form" (ngSubmit)="submit()" class="space-y-3">
|
|
145
|
+
<div class="flex items-center gap-2">
|
|
146
|
+
<hlm-checkbox id="accept" formControlName="accept" />
|
|
147
|
+
<label for="accept" class="text-sm">I agree to the privacy policy</label>
|
|
148
|
+
</div>
|
|
149
|
+
@if (form.controls.accept.touched && form.controls.accept.invalid) {
|
|
150
|
+
<p class="text-destructive text-sm">You must accept to continue.</p>
|
|
151
|
+
}
|
|
152
|
+
<button type="submit" [disabled]="form.invalid">Continue</button>
|
|
153
|
+
<button type="button" (click)="form.controls.accept.disable()">Disable via form</button>
|
|
154
|
+
</form>
|
|
155
|
+
`,
|
|
156
|
+
})
|
|
157
|
+
export class ReactiveCheckboxComponent {
|
|
158
|
+
readonly form = new FormGroup({
|
|
159
|
+
accept: new FormControl(false, { validators: Validators.requiredTrue, nonNullable: true }),
|
|
160
|
+
});
|
|
161
|
+
submit() {
|
|
162
|
+
console.log(this.form.getRawValue());
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
### 3. Template-driven (`ngModel`)
|
|
168
|
+
|
|
169
|
+
```ts
|
|
170
|
+
import { Component } from '@angular/core';
|
|
171
|
+
import { FormsModule } from '@angular/forms';
|
|
172
|
+
import { HlmCheckboxImports } from '@egose/shadcn-theme-ng/checkbox';
|
|
173
|
+
|
|
174
|
+
@Component({
|
|
175
|
+
selector: 'app-ngmodel-checkbox',
|
|
176
|
+
standalone: true,
|
|
177
|
+
imports: [FormsModule, ...HlmCheckboxImports],
|
|
178
|
+
template: `
|
|
179
|
+
<div class="flex items-center gap-2">
|
|
180
|
+
<hlm-checkbox id="news" name="news" [(ngModel)]="subscribed" aria-label="Subscribe to newsletter" />
|
|
181
|
+
<label for="news" class="text-sm">Subscribe to newsletter</label>
|
|
182
|
+
</div>
|
|
183
|
+
`,
|
|
184
|
+
})
|
|
185
|
+
export class NgModelCheckboxComponent {
|
|
186
|
+
subscribed = true;
|
|
187
|
+
}
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
### 4. Indeterminate + select-all pattern
|
|
191
|
+
|
|
192
|
+
Parent shows `'indeterminate'` when some (not all) children are checked — the classic bulk-select header.
|
|
193
|
+
|
|
194
|
+
```ts
|
|
195
|
+
import { Component, computed, signal } from '@angular/core';
|
|
196
|
+
import { HlmCheckboxImports } from '@egose/shadcn-theme-ng/checkbox';
|
|
197
|
+
|
|
198
|
+
@Component({
|
|
199
|
+
selector: 'app-select-all',
|
|
200
|
+
standalone: true,
|
|
201
|
+
imports: [...HlmCheckboxImports],
|
|
202
|
+
template: `
|
|
203
|
+
<div class="flex items-center gap-2 border-b pb-2">
|
|
204
|
+
<hlm-checkbox id="all" [checked]="parentState()" (changed)="toggleAll($event)" aria-label="Select all files" />
|
|
205
|
+
<label for="all" class="text-sm font-medium">Select all</label>
|
|
206
|
+
</div>
|
|
207
|
+
@for (f of files(); track f.id) {
|
|
208
|
+
<div class="flex items-center gap-2 py-1">
|
|
209
|
+
<hlm-checkbox [id]="f.id" [checked]="f.done" (changed)="toggleOne(f.id, $event)" />
|
|
210
|
+
<label [for]="f.id" class="text-sm">{{ f.name }}</label>
|
|
211
|
+
</div>
|
|
212
|
+
}
|
|
213
|
+
`,
|
|
214
|
+
})
|
|
215
|
+
export class SelectAllComponent {
|
|
216
|
+
readonly files = signal([
|
|
217
|
+
{ id: 'f1', name: 'invoice.pdf', done: true },
|
|
218
|
+
{ id: 'f2', name: 'photo.png', done: false },
|
|
219
|
+
{ id: 'f3', name: 'notes.md', done: false },
|
|
220
|
+
]);
|
|
221
|
+
readonly parentState = computed<boolean | 'indeterminate'>(() => {
|
|
222
|
+
const all = this.files();
|
|
223
|
+
if (all.every((f) => f.done)) return true;
|
|
224
|
+
if (all.some((f) => f.done)) return 'indeterminate';
|
|
225
|
+
return false;
|
|
226
|
+
});
|
|
227
|
+
toggleAll(next: boolean) {
|
|
228
|
+
this.files.update((fs) => fs.map((f) => ({ ...f, done: next })));
|
|
229
|
+
}
|
|
230
|
+
toggleOne(id: string, next: boolean) {
|
|
231
|
+
this.files.update((fs) => fs.map((f) => (f.id === id ? { ...f, done: next } : f)));
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
### 5. Disabled / wrapper-disabled / required states
|
|
237
|
+
|
|
238
|
+
```ts
|
|
239
|
+
import { Component, signal } from '@angular/core';
|
|
240
|
+
import { HlmCheckboxImports } from '@egose/shadcn-theme-ng/checkbox';
|
|
241
|
+
|
|
242
|
+
@Component({
|
|
243
|
+
selector: 'app-states-checkbox',
|
|
244
|
+
standalone: true,
|
|
245
|
+
imports: [...HlmCheckboxImports],
|
|
246
|
+
template: `
|
|
247
|
+
<div class="space-y-2">
|
|
248
|
+
<div class="flex items-center gap-2">
|
|
249
|
+
<hlm-checkbox id="d1" [disabled]="true" aria-label="Disabled unchecked" />
|
|
250
|
+
<label for="d1" class="text-sm opacity-70">Disabled (unchecked)</label>
|
|
251
|
+
</div>
|
|
252
|
+
<div class="flex items-center gap-2">
|
|
253
|
+
<hlm-checkbox id="d2" [checked]="true" [disabled]="true" aria-label="Disabled checked" />
|
|
254
|
+
<label for="d2" class="text-sm opacity-70">Disabled (checked)</label>
|
|
255
|
+
</div>
|
|
256
|
+
<div class="flex items-center gap-2">
|
|
257
|
+
<hlm-checkbox id="w1" [wrapperDisabled]="preview()" aria-label="Preview lock" />
|
|
258
|
+
<label for="w1" class="text-sm">Preview lock (visual only — form value untouched)</label>
|
|
259
|
+
</div>
|
|
260
|
+
<div class="flex items-center gap-2">
|
|
261
|
+
<hlm-checkbox id="r1" [(checked)]="v" [required]="true" aria-label="Required" />
|
|
262
|
+
<label for="r1" class="text-sm">Required</label>
|
|
263
|
+
</div>
|
|
264
|
+
</div>
|
|
265
|
+
`,
|
|
266
|
+
})
|
|
267
|
+
export class StatesCheckboxComponent {
|
|
268
|
+
readonly preview = signal(true);
|
|
269
|
+
v = false;
|
|
270
|
+
}
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
### 6. Listening to `changed` + custom styling
|
|
274
|
+
|
|
275
|
+
```ts
|
|
276
|
+
import { Component } from '@angular/core';
|
|
277
|
+
import { HlmCheckboxImports } from '@egose/shadcn-theme-ng/checkbox';
|
|
278
|
+
|
|
279
|
+
@Component({
|
|
280
|
+
selector: 'app-changed-checkbox',
|
|
281
|
+
standalone: true,
|
|
282
|
+
imports: [...HlmCheckboxImports],
|
|
283
|
+
template: `
|
|
284
|
+
<div class="flex items-center gap-2">
|
|
285
|
+
<hlm-checkbox
|
|
286
|
+
id="audit"
|
|
287
|
+
class="data-[state=checked]:border-emerald-600 data-[state=checked]:bg-emerald-600"
|
|
288
|
+
aria-label="Enable audit log"
|
|
289
|
+
(changed)="onChanged($event)"
|
|
290
|
+
/>
|
|
291
|
+
<label for="audit" class="text-sm">Enable audit log</label>
|
|
292
|
+
</div>
|
|
293
|
+
<p class="mt-1 text-sm">Last event: {{ lastChanged === null ? 'none' : lastChanged }}</p>
|
|
294
|
+
`,
|
|
295
|
+
})
|
|
296
|
+
export class ChangedCheckboxComponent {
|
|
297
|
+
lastChanged: boolean | null = null;
|
|
298
|
+
onChanged(next: boolean) {
|
|
299
|
+
this.lastChanged = next;
|
|
300
|
+
console.log('checkbox changed →', next);
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
## Accessibility notes
|
|
306
|
+
|
|
307
|
+
- The component renders a native-checkbox-equivalent `brn-checkbox` with `aria-label`/`labelledby`/`describedby` forwarding — always provide one: visible `<label for>` preferred, `aria-label` for icon-only rows.
|
|
308
|
+
- `disabledState` adds `data-disabled`, `cursor-not-allowed`, and `opacity-50`; disabled boxes are skipped correctly because clicks early-return.
|
|
309
|
+
- The check glyph is decorative (`lucideCheck` icon, no text) — state is exposed via `data-[state]` / native semantics, not the icon.
|
|
310
|
+
- Tri-state: `'indeterminate'` is a visual/model state, not `aria-checked="mixed"` — if you need mixed semantics for a tree, add `aria-checked` handling at your own level and test with a screen reader.
|
|
311
|
+
|
|
312
|
+
## Theming / CSS variables
|
|
313
|
+
|
|
314
|
+
No component-specific CSS variables. The box uses `border-input`, `data-[state=checked]:bg-primary` / `text-primary-foreground`, `focus-visible:ring-ring/50`, `aria-invalid:border-destructive`, `size-4 rounded-[4px]`. Invalid-form styling integrates via `aria-invalid` ring tokens. Pass `class` to extend (merged with `hlm()`).
|
|
315
|
+
|
|
316
|
+
## Related subpaths
|
|
317
|
+
|
|
318
|
+
- `@egose/shadcn-theme-ng/form-checkbox` — labeled + described + validated field composition.
|
|
319
|
+
- `@egose/shadcn-theme-ng/label` — accessible labels for the `for`/`id` pair.
|
|
320
|
+
- `@egose/shadcn-theme-ng/field` — form layout rows that host checkboxes.
|
|
321
|
+
- `@egose/shadcn-theme-ng/icon` — `HlmIcon` sizing used by the inner check glyph.
|
|
@@ -44,13 +44,12 @@ class HlmCheckbox {
|
|
|
44
44
|
changed = output();
|
|
45
45
|
_onChange;
|
|
46
46
|
_onTouched;
|
|
47
|
-
|
|
47
|
+
_handleCheckedChange(checked) {
|
|
48
48
|
if (this.disabledState())
|
|
49
49
|
return;
|
|
50
|
-
|
|
51
|
-
this.checked
|
|
52
|
-
this.
|
|
53
|
-
this.changed.emit(!previousChecked);
|
|
50
|
+
this.checked.set(checked);
|
|
51
|
+
this._onChange?.(checked);
|
|
52
|
+
this.changed.emit(checked);
|
|
54
53
|
}
|
|
55
54
|
/** CONTROL VALUE ACCESSOR */
|
|
56
55
|
writeValue(value) {
|
|
@@ -66,14 +65,14 @@ class HlmCheckbox {
|
|
|
66
65
|
this.formDisabled.set(isDisabled);
|
|
67
66
|
}
|
|
68
67
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: HlmCheckbox, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
69
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.3", type: HlmCheckbox, isStandalone: true, selector: "hlm-checkbox", inputs: { userClass: { classPropertyName: "userClass", publicName: "class", isSignal: true, isRequired: false, transformFunction: null }, id: { classPropertyName: "id", publicName: "id", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "aria-label", isSignal: true, isRequired: false, transformFunction: null }, ariaLabelledby: { classPropertyName: "ariaLabelledby", publicName: "aria-labelledby", isSignal: true, isRequired: false, transformFunction: null }, ariaDescribedby: { classPropertyName: "ariaDescribedby", publicName: "aria-describedby", isSignal: true, isRequired: false, transformFunction: null }, checked: { classPropertyName: "checked", publicName: "checked", isSignal: true, isRequired: false, transformFunction: null }, name: { classPropertyName: "name", publicName: "name", isSignal: true, isRequired: false, transformFunction: null }, required: { classPropertyName: "required", publicName: "required", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, wrapperDisabled: { classPropertyName: "wrapperDisabled", publicName: "wrapperDisabled", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { checked: "checkedChange", changed: "changed" }, host: { properties: { "attr.id": "null", "attr.aria-label": "null", "attr.aria-labelledby": "null", "attr.aria-describedby": "null", "attr.data-disabled": "disabledState() ? \"\" : null" }, classAttribute: "contents peer" }, providers: [HLM_CHECKBOX_VALUE_ACCESSOR], ngImport: i0, template: "\n <brn-checkbox\n [id]=\"id()\"\n [name]=\"name()\"\n [class]=\"_computedClass()\"\n [checked]=\"checked()\"\n [disabled]=\"disabledState()\"\n [required]=\"required()\"\n [aria-label]=\"ariaLabel()\"\n [aria-labelledby]=\"ariaLabelledby()\"\n [aria-describedby]=\"ariaDescribedby()\"\n (
|
|
68
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.3", type: HlmCheckbox, isStandalone: true, selector: "hlm-checkbox", inputs: { userClass: { classPropertyName: "userClass", publicName: "class", isSignal: true, isRequired: false, transformFunction: null }, id: { classPropertyName: "id", publicName: "id", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "aria-label", isSignal: true, isRequired: false, transformFunction: null }, ariaLabelledby: { classPropertyName: "ariaLabelledby", publicName: "aria-labelledby", isSignal: true, isRequired: false, transformFunction: null }, ariaDescribedby: { classPropertyName: "ariaDescribedby", publicName: "aria-describedby", isSignal: true, isRequired: false, transformFunction: null }, checked: { classPropertyName: "checked", publicName: "checked", isSignal: true, isRequired: false, transformFunction: null }, name: { classPropertyName: "name", publicName: "name", isSignal: true, isRequired: false, transformFunction: null }, required: { classPropertyName: "required", publicName: "required", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, wrapperDisabled: { classPropertyName: "wrapperDisabled", publicName: "wrapperDisabled", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { checked: "checkedChange", changed: "changed" }, host: { properties: { "attr.id": "null", "attr.aria-label": "null", "attr.aria-labelledby": "null", "attr.aria-describedby": "null", "attr.data-disabled": "disabledState() ? \"\" : null" }, classAttribute: "contents peer" }, providers: [HLM_CHECKBOX_VALUE_ACCESSOR], ngImport: i0, template: "\n <brn-checkbox\n [id]=\"id()\"\n [name]=\"name()\"\n [class]=\"_computedClass()\"\n [checked]=\"checked()\"\n [disabled]=\"disabledState()\"\n [required]=\"required()\"\n [aria-label]=\"ariaLabel()\"\n [aria-labelledby]=\"ariaLabelledby()\"\n [aria-describedby]=\"ariaDescribedby()\"\n (checkedChange)=\"_handleCheckedChange($event)\"\n (touched)=\"_onTouched?.()\"\n >\n @if (checked()) {\n <span class=\"flex items-center justify-center text-current transition-none\">\n <ng-icon hlm size=\"14px\" name=\"lucideCheck\" />\n </span>\n }\n </brn-checkbox>\n ", isInline: true, dependencies: [{ kind: "component", type: BrnCheckbox, selector: "brn-checkbox", inputs: ["checked", "indeterminate", "id", "name", "class", "hostStyles", "aria-label", "aria-labelledby", "aria-describedby", "required", "disabled", "forceInvalid"], outputs: ["checkedChange", "indeterminateChange", "touched"] }, { kind: "component", type: NgIcon, selector: "ng-icon", inputs: ["name", "svg", "size", "strokeWidth", "color"] }, { kind: "directive", type: HlmIcon, selector: "ng-icon[hlm]", inputs: ["size"] }], viewProviders: [provideIcons({ lucideCheck })], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
70
69
|
}
|
|
71
70
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: HlmCheckbox, decorators: [{
|
|
72
71
|
type: Component,
|
|
73
72
|
args: [{
|
|
74
73
|
selector: 'hlm-checkbox',
|
|
75
74
|
imports: [BrnCheckbox, NgIcon, HlmIcon],
|
|
76
|
-
template: "\n <brn-checkbox\n [id]=\"id()\"\n [name]=\"name()\"\n [class]=\"_computedClass()\"\n [checked]=\"checked()\"\n [disabled]=\"disabledState()\"\n [required]=\"required()\"\n [aria-label]=\"ariaLabel()\"\n [aria-labelledby]=\"ariaLabelledby()\"\n [aria-describedby]=\"ariaDescribedby()\"\n (
|
|
75
|
+
template: "\n <brn-checkbox\n [id]=\"id()\"\n [name]=\"name()\"\n [class]=\"_computedClass()\"\n [checked]=\"checked()\"\n [disabled]=\"disabledState()\"\n [required]=\"required()\"\n [aria-label]=\"ariaLabel()\"\n [aria-labelledby]=\"ariaLabelledby()\"\n [aria-describedby]=\"ariaDescribedby()\"\n (checkedChange)=\"_handleCheckedChange($event)\"\n (touched)=\"_onTouched?.()\"\n >\n @if (checked()) {\n <span class=\"flex items-center justify-center text-current transition-none\">\n <ng-icon hlm size=\"14px\" name=\"lucideCheck\" />\n </span>\n }\n </brn-checkbox>\n ",
|
|
77
76
|
host: {
|
|
78
77
|
class: 'contents peer',
|
|
79
78
|
'[attr.id]': 'null',
|
|
@@ -35,7 +35,7 @@ declare class HlmCheckbox implements ControlValueAccessor {
|
|
|
35
35
|
readonly changed: _angular_core.OutputEmitterRef<boolean>;
|
|
36
36
|
protected _onChange?: ChangeFn<CheckboxValue>;
|
|
37
37
|
protected _onTouched?: TouchFn;
|
|
38
|
-
protected
|
|
38
|
+
protected _handleCheckedChange(checked: boolean): void;
|
|
39
39
|
/** CONTROL VALUE ACCESSOR */
|
|
40
40
|
writeValue(value: CheckboxValue): void;
|
|
41
41
|
registerOnChange(fn: ChangeFn<CheckboxValue>): void;
|