@radix-ng/primitives 1.1.0 → 1.1.1
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/fesm2022/radix-ng-primitives-autocomplete.mjs +66 -7
- package/fesm2022/radix-ng-primitives-autocomplete.mjs.map +1 -1
- package/fesm2022/radix-ng-primitives-checkbox.mjs +147 -125
- package/fesm2022/radix-ng-primitives-checkbox.mjs.map +1 -1
- package/fesm2022/radix-ng-primitives-combobox.mjs +171 -37
- package/fesm2022/radix-ng-primitives-combobox.mjs.map +1 -1
- package/fesm2022/radix-ng-primitives-core.mjs +173 -5
- package/fesm2022/radix-ng-primitives-core.mjs.map +1 -1
- package/fesm2022/radix-ng-primitives-number-field.mjs +38 -7
- package/fesm2022/radix-ng-primitives-number-field.mjs.map +1 -1
- package/fesm2022/radix-ng-primitives-radio.mjs +49 -2
- package/fesm2022/radix-ng-primitives-radio.mjs.map +1 -1
- package/fesm2022/radix-ng-primitives-select.mjs +35 -3
- package/fesm2022/radix-ng-primitives-select.mjs.map +1 -1
- package/fesm2022/radix-ng-primitives-slider.mjs +17 -2
- package/fesm2022/radix-ng-primitives-slider.mjs.map +1 -1
- package/fesm2022/radix-ng-primitives-switch.mjs +60 -7
- package/fesm2022/radix-ng-primitives-switch.mjs.map +1 -1
- package/fesm2022/radix-ng-primitives-toggle-group.mjs +25 -3
- package/fesm2022/radix-ng-primitives-toggle-group.mjs.map +1 -1
- package/package.json +1 -1
- package/types/radix-ng-primitives-autocomplete.d.ts +10 -1
- package/types/radix-ng-primitives-checkbox.d.ts +56 -43
- package/types/radix-ng-primitives-combobox.d.ts +46 -2
- package/types/radix-ng-primitives-core.d.ts +62 -4
- package/types/radix-ng-primitives-number-field.d.ts +12 -5
- package/types/radix-ng-primitives-radio.d.ts +6 -1
- package/types/radix-ng-primitives-select.d.ts +8 -1
- package/types/radix-ng-primitives-slider.d.ts +2 -1
- package/types/radix-ng-primitives-switch.d.ts +19 -3
- package/types/radix-ng-primitives-toggle-group.d.ts +5 -1
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
|
-
import { inject, model, input, booleanAttribute, output, signal, computed, effect, Directive, ElementRef,
|
|
2
|
+
import { inject, model, input, booleanAttribute, output, signal, computed, effect, Directive, ElementRef, DestroyRef, NgModule } from '@angular/core';
|
|
3
3
|
import * as i1 from '@radix-ng/primitives/core';
|
|
4
|
-
import { createContext, RdxFormUiControlBase, createCancelableChangeEventDetails, provideValueAccessor, provideFormUiState, RdxFormUiStateHost, RdxControlValueAccessor, injectNgControlState, RDX_FIELD_VALIDITY } from '@radix-ng/primitives/core';
|
|
4
|
+
import { createContext, RdxFormUiControlBase, useNativeFormControl, serializeNativeFormValue, createCancelableChangeEventDetails, provideValueAccessor, provideFormUiState, RdxFormUiStateHost, RdxControlValueAccessor, injectNgControlState, RDX_FIELD_VALIDITY } from '@radix-ng/primitives/core';
|
|
5
5
|
|
|
6
6
|
const [injectCheckboxGroupContext, provideCheckboxGroupContext] = createContext('CheckboxGroupContext', 'components/checkbox');
|
|
7
7
|
const groupContext = () => {
|
|
@@ -9,38 +9,45 @@ const groupContext = () => {
|
|
|
9
9
|
return {
|
|
10
10
|
value: group.value,
|
|
11
11
|
allValues: group.allValues,
|
|
12
|
+
form: group.form,
|
|
12
13
|
disabled: group.disabledState,
|
|
13
14
|
parentState: group.parentState,
|
|
14
15
|
controlledIds: group.controlledIds,
|
|
15
|
-
controlId: (
|
|
16
|
-
toggleValue: (
|
|
16
|
+
controlId: (value) => group.controlId(value),
|
|
17
|
+
toggleValue: (value, event) => group.toggleValue(value, event),
|
|
17
18
|
toggleAll: (event) => group.toggleAll(event),
|
|
18
|
-
registerChild: (
|
|
19
|
-
registerControl: (
|
|
19
|
+
registerChild: (value, disabled) => group.registerChild(value, disabled),
|
|
20
|
+
registerControl: (value, id) => group.registerControl(value, id)
|
|
20
21
|
};
|
|
21
22
|
};
|
|
22
23
|
let nextCheckboxGroupId = 0;
|
|
23
24
|
/**
|
|
24
|
-
* Groups a set of checkboxes that share a single array value (the
|
|
25
|
+
* Groups a set of checkboxes that share a single array value (the values of the checked boxes).
|
|
25
26
|
*
|
|
26
|
-
* Each child `rdxCheckboxRoot` participates by its `
|
|
27
|
-
* "select all" checkbox whose state is derived from `allValues`.
|
|
27
|
+
* Each child `rdxCheckboxRoot` participates by its `value` (falling back to `name`). A child marked
|
|
28
|
+
* `parent` becomes a "select all" checkbox whose state is derived from `allValues`.
|
|
28
29
|
*/
|
|
29
30
|
class RdxCheckboxGroupDirective extends RdxFormUiControlBase {
|
|
30
31
|
constructor() {
|
|
31
32
|
super();
|
|
32
|
-
/** The
|
|
33
|
+
/** The values of the currently checked checkboxes. Use with `onValueChange` or `[(value)]`. */
|
|
33
34
|
this.value = model([], /* @ts-ignore */
|
|
34
35
|
...(ngDevMode ? [{ debugName: "value" }] : /* istanbul ignore next */ []));
|
|
35
|
-
/** The
|
|
36
|
+
/** The values checked initially when the group is uncontrolled. */
|
|
36
37
|
this.defaultValue = input(/* @ts-ignore */
|
|
37
38
|
...(ngDevMode ? [undefined, { debugName: "defaultValue" }] : /* istanbul ignore next */ []));
|
|
38
|
-
/** All checkbox
|
|
39
|
+
/** All checkbox values in the group. Required for a `parent` (select-all) checkbox. */
|
|
39
40
|
this.allValues = input([], /* @ts-ignore */
|
|
40
41
|
...(ngDevMode ? [{ debugName: "allValues" }] : /* istanbul ignore next */ []));
|
|
42
|
+
/** Native form field name. Selected values are submitted as repeated entries under this name. */
|
|
43
|
+
this.name = input(/* @ts-ignore */
|
|
44
|
+
...(ngDevMode ? [undefined, { debugName: "name" }] : /* istanbul ignore next */ []));
|
|
45
|
+
/** Associates the group with an external form by id. */
|
|
46
|
+
this.form = input(/* @ts-ignore */
|
|
47
|
+
...(ngDevMode ? [undefined, { debugName: "form" }] : /* istanbul ignore next */ []));
|
|
41
48
|
/** Whether the whole group is disabled. */
|
|
42
49
|
this.disabled = input(false, { ...(ngDevMode ? { debugName: "disabled" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
43
|
-
/** Emits the new array of checked
|
|
50
|
+
/** Emits the new array of checked values whenever the value changes. */
|
|
44
51
|
this.onValueChange = output();
|
|
45
52
|
this.disabledByCva = signal(false, /* @ts-ignore */
|
|
46
53
|
...(ngDevMode ? [{ debugName: "disabledByCva" }] : /* istanbul ignore next */ []));
|
|
@@ -64,18 +71,18 @@ class RdxCheckboxGroupDirective extends RdxFormUiControlBase {
|
|
|
64
71
|
this.seeded = false;
|
|
65
72
|
/** Where the parent is in its mixed → on → off cycle. Reset to `mixed` on any direct child change. */
|
|
66
73
|
this.parentStatus = 'mixed';
|
|
67
|
-
/** Per-
|
|
68
|
-
this.
|
|
74
|
+
/** Per-value disabled signals, so the parent can preserve disabled-but-checked children. */
|
|
75
|
+
this.disabledByValue = new Map();
|
|
69
76
|
/** Stable group id used to derive child control ids when the consumer sets none. */
|
|
70
77
|
this.elementId = `rdx-checkbox-group-${nextCheckboxGroupId++}`;
|
|
71
|
-
/** Registered control element ids, keyed by child
|
|
78
|
+
/** Registered control element ids, keyed by child value. */
|
|
72
79
|
this.controlIds = signal({}, /* @ts-ignore */
|
|
73
80
|
...(ngDevMode ? [{ debugName: "controlIds" }] : /* istanbul ignore next */ []));
|
|
74
81
|
/** The space-separated control ids in `allValues` order, for the parent's `aria-controls`. */
|
|
75
82
|
this.controlledIds = computed(() => {
|
|
76
83
|
const ids = this.controlIds();
|
|
77
84
|
const list = this.allValues()
|
|
78
|
-
.map((
|
|
85
|
+
.map((value) => ids[value])
|
|
79
86
|
.filter((id) => id !== undefined);
|
|
80
87
|
return list.length > 0 ? list.join(' ') : undefined;
|
|
81
88
|
}, /* @ts-ignore */
|
|
@@ -87,6 +94,25 @@ class RdxCheckboxGroupDirective extends RdxFormUiControlBase {
|
|
|
87
94
|
this.onTouched = () => {
|
|
88
95
|
/* Empty */
|
|
89
96
|
};
|
|
97
|
+
useNativeFormControl({
|
|
98
|
+
name: this.name,
|
|
99
|
+
form: this.form,
|
|
100
|
+
disabled: this.disabledState,
|
|
101
|
+
value: this.value,
|
|
102
|
+
serialize: serializeNativeFormValue,
|
|
103
|
+
defaultValue: () => [...(this.defaultValue() ?? this.value())],
|
|
104
|
+
onReset: (value) => {
|
|
105
|
+
const next = [...value];
|
|
106
|
+
this.value.set(next);
|
|
107
|
+
if (!this.resetNgControl(next)) {
|
|
108
|
+
this.onChange(next);
|
|
109
|
+
}
|
|
110
|
+
this.seeded = false;
|
|
111
|
+
this.uncontrolledState = next;
|
|
112
|
+
this.parentStatus = 'mixed';
|
|
113
|
+
this.formUi.resetInteractionState?.();
|
|
114
|
+
}
|
|
115
|
+
});
|
|
90
116
|
effect(() => {
|
|
91
117
|
const defaultValue = this.defaultValue();
|
|
92
118
|
if (!this.hasAppliedDefault && defaultValue !== undefined) {
|
|
@@ -99,40 +125,40 @@ class RdxCheckboxGroupDirective extends RdxFormUiControlBase {
|
|
|
99
125
|
formUiTouchTarget() {
|
|
100
126
|
return { markAsTouched: () => this.onTouched() };
|
|
101
127
|
}
|
|
102
|
-
/** @ignore Register a child's disabled signal keyed by its
|
|
103
|
-
registerChild(
|
|
104
|
-
this.
|
|
128
|
+
/** @ignore Register a child's disabled signal keyed by its value. */
|
|
129
|
+
registerChild(value, disabled) {
|
|
130
|
+
this.disabledByValue.set(value, disabled);
|
|
105
131
|
return () => {
|
|
106
|
-
if (this.
|
|
107
|
-
this.
|
|
132
|
+
if (this.disabledByValue.get(value) === disabled) {
|
|
133
|
+
this.disabledByValue.delete(value);
|
|
108
134
|
}
|
|
109
135
|
};
|
|
110
136
|
}
|
|
111
|
-
/** A stable control id for a child, derived from the group id and
|
|
112
|
-
controlId(
|
|
113
|
-
return `${this.elementId}-${
|
|
137
|
+
/** A stable control id for a child, derived from the group id and item value. */
|
|
138
|
+
controlId(value) {
|
|
139
|
+
return `${this.elementId}-${value}`;
|
|
114
140
|
}
|
|
115
141
|
/** @ignore Register a child's control element id so the parent can list it in `aria-controls`. */
|
|
116
|
-
registerControl(
|
|
117
|
-
this.controlIds.update((ids) => ({ ...ids, [
|
|
142
|
+
registerControl(value, id) {
|
|
143
|
+
this.controlIds.update((ids) => ({ ...ids, [value]: id }));
|
|
118
144
|
return () => {
|
|
119
145
|
this.controlIds.update((ids) => {
|
|
120
|
-
if (ids[
|
|
146
|
+
if (ids[value] !== id) {
|
|
121
147
|
return ids;
|
|
122
148
|
}
|
|
123
149
|
const next = { ...ids };
|
|
124
|
-
delete next[
|
|
150
|
+
delete next[value];
|
|
125
151
|
return next;
|
|
126
152
|
});
|
|
127
153
|
};
|
|
128
154
|
}
|
|
129
|
-
/** Add/remove a single child
|
|
130
|
-
toggleValue(
|
|
155
|
+
/** Add/remove a single child value from the group value (a direct child change). */
|
|
156
|
+
toggleValue(value, event) {
|
|
131
157
|
if (this.disabledState()) {
|
|
132
158
|
return;
|
|
133
159
|
}
|
|
134
160
|
const current = this.value();
|
|
135
|
-
const next = current.includes(
|
|
161
|
+
const next = current.includes(value) ? current.filter((item) => item !== value) : [...current, value];
|
|
136
162
|
if (!this.emit(next, event)) {
|
|
137
163
|
return;
|
|
138
164
|
}
|
|
@@ -158,8 +184,8 @@ class RdxCheckboxGroupDirective extends RdxFormUiControlBase {
|
|
|
158
184
|
const allValues = this.allValues();
|
|
159
185
|
const remembered = this.uncontrolledState;
|
|
160
186
|
// Disabled children that were checked stay checked through every transition.
|
|
161
|
-
const none = allValues.filter((
|
|
162
|
-
const all = allValues.filter((
|
|
187
|
+
const none = allValues.filter((value) => this.isValueDisabled(value) && remembered.includes(value));
|
|
188
|
+
const all = allValues.filter((value) => !this.isValueDisabled(value) || remembered.includes(value));
|
|
163
189
|
const rememberedIsAllOrNone = remembered.length === all.length || remembered.length === 0;
|
|
164
190
|
if (rememberedIsAllOrNone) {
|
|
165
191
|
this.emit(this.value().length === all.length ? none : all, event);
|
|
@@ -180,8 +206,8 @@ class RdxCheckboxGroupDirective extends RdxFormUiControlBase {
|
|
|
180
206
|
}
|
|
181
207
|
this.parentStatus = nextStatus;
|
|
182
208
|
}
|
|
183
|
-
|
|
184
|
-
return this.
|
|
209
|
+
isValueDisabled(value) {
|
|
210
|
+
return this.disabledByValue.get(value)?.() ?? false;
|
|
185
211
|
}
|
|
186
212
|
/** Seed the remembered selection from the current value the first time the parent is used. */
|
|
187
213
|
ensureSeeded() {
|
|
@@ -220,7 +246,7 @@ class RdxCheckboxGroupDirective extends RdxFormUiControlBase {
|
|
|
220
246
|
this.disabledByCva.set(isDisabled);
|
|
221
247
|
}
|
|
222
248
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.2", ngImport: i0, type: RdxCheckboxGroupDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
|
|
223
|
-
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "22.0.2", type: RdxCheckboxGroupDirective, isStandalone: true, selector: "[rdxCheckboxGroup]", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, defaultValue: { classPropertyName: "defaultValue", publicName: "defaultValue", isSignal: true, isRequired: false, transformFunction: null }, allValues: { classPropertyName: "allValues", publicName: "allValues", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange", onValueChange: "onValueChange" }, host: { attributes: { "role": "group" }, properties: { "attr.data-disabled": "disabledState() ? \"\" : undefined" } }, providers: [
|
|
249
|
+
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "22.0.2", type: RdxCheckboxGroupDirective, isStandalone: true, selector: "[rdxCheckboxGroup]", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, defaultValue: { classPropertyName: "defaultValue", publicName: "defaultValue", isSignal: true, isRequired: false, transformFunction: null }, allValues: { classPropertyName: "allValues", publicName: "allValues", isSignal: true, isRequired: false, transformFunction: null }, name: { classPropertyName: "name", publicName: "name", isSignal: true, isRequired: false, transformFunction: null }, form: { classPropertyName: "form", publicName: "form", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange", onValueChange: "onValueChange" }, host: { attributes: { "role": "group" }, properties: { "attr.data-disabled": "disabledState() ? \"\" : undefined" } }, providers: [
|
|
224
250
|
provideValueAccessor(RdxCheckboxGroupDirective),
|
|
225
251
|
provideCheckboxGroupContext(groupContext),
|
|
226
252
|
provideFormUiState(() => inject(RdxCheckboxGroupDirective).formUi)
|
|
@@ -242,7 +268,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.2", ngImpor
|
|
|
242
268
|
'[attr.data-disabled]': 'disabledState() ? "" : undefined'
|
|
243
269
|
}
|
|
244
270
|
}]
|
|
245
|
-
}], ctorParameters: () => [], propDecorators: { value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }, { type: i0.Output, args: ["valueChange"] }], defaultValue: [{ type: i0.Input, args: [{ isSignal: true, alias: "defaultValue", required: false }] }], allValues: [{ type: i0.Input, args: [{ isSignal: true, alias: "allValues", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], onValueChange: [{ type: i0.Output, args: ["onValueChange"] }] } });
|
|
271
|
+
}], ctorParameters: () => [], propDecorators: { value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }, { type: i0.Output, args: ["valueChange"] }], defaultValue: [{ type: i0.Input, args: [{ isSignal: true, alias: "defaultValue", required: false }] }], allValues: [{ type: i0.Input, args: [{ isSignal: true, alias: "allValues", required: false }] }], name: [{ type: i0.Input, args: [{ isSignal: true, alias: "name", required: false }] }], form: [{ type: i0.Input, args: [{ isSignal: true, alias: "form", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], onValueChange: [{ type: i0.Output, args: ["onValueChange"] }] } });
|
|
246
272
|
|
|
247
273
|
function isIndeterminate(checked) {
|
|
248
274
|
return checked === 'indeterminate';
|
|
@@ -259,10 +285,11 @@ const rootContext = () => {
|
|
|
259
285
|
indeterminate: checkbox.indeterminateState,
|
|
260
286
|
disabled: checkbox.disabledState,
|
|
261
287
|
required: checkbox.required,
|
|
262
|
-
value: checkbox.
|
|
263
|
-
name: checkbox.
|
|
288
|
+
value: checkbox.nativeValue,
|
|
289
|
+
name: checkbox.nativeName,
|
|
290
|
+
itemValue: checkbox.itemValue,
|
|
264
291
|
parent: checkbox.parent,
|
|
265
|
-
form: checkbox.
|
|
292
|
+
form: checkbox.nativeForm,
|
|
266
293
|
readonly: checkbox.readOnlyState,
|
|
267
294
|
state: checkbox.state,
|
|
268
295
|
invalidState: checkbox.invalidState,
|
|
@@ -270,6 +297,7 @@ const rootContext = () => {
|
|
|
270
297
|
touchedState: checkbox.touchedState,
|
|
271
298
|
dirtyState: checkbox.dirtyState,
|
|
272
299
|
uncheckedValue: checkbox.uncheckedValue,
|
|
300
|
+
registerNativeInput: (input) => checkbox.registerNativeInput(input),
|
|
273
301
|
toggle(event) {
|
|
274
302
|
checkbox.toggle(event);
|
|
275
303
|
}
|
|
@@ -283,11 +311,10 @@ class RdxCheckboxRootDirective {
|
|
|
283
311
|
constructor() {
|
|
284
312
|
this.controlValueAccessor = inject(RdxControlValueAccessor);
|
|
285
313
|
this.ngControlState = injectNgControlState();
|
|
286
|
-
this.elementRef = inject(ElementRef);
|
|
287
|
-
this.renderer = inject(Renderer2);
|
|
288
|
-
this.uncheckedInputElement = null;
|
|
289
314
|
/** The group this checkbox belongs to, if it is rendered inside a `rdxCheckboxGroup`. */
|
|
290
315
|
this.group = injectCheckboxGroupContext(true);
|
|
316
|
+
this.nativeInput = signal(null, /* @ts-ignore */
|
|
317
|
+
...(ngDevMode ? [{ debugName: "nativeInput" }] : /* istanbul ignore next */ []));
|
|
291
318
|
/**
|
|
292
319
|
* The controlled checked state of the checkbox. Must be used in conjunction with onCheckedChange.
|
|
293
320
|
*
|
|
@@ -319,11 +346,12 @@ class RdxCheckboxRootDirective {
|
|
|
319
346
|
* Bound publicly as `[value]`; the TS member is named `submitValue` so the
|
|
320
347
|
* directive can satisfy `RdxFormCheckboxControl`, whose contract reserves a
|
|
321
348
|
* `value` member for `RdxFormValueControl` and forbids it on checkbox-style
|
|
322
|
-
* controls.
|
|
323
|
-
*
|
|
349
|
+
* controls.
|
|
350
|
+
* When omitted, native submission uses the browser checkbox default (`on`). Inside a
|
|
351
|
+
* `rdxCheckboxGroup`, the child's `name` is used as a compatibility fallback.
|
|
324
352
|
* @group Props
|
|
325
353
|
*/
|
|
326
|
-
this.submitValue = input(
|
|
354
|
+
this.submitValue = input(undefined, { ...(ngDevMode ? { debugName: "submitValue" } : /* istanbul ignore next */ {}), alias: 'value' });
|
|
327
355
|
/**
|
|
328
356
|
* The value submitted with the form when the checkbox is unchecked.
|
|
329
357
|
* By default, unchecked checkboxes do not submit any value, matching native checkbox behavior.
|
|
@@ -374,8 +402,8 @@ class RdxCheckboxRootDirective {
|
|
|
374
402
|
this.errors = input([], /* @ts-ignore */
|
|
375
403
|
...(ngDevMode ? [{ debugName: "errors" }] : /* istanbul ignore next */ []));
|
|
376
404
|
/**
|
|
377
|
-
* Name of
|
|
378
|
-
* `
|
|
405
|
+
* Name of a standalone form control. Inside a `rdxCheckboxGroup`, prefer `[value]` to identify
|
|
406
|
+
* the item; `name` remains a compatibility fallback for existing group templates.
|
|
379
407
|
* @group Props
|
|
380
408
|
*/
|
|
381
409
|
this.name = input(/* @ts-ignore */
|
|
@@ -392,6 +420,18 @@ class RdxCheckboxRootDirective {
|
|
|
392
420
|
*/
|
|
393
421
|
this.form = input(/* @ts-ignore */
|
|
394
422
|
...(ngDevMode ? [undefined, { debugName: "form" }] : /* istanbul ignore next */ []));
|
|
423
|
+
/** @ignore Item identity inside a checkbox group (`value`, falling back to the legacy child name). */
|
|
424
|
+
this.itemValue = computed(() => this.submitValue() ?? this.name(), /* @ts-ignore */
|
|
425
|
+
...(ngDevMode ? [{ debugName: "itemValue" }] : /* istanbul ignore next */ []));
|
|
426
|
+
/** @ignore Native checkbox value; browsers default an omitted checkbox value to `on`. */
|
|
427
|
+
this.nativeValue = computed(() => this.submitValue() ?? 'on', /* @ts-ignore */
|
|
428
|
+
...(ngDevMode ? [{ debugName: "nativeValue" }] : /* istanbul ignore next */ []));
|
|
429
|
+
/** @ignore A checkbox group owns the successful-control name and serializes its children centrally. */
|
|
430
|
+
this.nativeName = computed(() => (this.group || this.parent() ? undefined : this.name()), /* @ts-ignore */
|
|
431
|
+
...(ngDevMode ? [{ debugName: "nativeName" }] : /* istanbul ignore next */ []));
|
|
432
|
+
/** @ignore Child native inputs inherit an external form association from their checkbox group. */
|
|
433
|
+
this.nativeForm = computed(() => this.group?.form() ?? this.form(), /* @ts-ignore */
|
|
434
|
+
...(ngDevMode ? [{ debugName: "nativeForm" }] : /* istanbul ignore next */ []));
|
|
395
435
|
/**
|
|
396
436
|
* Event emitted when the checkbox checked state changes.
|
|
397
437
|
* @group Emits
|
|
@@ -405,8 +445,8 @@ class RdxCheckboxRootDirective {
|
|
|
405
445
|
/**
|
|
406
446
|
* @ignore
|
|
407
447
|
* The effective checked state as a `boolean`. Inside a `rdxCheckboxGroup` it is derived from the
|
|
408
|
-
* group (a `parent` checkbox is checked only when every child is; a child from whether its
|
|
409
|
-
* is in the group value); standalone it reads the CVA value.
|
|
448
|
+
* group (a `parent` checkbox is checked only when every child is; a child from whether its item
|
|
449
|
+
* value is in the group value); standalone it reads the CVA value.
|
|
410
450
|
*/
|
|
411
451
|
this.checkedState = computed(() => {
|
|
412
452
|
const group = this.group;
|
|
@@ -414,9 +454,9 @@ class RdxCheckboxRootDirective {
|
|
|
414
454
|
if (this.parent()) {
|
|
415
455
|
return group.parentState() === true;
|
|
416
456
|
}
|
|
417
|
-
const
|
|
418
|
-
if (
|
|
419
|
-
return group.value().includes(
|
|
457
|
+
const value = this.itemValue();
|
|
458
|
+
if (value !== undefined) {
|
|
459
|
+
return group.value().includes(value);
|
|
420
460
|
}
|
|
421
461
|
}
|
|
422
462
|
return !!this.controlValueAccessor.value();
|
|
@@ -489,13 +529,45 @@ class RdxCheckboxRootDirective {
|
|
|
489
529
|
...(ngDevMode ? [{ debugName: "dirtyState" }] : /* istanbul ignore next */ []));
|
|
490
530
|
this.state = computed(() => this.indeterminateState() ? 'indeterminate' : this.checkedState() ? 'checked' : 'unchecked', /* @ts-ignore */
|
|
491
531
|
...(ngDevMode ? [{ debugName: "state" }] : /* istanbul ignore next */ []));
|
|
492
|
-
|
|
532
|
+
this.nativeInputOwnsValue = computed(() => this.nativeInput() !== null && (this.checkedState() || this.uncheckedValue() === undefined), /* @ts-ignore */
|
|
533
|
+
...(ngDevMode ? [{ debugName: "nativeInputOwnsValue" }] : /* istanbul ignore next */ []));
|
|
534
|
+
useNativeFormControl({
|
|
535
|
+
name: this.nativeName,
|
|
536
|
+
form: this.nativeForm,
|
|
537
|
+
disabled: this.disabledState,
|
|
538
|
+
value: this.checkedState,
|
|
539
|
+
serialize: (checked) => {
|
|
540
|
+
const value = checked ? this.nativeValue() : this.uncheckedValue();
|
|
541
|
+
return value === undefined ? [] : [value];
|
|
542
|
+
},
|
|
543
|
+
hasNativeControl: this.nativeInputOwnsValue,
|
|
544
|
+
syncNativeControl: () => {
|
|
545
|
+
const input = this.nativeInput();
|
|
546
|
+
if (input) {
|
|
547
|
+
input.checked = this.checkedState();
|
|
548
|
+
input.indeterminate = this.indeterminateState();
|
|
549
|
+
}
|
|
550
|
+
},
|
|
551
|
+
defaultValue: () => this.defaultChecked() ?? this.checkedState(),
|
|
552
|
+
onReset: (value) => {
|
|
553
|
+
if (this.group || this.parent()) {
|
|
554
|
+
return;
|
|
555
|
+
}
|
|
556
|
+
this.indeterminate.set(false);
|
|
557
|
+
this.checked.set(value);
|
|
558
|
+
if (!this.ngControlState.reset(value)) {
|
|
559
|
+
this.controlValueAccessor.writeValue(value);
|
|
560
|
+
}
|
|
561
|
+
this.reset();
|
|
562
|
+
}
|
|
563
|
+
});
|
|
564
|
+
// Inside a group, register this child's item value and its own disabled state so a `parent`
|
|
493
565
|
// checkbox can preserve disabled-but-checked children when selecting/deselecting all.
|
|
494
566
|
effect((onCleanup) => {
|
|
495
567
|
const group = this.group;
|
|
496
|
-
const
|
|
497
|
-
if (group && !this.parent() &&
|
|
498
|
-
onCleanup(group.registerChild(
|
|
568
|
+
const value = this.itemValue();
|
|
569
|
+
if (group && !this.parent() && value !== undefined) {
|
|
570
|
+
onCleanup(group.registerChild(value, this.controlValueAccessor.disabled));
|
|
499
571
|
}
|
|
500
572
|
});
|
|
501
573
|
let hasAppliedDefault = false;
|
|
@@ -507,9 +579,6 @@ class RdxCheckboxRootDirective {
|
|
|
507
579
|
this.controlValueAccessor.setValue(defaultChecked);
|
|
508
580
|
}
|
|
509
581
|
});
|
|
510
|
-
effect(() => {
|
|
511
|
-
this.syncUncheckedInput();
|
|
512
|
-
});
|
|
513
582
|
// Reactive/template-driven forms own their NgControl interaction state. Signal Forms instead
|
|
514
583
|
// writes the public touched/dirty members, so standalone controls retain the existing fallback.
|
|
515
584
|
effect(() => {
|
|
@@ -524,9 +593,6 @@ class RdxCheckboxRootDirective {
|
|
|
524
593
|
this.dirtyValue.set(false);
|
|
525
594
|
}
|
|
526
595
|
}, { debugName: 'RdxCheckboxRoot.syncInteractionState' });
|
|
527
|
-
inject(DestroyRef).onDestroy(() => {
|
|
528
|
-
this.removeUncheckedInput();
|
|
529
|
-
});
|
|
530
596
|
}
|
|
531
597
|
toggle(event) {
|
|
532
598
|
if (this.disabledState() || this.readOnlyState()) {
|
|
@@ -538,9 +604,9 @@ class RdxCheckboxRootDirective {
|
|
|
538
604
|
group.toggleAll(event);
|
|
539
605
|
return;
|
|
540
606
|
}
|
|
541
|
-
const
|
|
542
|
-
if (
|
|
543
|
-
group.toggleValue(
|
|
607
|
+
const value = this.itemValue();
|
|
608
|
+
if (value !== undefined) {
|
|
609
|
+
group.toggleValue(value, event);
|
|
544
610
|
return;
|
|
545
611
|
}
|
|
546
612
|
}
|
|
@@ -571,60 +637,14 @@ class RdxCheckboxRootDirective {
|
|
|
571
637
|
this.touched.set(false);
|
|
572
638
|
this.dirtyValue.set(false);
|
|
573
639
|
}
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
}
|
|
582
|
-
const input = this.ensureUncheckedInput();
|
|
583
|
-
this.renderer.setAttribute(input, 'type', 'hidden');
|
|
584
|
-
this.renderer.setAttribute(input, 'name', name);
|
|
585
|
-
this.renderer.setAttribute(input, 'value', uncheckedValue);
|
|
586
|
-
this.setOptionalAttribute(input, 'form', this.form());
|
|
587
|
-
this.setBooleanAttribute(input, 'disabled', this.disabledState());
|
|
588
|
-
}
|
|
589
|
-
ensureUncheckedInput() {
|
|
590
|
-
if (this.uncheckedInputElement) {
|
|
591
|
-
return this.uncheckedInputElement;
|
|
592
|
-
}
|
|
593
|
-
const host = this.elementRef.nativeElement;
|
|
594
|
-
const parent = host.parentNode;
|
|
595
|
-
const input = this.renderer.createElement('input');
|
|
596
|
-
if (parent) {
|
|
597
|
-
this.renderer.insertBefore(parent, input, host.nextSibling);
|
|
598
|
-
}
|
|
599
|
-
this.uncheckedInputElement = input;
|
|
600
|
-
return input;
|
|
601
|
-
}
|
|
602
|
-
removeUncheckedInput() {
|
|
603
|
-
const input = this.uncheckedInputElement;
|
|
604
|
-
if (!input) {
|
|
605
|
-
return;
|
|
606
|
-
}
|
|
607
|
-
const parent = input.parentNode;
|
|
608
|
-
if (parent) {
|
|
609
|
-
this.renderer.removeChild(parent, input);
|
|
610
|
-
}
|
|
611
|
-
this.uncheckedInputElement = null;
|
|
612
|
-
}
|
|
613
|
-
setOptionalAttribute(element, name, value) {
|
|
614
|
-
if (value) {
|
|
615
|
-
this.renderer.setAttribute(element, name, value);
|
|
616
|
-
}
|
|
617
|
-
else {
|
|
618
|
-
this.renderer.removeAttribute(element, name);
|
|
619
|
-
}
|
|
620
|
-
}
|
|
621
|
-
setBooleanAttribute(element, name, value) {
|
|
622
|
-
if (value) {
|
|
623
|
-
this.renderer.setAttribute(element, name, '');
|
|
624
|
-
}
|
|
625
|
-
else {
|
|
626
|
-
this.renderer.removeAttribute(element, name);
|
|
627
|
-
}
|
|
640
|
+
/** @ignore Register the optional native checkbox so it owns checked-value serialization. */
|
|
641
|
+
registerNativeInput(input) {
|
|
642
|
+
this.nativeInput.set(input);
|
|
643
|
+
return () => {
|
|
644
|
+
if (this.nativeInput() === input) {
|
|
645
|
+
this.nativeInput.set(null);
|
|
646
|
+
}
|
|
647
|
+
};
|
|
628
648
|
}
|
|
629
649
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.2", ngImport: i0, type: RdxCheckboxRootDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
|
|
630
650
|
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "22.0.2", type: RdxCheckboxRootDirective, isStandalone: true, selector: "[rdxCheckboxRoot]", inputs: { checked: { classPropertyName: "checked", publicName: "checked", isSignal: true, isRequired: false, transformFunction: null }, defaultChecked: { classPropertyName: "defaultChecked", publicName: "defaultChecked", isSignal: true, isRequired: false, transformFunction: null }, indeterminate: { classPropertyName: "indeterminate", publicName: "indeterminate", isSignal: true, isRequired: false, transformFunction: null }, submitValue: { classPropertyName: "submitValue", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, uncheckedValue: { classPropertyName: "uncheckedValue", publicName: "uncheckedValue", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, readonly: { classPropertyName: "readonly", publicName: "readOnly", isSignal: true, isRequired: false, transformFunction: null }, required: { classPropertyName: "required", publicName: "required", isSignal: true, isRequired: false, transformFunction: null }, invalid: { classPropertyName: "invalid", publicName: "invalid", isSignal: true, isRequired: false, transformFunction: null }, pending: { classPropertyName: "pending", publicName: "pending", isSignal: true, isRequired: false, transformFunction: null }, touched: { classPropertyName: "touched", publicName: "touched", isSignal: true, isRequired: false, transformFunction: null }, dirty: { classPropertyName: "dirty", publicName: "dirty", isSignal: true, isRequired: false, transformFunction: null }, errors: { classPropertyName: "errors", publicName: "errors", isSignal: true, isRequired: false, transformFunction: null }, name: { classPropertyName: "name", publicName: "name", isSignal: true, isRequired: false, transformFunction: null }, parent: { classPropertyName: "parent", publicName: "parent", isSignal: true, isRequired: false, transformFunction: null }, form: { classPropertyName: "form", publicName: "form", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { checked: "checkedChange", indeterminate: "indeterminateChange", touched: "touchedChange", onCheckedChange: "onCheckedChange", touch: "touch" }, host: { properties: { "attr.data-checked": "checkedState() && !indeterminateState() ? \"\" : undefined", "attr.data-unchecked": "!checkedState() && !indeterminateState() ? \"\" : undefined", "attr.data-indeterminate": "indeterminateState() ? \"\" : undefined", "attr.data-disabled": "disabledState() ? \"\" : undefined", "attr.data-readonly": "readOnlyState() ? \"\" : undefined", "attr.data-required": "required() ? \"\" : undefined", "attr.data-invalid": "displayValid() === false ? \"\" : undefined", "attr.data-valid": "displayValid() === true ? \"\" : undefined", "attr.data-touched": "touchedState() ? \"\" : undefined", "attr.data-dirty": "dirtyState() ? \"\" : undefined" } }, providers: [provideCheckboxRootContext(rootContext)], hostDirectives: [{ directive: i1.RdxControlValueAccessor, inputs: ["value", "checked", "disabled", "disabled"] }], ngImport: i0 }); }
|
|
@@ -673,15 +693,15 @@ class RdxCheckboxButtonDirective {
|
|
|
673
693
|
// `aria-controls`. Use the consumer's id when present, otherwise derive a stable one.
|
|
674
694
|
effect((onCleanup) => {
|
|
675
695
|
const group = this.group;
|
|
676
|
-
const
|
|
677
|
-
if (!group || this.rootContext.parent() ||
|
|
696
|
+
const value = this.rootContext.itemValue();
|
|
697
|
+
if (!group || this.rootContext.parent() || value === undefined) {
|
|
678
698
|
return;
|
|
679
699
|
}
|
|
680
700
|
const el = this.elementRef.nativeElement;
|
|
681
701
|
if (!el.id) {
|
|
682
|
-
el.id = group.controlId(
|
|
702
|
+
el.id = group.controlId(value);
|
|
683
703
|
}
|
|
684
|
-
onCleanup(group.registerControl(
|
|
704
|
+
onCleanup(group.registerControl(value, el.id));
|
|
685
705
|
});
|
|
686
706
|
}
|
|
687
707
|
clicked(event) {
|
|
@@ -763,6 +783,8 @@ class RdxCheckboxInputDirective {
|
|
|
763
783
|
constructor() {
|
|
764
784
|
this.rootContext = injectCheckboxRootContext();
|
|
765
785
|
this.input = inject(ElementRef).nativeElement;
|
|
786
|
+
const unregister = this.rootContext.registerNativeInput(this.input);
|
|
787
|
+
inject(DestroyRef).onDestroy(unregister);
|
|
766
788
|
let isInitial = true;
|
|
767
789
|
/**
|
|
768
790
|
* Keeps the hidden native input in sync so form submission, native
|