@egose/shadcn-theme-ng-tw 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/fesm2022/alert.mjs +1 -1
- 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/button-group/fesm2022/button-group.mjs +1 -1
- 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 +211 -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 +273 -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 +60 -16
- 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 +239 -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 +236 -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 +194 -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 +229 -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 +187 -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 +203 -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 +211 -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 +24 -15
- package/form-select/types/form-select.d.ts +18 -1
- package/form-slider/README.md +182 -0
- package/form-slider/fesm2022/form-slider.mjs +186 -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 +178 -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 +241 -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 +216 -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 +23 -13
- 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 +877 -409
- 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/sheet/fesm2022/sheet.mjs +1 -1
- package/sidebar/README.md +457 -5
- package/skeleton/README.md +217 -5
- package/slider/README.md +273 -5
- package/slider/fesm2022/slider.mjs +17 -13
- 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 +12 -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/switch/README.md
CHANGED
|
@@ -1,3 +1,311 @@
|
|
|
1
|
-
# Switch
|
|
1
|
+
# Switch (`@egose/shadcn-theme-ng/switch`)
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
A toggle switch, equivalent to [shadcn/ui Switch](https://ui.shadcn.com/docs/components/switch). This subpath ships `HlmSwitch` — a shadcn-styled `ControlValueAccessor` component wrapping spartan-ng's `BrnSwitch`/`BrnSwitchThumb` primitives — plus the `HlmSwitchThumb` styling directive for advanced use. Supports template-driven forms, reactive forms, and two-way `[(checked)]` binding out of the box.
|
|
4
|
+
|
|
5
|
+
> **Ships as:** `@egose/shadcn-theme-ng/switch` and `@egose/shadcn-theme-ng-tw/switch` (the `tw:`-prefixed Tailwind variant). See the [package README](../../README.md) for install steps, peer dependencies, Tailwind setup, and testing/release guidance. Do not publish this project directory independently.
|
|
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
|
+
`@spartan-ng/brain` arrives transitively; `FormsModule`/`ReactiveFormsModule` come from your app when you need form bindings. See the [package README](../../README.md) for the full peer-dependency table.
|
|
18
|
+
|
|
19
|
+
## Imports
|
|
20
|
+
|
|
21
|
+
All public symbols are re-exported from `projects/switch/src/public-api.ts`:
|
|
22
|
+
|
|
23
|
+
```ts
|
|
24
|
+
import { HlmSwitch, HlmSwitchThumb, HlmSwitchImports, HlmSwitchModule } from '@egose/shadcn-theme-ng/switch';
|
|
25
|
+
// tw variant:
|
|
26
|
+
// import { HlmSwitch, HlmSwitchThumb, HlmSwitchImports, HlmSwitchModule } from '@egose/shadcn-theme-ng-tw/switch';
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
Standalone-component usage (preferred):
|
|
30
|
+
|
|
31
|
+
```ts
|
|
32
|
+
import { Component } from '@angular/core';
|
|
33
|
+
import { HlmSwitchImports } from '@egose/shadcn-theme-ng/switch';
|
|
34
|
+
|
|
35
|
+
@Component({
|
|
36
|
+
selector: 'app-demo',
|
|
37
|
+
standalone: true,
|
|
38
|
+
imports: [...HlmSwitchImports],
|
|
39
|
+
template: `<hlm-switch />`,
|
|
40
|
+
})
|
|
41
|
+
export class DemoComponent {}
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
NgModule usage:
|
|
45
|
+
|
|
46
|
+
```ts
|
|
47
|
+
import { NgModule } from '@angular/core';
|
|
48
|
+
import { HlmSwitchModule } from '@egose/shadcn-theme-ng/switch';
|
|
49
|
+
|
|
50
|
+
@NgModule({ imports: [HlmSwitchModule] })
|
|
51
|
+
export class FeatureModule {}
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
| Symbol | Kind | Description |
|
|
55
|
+
| ------------------ | -------------------- | --------------------------------------------------------------- |
|
|
56
|
+
| `HlmSwitch` | Standalone component | `<hlm-switch>` — styled switch with `ControlValueAccessor`. |
|
|
57
|
+
| `HlmSwitchThumb` | Directive | Thumb styling for custom `brn-switch` compositions (see below). |
|
|
58
|
+
| `HlmSwitchImports` | `const` array | `[HlmSwitch, HlmSwitchThumb]` — spread into `imports: [...]`. |
|
|
59
|
+
| `HlmSwitchModule` | NgModule | Imports + re-exports both for NgModule consumers. |
|
|
60
|
+
|
|
61
|
+
## Anatomy / Structure
|
|
62
|
+
|
|
63
|
+
```html
|
|
64
|
+
<!-- basic -->
|
|
65
|
+
<hlm-switch />
|
|
66
|
+
|
|
67
|
+
<!-- with label (always associate a visible label) -->
|
|
68
|
+
<div class="flex items-center gap-2">
|
|
69
|
+
<hlm-switch id="airplane" />
|
|
70
|
+
<label hlmLabel for="airplane">Airplane mode</label>
|
|
71
|
+
</div>
|
|
72
|
+
|
|
73
|
+
<!-- two-way binding + change output -->
|
|
74
|
+
<hlm-switch [(checked)]="enabled" (changed)="onChanged($event)" />
|
|
75
|
+
|
|
76
|
+
<!-- disabled -->
|
|
77
|
+
<hlm-switch [disabled]="true" />
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
The component renders an inner `<brn-switch>` + `<brn-switch-thumb hlm>` pair. The outer `<hlm-switch>` host uses `class="contents"` and nulls its own `id`/`aria-*` attributes — set `id`, `aria-label`, `aria-labelledby`, `aria-describedby` as inputs and they are forwarded to the inner `brn-switch`.
|
|
81
|
+
|
|
82
|
+
## API reference
|
|
83
|
+
|
|
84
|
+
### `HlmSwitch` — selector `hlm-switch` (component, `ControlValueAccessor`)
|
|
85
|
+
|
|
86
|
+
| Input | Type | Default | Description |
|
|
87
|
+
| ------------------ | ------------------------------------------- | ------- | ---------------------------------------------------------------------- |
|
|
88
|
+
| `checked` | `model<boolean>` (two-way bindable) | `false` | Checked state. Supports `[(checked)]`. |
|
|
89
|
+
| `disabled` | `boolean` (coerced with `booleanAttribute`) | `false` | Disabled state (also set via `setDisabledState` from forms). |
|
|
90
|
+
| `id` | `string \| null` | `null` | Forwarded to the inner `<brn-switch>` `id` (pairs with `<label for>`). |
|
|
91
|
+
| `aria-label` | `string \| null` (alias `ariaLabel`) | `null` | Forwarded `aria-label`. |
|
|
92
|
+
| `aria-labelledby` | `string \| null` (alias `ariaLabelledby`) | `null` | Forwarded `aria-labelledby`. |
|
|
93
|
+
| `aria-describedby` | `string \| null` (alias `ariaDescribedby`) | `null` | Forwarded `aria-describedby` (e.g. hint text id). |
|
|
94
|
+
| `class` | `ClassValue` (aliased input `userClass`) | `''` | Extra classes merged onto the inner `brn-switch` track. |
|
|
95
|
+
|
|
96
|
+
| Output | Type | Description |
|
|
97
|
+
| --------- | --------- | ----------------------------------------- |
|
|
98
|
+
| `changed` | `boolean` | Emits whenever the checked state changes. |
|
|
99
|
+
|
|
100
|
+
`ControlValueAccessor` methods (used by Angular forms, not called directly): `writeValue(value: boolean)`, `registerOnChange(fn)`, `registerOnTouched(fn)`, `setDisabledState(isDisabled: boolean)`. Also exports `EG_SWITCH_VALUE_ACCESSOR` (`NG_VALUE_ACCESSOR` provider).
|
|
101
|
+
|
|
102
|
+
### `HlmSwitchThumb` — selector `brn-switch-thumb[hlm], [hlmSwitchThumb]` (directive)
|
|
103
|
+
|
|
104
|
+
Thin styling directive for hand-built `brn-switch` compositions. Only one input:
|
|
105
|
+
|
|
106
|
+
| Input | Type | Default | Description |
|
|
107
|
+
| ------- | ------------ | ------- | -------------------------------------------- |
|
|
108
|
+
| `class` | `ClassValue` | `''` | Extra classes merged onto the thumb element. |
|
|
109
|
+
|
|
110
|
+
You rarely need this — `<hlm-switch>` already includes `<brn-switch-thumb hlm />` internally.
|
|
111
|
+
|
|
112
|
+
## Examples
|
|
113
|
+
|
|
114
|
+
### 1. Basic usage with label
|
|
115
|
+
|
|
116
|
+
```ts
|
|
117
|
+
// demo-basic.component.ts
|
|
118
|
+
import { Component } from '@angular/core';
|
|
119
|
+
import { HlmSwitchImports } from '@egose/shadcn-theme-ng/switch';
|
|
120
|
+
import { HlmLabel } from '@egose/shadcn-theme-ng/label';
|
|
121
|
+
|
|
122
|
+
@Component({
|
|
123
|
+
selector: 'demo-basic',
|
|
124
|
+
standalone: true,
|
|
125
|
+
imports: [...HlmSwitchImports, HlmLabel],
|
|
126
|
+
template: `
|
|
127
|
+
<div class="flex items-center gap-2">
|
|
128
|
+
<hlm-switch id="airplane" />
|
|
129
|
+
<label hlmLabel for="airplane">Airplane mode</label>
|
|
130
|
+
</div>
|
|
131
|
+
`,
|
|
132
|
+
})
|
|
133
|
+
export class DemoBasic {}
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
### 2. Two-way binding + `changed` output
|
|
137
|
+
|
|
138
|
+
```ts
|
|
139
|
+
// demo-bound.component.ts
|
|
140
|
+
import { Component, signal } from '@angular/core';
|
|
141
|
+
import { HlmSwitchImports } from '@egose/shadcn-theme-ng/switch';
|
|
142
|
+
|
|
143
|
+
@Component({
|
|
144
|
+
selector: 'demo-bound',
|
|
145
|
+
standalone: true,
|
|
146
|
+
imports: [...HlmSwitchImports],
|
|
147
|
+
template: `
|
|
148
|
+
<hlm-switch [(checked)]="enabled" (changed)="log($event)" aria-label="Enable notifications" />
|
|
149
|
+
<p class="text-sm text-muted-foreground">Notifications {{ enabled() ? 'on' : 'off' }}</p>
|
|
150
|
+
`,
|
|
151
|
+
})
|
|
152
|
+
export class DemoBound {
|
|
153
|
+
readonly enabled = signal(true);
|
|
154
|
+
|
|
155
|
+
log(v: boolean) {
|
|
156
|
+
console.log('switch changed:', v);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
### 3. Reactive forms (`formControl`)
|
|
162
|
+
|
|
163
|
+
`HlmSwitch` implements `ControlValueAccessor`, so `formControl` / `formControlName` work directly.
|
|
164
|
+
|
|
165
|
+
```ts
|
|
166
|
+
// demo-reactive.component.ts
|
|
167
|
+
import { Component } from '@angular/core';
|
|
168
|
+
import { FormControl, FormGroup, ReactiveFormsModule } from '@angular/forms';
|
|
169
|
+
import { HlmSwitchImports } from '@egose/shadcn-theme-ng/switch';
|
|
170
|
+
|
|
171
|
+
@Component({
|
|
172
|
+
selector: 'demo-reactive',
|
|
173
|
+
standalone: true,
|
|
174
|
+
imports: [...HlmSwitchImports, ReactiveFormsModule],
|
|
175
|
+
template: `
|
|
176
|
+
<form [formGroup]="form" class="flex items-center gap-2">
|
|
177
|
+
<hlm-switch formControlName="marketing" id="marketing" />
|
|
178
|
+
<label for="marketing">Marketing emails</label>
|
|
179
|
+
</form>
|
|
180
|
+
<p class="text-sm">Value: {{ form.value | json }}</p>
|
|
181
|
+
`,
|
|
182
|
+
})
|
|
183
|
+
export class DemoReactive {
|
|
184
|
+
readonly form = new FormGroup({ marketing: new FormControl(false) });
|
|
185
|
+
}
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
### 4. Template-driven forms (`ngModel`)
|
|
189
|
+
|
|
190
|
+
```ts
|
|
191
|
+
// demo-template.component.ts
|
|
192
|
+
import { Component } from '@angular/core';
|
|
193
|
+
import { FormsModule } from '@angular/forms';
|
|
194
|
+
import { HlmSwitchImports } from '@egose/shadcn-theme-ng/switch';
|
|
195
|
+
|
|
196
|
+
@Component({
|
|
197
|
+
selector: 'demo-template',
|
|
198
|
+
standalone: true,
|
|
199
|
+
imports: [...HlmSwitchImports, FormsModule],
|
|
200
|
+
template: `
|
|
201
|
+
<hlm-switch [(ngModel)]="dark" name="dark" aria-label="Dark mode" />
|
|
202
|
+
<p class="text-sm">Dark mode {{ dark ? 'on' : 'off' }}</p>
|
|
203
|
+
`,
|
|
204
|
+
})
|
|
205
|
+
export class DemoTemplate {
|
|
206
|
+
dark = false;
|
|
207
|
+
}
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
### 5. Disabled / loading states
|
|
211
|
+
|
|
212
|
+
```ts
|
|
213
|
+
// demo-states.component.ts
|
|
214
|
+
import { Component, signal } from '@angular/core';
|
|
215
|
+
import { HlmSwitchImports } from '@egose/shadcn-theme-ng/switch';
|
|
216
|
+
|
|
217
|
+
@Component({
|
|
218
|
+
selector: 'demo-states',
|
|
219
|
+
standalone: true,
|
|
220
|
+
imports: [...HlmSwitchImports],
|
|
221
|
+
template: `
|
|
222
|
+
<div class="flex flex-col gap-3">
|
|
223
|
+
<div class="flex items-center gap-2">
|
|
224
|
+
<hlm-switch [checked]="true" [disabled]="true" />
|
|
225
|
+
<span class="text-sm">On, disabled</span>
|
|
226
|
+
</div>
|
|
227
|
+
<div class="flex items-center gap-2">
|
|
228
|
+
<hlm-switch [checked]="false" [disabled]="true" />
|
|
229
|
+
<span class="text-sm">Off, disabled</span>
|
|
230
|
+
</div>
|
|
231
|
+
<div class="flex items-center gap-2">
|
|
232
|
+
<hlm-switch [disabled]="saving()" aria-label="Sync" />
|
|
233
|
+
<span class="text-sm">{{ saving() ? 'Saving…' : 'Sync enabled' }}</span>
|
|
234
|
+
</div>
|
|
235
|
+
</div>
|
|
236
|
+
`,
|
|
237
|
+
})
|
|
238
|
+
export class DemoStates {
|
|
239
|
+
readonly saving = signal(true);
|
|
240
|
+
}
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
> Disabled switches render `cursor-not-allowed` + `opacity-50` automatically via `data-[disabled=true]` styles.
|
|
244
|
+
|
|
245
|
+
### 6. Advanced: settings list + custom thumb composition
|
|
246
|
+
|
|
247
|
+
Settings-list pattern with descriptions wired via `aria-describedby`:
|
|
248
|
+
|
|
249
|
+
```ts
|
|
250
|
+
// demo-settings.component.ts
|
|
251
|
+
import { Component, signal } from '@angular/core';
|
|
252
|
+
import { HlmSwitchImports } from '@egose/shadcn-theme-ng/switch';
|
|
253
|
+
|
|
254
|
+
@Component({
|
|
255
|
+
selector: 'demo-settings',
|
|
256
|
+
standalone: true,
|
|
257
|
+
imports: [...HlmSwitchImports],
|
|
258
|
+
template: `
|
|
259
|
+
<div class="flex items-center justify-between gap-4 rounded-lg border p-4">
|
|
260
|
+
<div>
|
|
261
|
+
<p class="text-sm font-medium">Two-factor authentication</p>
|
|
262
|
+
<p id="tfa-hint" class="text-sm text-muted-foreground">Require a code at sign-in.</p>
|
|
263
|
+
</div>
|
|
264
|
+
<hlm-switch [(checked)]="tfa" aria-describedby="tfa-hint" aria-label="Two-factor authentication" />
|
|
265
|
+
</div>
|
|
266
|
+
`,
|
|
267
|
+
})
|
|
268
|
+
export class DemoSettings {
|
|
269
|
+
readonly tfa = signal(false);
|
|
270
|
+
}
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
Custom composition with `HlmSwitchThumb` directly on a `brn-switch` (rare — only when you need full control of the track):
|
|
274
|
+
|
|
275
|
+
```ts
|
|
276
|
+
// demo-custom.component.ts
|
|
277
|
+
import { Component } from '@angular/core';
|
|
278
|
+
import { BrnSwitch, BrnSwitchThumb } from '@spartan-ng/brain/switch';
|
|
279
|
+
import { HlmSwitchThumb } from '@egose/shadcn-theme-ng/switch';
|
|
280
|
+
|
|
281
|
+
@Component({
|
|
282
|
+
selector: 'demo-custom',
|
|
283
|
+
standalone: true,
|
|
284
|
+
imports: [BrnSwitch, BrnSwitchThumb, HlmSwitchThumb],
|
|
285
|
+
template: `
|
|
286
|
+
<brn-switch class="my-track-classes">
|
|
287
|
+
<brn-switch-thumb hlm class="my-thumb-overrides" />
|
|
288
|
+
</brn-switch>
|
|
289
|
+
`,
|
|
290
|
+
})
|
|
291
|
+
export class DemoCustom {}
|
|
292
|
+
```
|
|
293
|
+
|
|
294
|
+
## Accessibility notes
|
|
295
|
+
|
|
296
|
+
- A switch must always have an accessible name: pair it with a visible `<label>` (via matching `id`/`for`), or set `aria-label` / `aria-labelledby`.
|
|
297
|
+
- Use `aria-describedby` to associate hint text, as in the settings example above.
|
|
298
|
+
- The inner `brn-switch` handles `role="switch"`, `aria-checked`, and keyboard interaction (Space/Enter); do not add your own key handlers.
|
|
299
|
+
- Disabled switches are exposed as `aria-disabled`/`data-[disabled=true]` — keep them focusable-visible but non-interactive, and explain _why_ they are disabled in nearby text when it is not obvious.
|
|
300
|
+
- Prefer switches for immediate-effect on/off settings; use a checkbox for multi-select or form-submission choices.
|
|
301
|
+
|
|
302
|
+
## Theming / CSS variables
|
|
303
|
+
|
|
304
|
+
The track uses theme tokens (`data-[state=checked]:bg-primary`, `bg-input`, `border-ring`, `ring-ring/50`) and the thumb uses `bg-background` / dark-mode `bg-foreground` / `bg-primary-foreground` shifts. Both follow your shadcn CSS-variable theme. Pass `class` to append/override track utilities (merged with `hlm()`).
|
|
305
|
+
|
|
306
|
+
## Related subpaths
|
|
307
|
+
|
|
308
|
+
- `@egose/shadcn-theme-ng/label` — accessible labels for switches.
|
|
309
|
+
- `@egose/shadcn-theme-ng/checkbox` — alternative boolean control for forms.
|
|
310
|
+
- `@egose/shadcn-theme-ng/form-checkbox` — labeled checkbox+description field pattern.
|
|
311
|
+
- `@egose/shadcn-theme-ng/toggle` — press-state button (vs. a switch track).
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
|
-
import { input, computed, Directive, forwardRef, model, booleanAttribute, output,
|
|
2
|
+
import { input, computed, Directive, forwardRef, model, booleanAttribute, output, signal, ChangeDetectionStrategy, Component, NgModule } from '@angular/core';
|
|
3
3
|
import { NG_VALUE_ACCESSOR } from '@angular/forms';
|
|
4
4
|
import { BrnSwitchThumb, BrnSwitch } from '@spartan-ng/brain/switch';
|
|
5
5
|
import { hlm } from '@egose/shadcn-theme-ng-tw/utils';
|
|
@@ -46,7 +46,9 @@ class HlmSwitch {
|
|
|
46
46
|
ariaDescribedby = input(null, { ...(ngDevMode ? { debugName: "ariaDescribedby" } : /* istanbul ignore next */ {}), alias: 'aria-describedby' });
|
|
47
47
|
/** Emits when the checked state of the switch changes. */
|
|
48
48
|
changed = output();
|
|
49
|
-
|
|
49
|
+
_formDisabled = signal(false, /* @ts-ignore */
|
|
50
|
+
...(ngDevMode ? [{ debugName: "_formDisabled" }] : /* istanbul ignore next */ []));
|
|
51
|
+
_disabled = computed(() => this.disabled() || this._formDisabled(), /* @ts-ignore */
|
|
50
52
|
...(ngDevMode ? [{ debugName: "_disabled" }] : /* istanbul ignore next */ []));
|
|
51
53
|
_onChange;
|
|
52
54
|
_onTouched;
|
|
@@ -67,14 +69,14 @@ class HlmSwitch {
|
|
|
67
69
|
this._onTouched = fn;
|
|
68
70
|
}
|
|
69
71
|
setDisabledState(isDisabled) {
|
|
70
|
-
this.
|
|
72
|
+
this._formDisabled.set(isDisabled);
|
|
71
73
|
}
|
|
72
74
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: HlmSwitch, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
73
75
|
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "22.1.3", type: HlmSwitch, isStandalone: true, selector: "hlm-switch", inputs: { userClass: { classPropertyName: "userClass", publicName: "class", isSignal: true, isRequired: false, transformFunction: null }, checked: { classPropertyName: "checked", publicName: "checked", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", 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 } }, outputs: { checked: "checkedChange", changed: "changed" }, host: { properties: { "attr.id": "null", "attr.aria-label": "null", "attr.aria-labelledby": "null", "attr.aria-describedby": "null" }, classAttribute: "contents" }, providers: [EG_SWITCH_VALUE_ACCESSOR], ngImport: i0, template: `
|
|
74
76
|
<brn-switch
|
|
75
77
|
[class]="_computedClass()"
|
|
76
78
|
[checked]="checked()"
|
|
77
|
-
(
|
|
79
|
+
(checkedChange)="handleChange($event)"
|
|
78
80
|
(touched)="_onTouched?.()"
|
|
79
81
|
[disabled]="_disabled()"
|
|
80
82
|
[id]="id()"
|
|
@@ -103,7 +105,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImpor
|
|
|
103
105
|
<brn-switch
|
|
104
106
|
[class]="_computedClass()"
|
|
105
107
|
[checked]="checked()"
|
|
106
|
-
(
|
|
108
|
+
(checkedChange)="handleChange($event)"
|
|
107
109
|
(touched)="_onTouched?.()"
|
|
108
110
|
[disabled]="_disabled()"
|
|
109
111
|
[id]="id()"
|
package/switch/types/switch.d.ts
CHANGED
|
@@ -26,7 +26,8 @@ declare class HlmSwitch implements ControlValueAccessor {
|
|
|
26
26
|
readonly ariaDescribedby: _angular_core.InputSignal<string | null>;
|
|
27
27
|
/** Emits when the checked state of the switch changes. */
|
|
28
28
|
readonly changed: _angular_core.OutputEmitterRef<boolean>;
|
|
29
|
-
|
|
29
|
+
private readonly _formDisabled;
|
|
30
|
+
protected readonly _disabled: _angular_core.Signal<boolean>;
|
|
30
31
|
protected _onChange?: ChangeFn<boolean>;
|
|
31
32
|
protected _onTouched?: TouchFn;
|
|
32
33
|
protected handleChange(value: unknown): void;
|