@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
|
@@ -4,7 +4,7 @@ import * as i1 from '@radix-ng/primitives/popper';
|
|
|
4
4
|
import { RdxPopperAnchor, RdxPopperArrow, RdxPopper, RdxPopperContentWrapper, provideRdxPopperContentWrapper, provideRdxPopperContentConfig, DROPDOWN_COLLISION_AVOIDANCE, injectPopperContentWrapperContext, RdxPopperContent } from '@radix-ng/primitives/popper';
|
|
5
5
|
import { NG_VALUE_ACCESSOR } from '@angular/forms';
|
|
6
6
|
import * as i2 from '@radix-ng/primitives/core';
|
|
7
|
-
import { useFilter, injectId, useListHighlight, useTransitionStatus, createContext, RdxFormUiControlBase, createFloatingRootContext, isItemEqualToValue, isNullish, createCancelableChangeEventDetails, itemToStringLabel, provideFloatingTree, provideFloatingRootContext, setupInternalBackdrop, RDX_FLOATING_ROOT_CONTEXT, RDX_FLOATING_REGISTRATION, useAnchoredScrollLock, RdxFloatingNodeRegistration, rdxDevError } from '@radix-ng/primitives/core';
|
|
7
|
+
import { useFilter, injectId, useListHighlight, useTransitionStatus, createContext, RdxFormUiControlBase, createFloatingRootContext, useNativeFormControl, serializeNativeFormValue, isItemEqualToValue, isNullish, createCancelableChangeEventDetails, itemToStringLabel, provideFloatingTree, provideFloatingRootContext, setupInternalBackdrop, RDX_FLOATING_ROOT_CONTEXT, RDX_FLOATING_REGISTRATION, useAnchoredScrollLock, RdxFloatingNodeRegistration, rdxDevError } from '@radix-ng/primitives/core';
|
|
8
8
|
import { injectDirection } from '@radix-ng/primitives/direction-provider';
|
|
9
9
|
import * as i1$1 from '@radix-ng/primitives/dismissable-layer';
|
|
10
10
|
import { RdxFloatingInsideElement, RdxDismiss } from '@radix-ng/primitives/dismissable-layer';
|
|
@@ -98,34 +98,58 @@ function useComboboxEngine(config) {
|
|
|
98
98
|
// Tracks whether the last interaction was the keyboard, so the highlight doesn't jump to an item
|
|
99
99
|
// the cursor happens to rest on when arrow-key navigation scrolls the list under a still pointer.
|
|
100
100
|
let keyboardActive = false;
|
|
101
|
-
|
|
102
|
-
|
|
101
|
+
// Keep registrations in a stable map. Copying the growing array on every item mount/unmount makes
|
|
102
|
+
// registering N options O(n²) before filtering or DOM-order sorting even begins. The numeric tick is
|
|
103
|
+
// only the reactive invalidation channel; Angular batches the registrations from one render, so
|
|
104
|
+
// `orderedItems` materializes and sorts the final collection once for that batch. This is the same
|
|
105
|
+
// stable-map pattern used by Base UI and our CompositeList.
|
|
106
|
+
const itemRegistry = new Map();
|
|
107
|
+
const itemRegistryTick = signal(0, /* @ts-ignore */
|
|
108
|
+
...(ngDevMode ? [{ debugName: "itemRegistryTick" }] : /* istanbul ignore next */ []));
|
|
103
109
|
const orderedItems = computed(() => {
|
|
104
|
-
|
|
105
|
-
return
|
|
110
|
+
itemRegistryTick();
|
|
111
|
+
return [...itemRegistry.values()]
|
|
112
|
+
.filter((item) => item.element.isConnected)
|
|
113
|
+
.sort((a, b) => domOrder(a.element, b.element));
|
|
106
114
|
}, /* @ts-ignore */
|
|
107
115
|
...(ngDevMode ? [{ debugName: "orderedItems" }] : /* istanbul ignore next */ []));
|
|
108
|
-
const
|
|
116
|
+
const visibleItems = computed(() => {
|
|
117
|
+
const items = orderedItems();
|
|
118
|
+
const limit = config.limit();
|
|
119
|
+
if (limit === 0) {
|
|
120
|
+
return [];
|
|
121
|
+
}
|
|
122
|
+
// Read root signals once per query, not once per item. The early paths also avoid
|
|
123
|
+
// allocating/filtering when every registered item is known to be visible.
|
|
109
124
|
if (!config.filteringEnabled()) {
|
|
110
|
-
return
|
|
125
|
+
return limit >= 0 ? items.slice(0, limit) : items;
|
|
111
126
|
}
|
|
112
127
|
const filter = config.filter();
|
|
113
128
|
if (filter === null) {
|
|
114
|
-
return
|
|
129
|
+
return limit >= 0 ? items.slice(0, limit) : items;
|
|
115
130
|
}
|
|
116
131
|
const query = config.query();
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
132
|
+
if (!filter && query.length === 0) {
|
|
133
|
+
return limit >= 0 ? items.slice(0, limit) : items;
|
|
134
|
+
}
|
|
135
|
+
const matching = [];
|
|
136
|
+
const contains = filter ? null : defaultFilter().contains;
|
|
137
|
+
for (const item of items) {
|
|
138
|
+
// Custom filter: Base UI shape `(value, query, itemToString)`. Default: locale-aware
|
|
139
|
+
// contains on the item's own text (the element content), no value→text round-trip.
|
|
140
|
+
const matches = filter
|
|
141
|
+
? filter(item.value(), query, config.itemToString)
|
|
142
|
+
: contains(item.textValue(), query);
|
|
143
|
+
if (!matches) {
|
|
144
|
+
continue;
|
|
145
|
+
}
|
|
146
|
+
matching.push(item);
|
|
147
|
+
if (limit >= 0 && matching.length >= limit) {
|
|
148
|
+
break;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
return matching;
|
|
152
|
+
}, { ...(ngDevMode ? { debugName: "visibleItems" } : /* istanbul ignore next */ {}), equal: sameItemOrder });
|
|
129
153
|
const visibleSet = computed(() => new Set(visibleItems()), /* @ts-ignore */
|
|
130
154
|
...(ngDevMode ? [{ debugName: "visibleSet" }] : /* istanbul ignore next */ []));
|
|
131
155
|
const isVisible = (item) => visibleSet().has(item);
|
|
@@ -224,7 +248,13 @@ function useComboboxEngine(config) {
|
|
|
224
248
|
};
|
|
225
249
|
const recomputeInlinePreview = (label, query, reason) => {
|
|
226
250
|
// Pointer hover must not rewrite the input (matches Base UI); only typing / keyboard nav complete it.
|
|
227
|
-
if (!config.inlineMode() ||
|
|
251
|
+
if (!config.inlineMode() || !label || reason === 'pointer') {
|
|
252
|
+
inlinePreview.set(null);
|
|
253
|
+
return;
|
|
254
|
+
}
|
|
255
|
+
// Suppression belongs to the current edit only. Explicit keyboard navigation starts a new
|
|
256
|
+
// interaction and must still mirror the navigated label after a delete/cut edit.
|
|
257
|
+
if (suppressInline && reason !== 'keyboard') {
|
|
228
258
|
inlinePreview.set(null);
|
|
229
259
|
return;
|
|
230
260
|
}
|
|
@@ -316,11 +346,14 @@ function useComboboxEngine(config) {
|
|
|
316
346
|
pendingHighlightEdge.set(null);
|
|
317
347
|
});
|
|
318
348
|
}, { injector });
|
|
319
|
-
// Inline completion: mirror the active item's label into the input.
|
|
320
|
-
//
|
|
321
|
-
// `both → list`
|
|
349
|
+
// Inline completion: mirror the active item's label into the input. When inline mode is off, stop
|
|
350
|
+
// before reading query/highlight state so Combobox and list-mode Autocomplete do not subscribe this
|
|
351
|
+
// effect to the typing hot path. A `both → list` switch still clears the previous preview.
|
|
322
352
|
effect(() => {
|
|
323
|
-
config.inlineMode()
|
|
353
|
+
if (!config.inlineMode()) {
|
|
354
|
+
untracked(() => inlinePreview.set(null));
|
|
355
|
+
return;
|
|
356
|
+
}
|
|
324
357
|
highlightedItem();
|
|
325
358
|
highlightedIndex();
|
|
326
359
|
const query = config.query();
|
|
@@ -459,10 +492,19 @@ function useComboboxEngine(config) {
|
|
|
459
492
|
filteredItems,
|
|
460
493
|
isVisible,
|
|
461
494
|
registerItem(item) {
|
|
462
|
-
|
|
495
|
+
if (itemRegistry.get(item.element) === item) {
|
|
496
|
+
return;
|
|
497
|
+
}
|
|
498
|
+
itemRegistry.set(item.element, item);
|
|
499
|
+
itemRegistryTick.update((tick) => tick + 1);
|
|
463
500
|
},
|
|
464
501
|
unregisterItem(item) {
|
|
465
|
-
|
|
502
|
+
// A stale cleanup must not delete a newer registration for the same host element.
|
|
503
|
+
if (itemRegistry.get(item.element) !== item) {
|
|
504
|
+
return;
|
|
505
|
+
}
|
|
506
|
+
itemRegistry.delete(item.element);
|
|
507
|
+
itemRegistryTick.update((tick) => tick + 1);
|
|
466
508
|
},
|
|
467
509
|
highlight,
|
|
468
510
|
highlightedItem,
|
|
@@ -603,6 +645,21 @@ function domOrder(a, b) {
|
|
|
603
645
|
}
|
|
604
646
|
return 0;
|
|
605
647
|
}
|
|
648
|
+
/** Referential item-sequence equality used to keep unchanged filtering results stable across queries. */
|
|
649
|
+
function sameItemOrder(previous, next) {
|
|
650
|
+
if (previous === next) {
|
|
651
|
+
return true;
|
|
652
|
+
}
|
|
653
|
+
if (previous.length !== next.length) {
|
|
654
|
+
return false;
|
|
655
|
+
}
|
|
656
|
+
for (let index = 0; index < previous.length; index++) {
|
|
657
|
+
if (previous[index] !== next[index]) {
|
|
658
|
+
return false;
|
|
659
|
+
}
|
|
660
|
+
}
|
|
661
|
+
return true;
|
|
662
|
+
}
|
|
606
663
|
|
|
607
664
|
// The engine stays private to the root (it owns mutable internals); the context factory — a free
|
|
608
665
|
// function, so it can't reach a `private` field — reads it through this registry instead.
|
|
@@ -617,6 +674,9 @@ const context = () => {
|
|
|
617
674
|
dir: root.dir,
|
|
618
675
|
value: root.value,
|
|
619
676
|
inputValue: root.inputValue,
|
|
677
|
+
name: root.name,
|
|
678
|
+
form: root.form,
|
|
679
|
+
inputOwnsFormValue: root.inputOwnsFormValue,
|
|
620
680
|
open: root.open,
|
|
621
681
|
present: root.present,
|
|
622
682
|
multiple: root.multiple,
|
|
@@ -768,6 +828,9 @@ class RdxComboboxRoot extends RdxFormUiControlBase {
|
|
|
768
828
|
/** Whether the combobox is in multiple-selection mode. */
|
|
769
829
|
this.multiple = computed(() => this.mode() === 'multiple', /* @ts-ignore */
|
|
770
830
|
...(ngDevMode ? [{ debugName: "multiple" }] : /* istanbul ignore next */ []));
|
|
831
|
+
/** Whether the visible text input owns native serialization in filter-only mode. */
|
|
832
|
+
this.inputOwnsFormValue = computed(() => this.mode() === 'none' && this.engine.inputLayout() !== 'inside', /* @ts-ignore */
|
|
833
|
+
...(ngDevMode ? [{ debugName: "inputOwnsFormValue" }] : /* istanbul ignore next */ []));
|
|
771
834
|
/** In `'none'` mode, whether pressing an item fills the input with its label. */
|
|
772
835
|
this.fillInputOnItemPress = input(true, { ...(ngDevMode ? { debugName: "fillInputOnItemPress" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
773
836
|
/** Text direction. */
|
|
@@ -779,6 +842,12 @@ class RdxComboboxRoot extends RdxFormUiControlBase {
|
|
|
779
842
|
this.readOnly = input(false, { ...(ngDevMode ? { debugName: "readOnly" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
780
843
|
/** Whether a value is required (for forms). */
|
|
781
844
|
this.required = input(false, { ...(ngDevMode ? { debugName: "required" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
845
|
+
/** Name used when serializing the committed selection into native `FormData`. */
|
|
846
|
+
this.name = input(/* @ts-ignore */
|
|
847
|
+
...(ngDevMode ? [undefined, { debugName: "name" }] : /* istanbul ignore next */ []));
|
|
848
|
+
/** Id of an external form that owns this control. */
|
|
849
|
+
this.form = input(/* @ts-ignore */
|
|
850
|
+
...(ngDevMode ? [undefined, { debugName: "form" }] : /* istanbul ignore next */ []));
|
|
782
851
|
/** Whether keyboard navigation wraps at the list boundaries. */
|
|
783
852
|
this.loopFocus = input(true, { ...(ngDevMode ? { debugName: "loopFocus" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
784
853
|
/**
|
|
@@ -857,6 +926,9 @@ class RdxComboboxRoot extends RdxFormUiControlBase {
|
|
|
857
926
|
/** Converts a value to its display label. Defaults to the matching item's text. */
|
|
858
927
|
this.itemToStringLabel = input(/* @ts-ignore */
|
|
859
928
|
...(ngDevMode ? [undefined, { debugName: "itemToStringLabel" }] : /* istanbul ignore next */ []));
|
|
929
|
+
/** Converts an item value to the string submitted by a native form. */
|
|
930
|
+
this.itemToStringValue = input(/* @ts-ignore */
|
|
931
|
+
...(ngDevMode ? [undefined, { debugName: "itemToStringValue" }] : /* istanbul ignore next */ []));
|
|
860
932
|
/** Emits before the selection changes; call `eventDetails.cancel()` to veto it. */
|
|
861
933
|
this.onValueChange = output();
|
|
862
934
|
/** Emits before the input text changes; call `eventDetails.cancel()` to veto it. */
|
|
@@ -874,6 +946,46 @@ class RdxComboboxRoot extends RdxFormUiControlBase {
|
|
|
874
946
|
...(ngDevMode ? [{ debugName: "cvaDisabled" }] : /* istanbul ignore next */ []));
|
|
875
947
|
this.disabledState = computed(() => this.disabled() || this.cvaDisabled(), /* @ts-ignore */
|
|
876
948
|
...(ngDevMode ? [{ debugName: "disabledState" }] : /* istanbul ignore next */ []));
|
|
949
|
+
this.nativeFormValue = computed(() => this.mode() === 'none' ? this.inputValue() : this.value(), /* @ts-ignore */
|
|
950
|
+
...(ngDevMode ? [{ debugName: "nativeFormValue" }] : /* istanbul ignore next */ []));
|
|
951
|
+
this.nativeFormControl = useNativeFormControl({
|
|
952
|
+
name: this.name,
|
|
953
|
+
form: this.form,
|
|
954
|
+
disabled: this.disabledState,
|
|
955
|
+
value: this.nativeFormValue,
|
|
956
|
+
serialize: (value) => {
|
|
957
|
+
const itemToStringValue = this.itemToStringValue();
|
|
958
|
+
return itemToStringValue
|
|
959
|
+
? serializeNativeFormValue(value, (entry) => itemToStringValue(entry))
|
|
960
|
+
: serializeNativeFormValue(value);
|
|
961
|
+
},
|
|
962
|
+
hasNativeControl: this.inputOwnsFormValue,
|
|
963
|
+
syncNativeControl: () => {
|
|
964
|
+
const input = this.engine.inputElement();
|
|
965
|
+
if (input && this.inputOwnsFormValue()) {
|
|
966
|
+
input.value = this.inputValue();
|
|
967
|
+
}
|
|
968
|
+
},
|
|
969
|
+
defaultValue: () => {
|
|
970
|
+
if (this.mode() === 'none') {
|
|
971
|
+
return this.inputValue();
|
|
972
|
+
}
|
|
973
|
+
const defaultValue = this.defaultValue();
|
|
974
|
+
return defaultValue === undefined ? this.value() : defaultValue;
|
|
975
|
+
},
|
|
976
|
+
onReset: (value) => {
|
|
977
|
+
if (this.mode() === 'none') {
|
|
978
|
+
this.setLabel(typeof value === 'string' ? value : '');
|
|
979
|
+
this.formUi.resetInteractionState?.();
|
|
980
|
+
return;
|
|
981
|
+
}
|
|
982
|
+
this.writeValue(value);
|
|
983
|
+
if (!this.resetNgControl(value)) {
|
|
984
|
+
this.onChange?.(value);
|
|
985
|
+
}
|
|
986
|
+
this.formUi.resetInteractionState?.();
|
|
987
|
+
}
|
|
988
|
+
});
|
|
877
989
|
this.requiredState = computed(() => this.required(), /* @ts-ignore */
|
|
878
990
|
...(ngDevMode ? [{ debugName: "requiredState" }] : /* istanbul ignore next */ []));
|
|
879
991
|
/** @ignore */
|
|
@@ -1157,7 +1269,7 @@ class RdxComboboxRoot extends RdxFormUiControlBase {
|
|
|
1157
1269
|
/** Requests submit of the closest form when `submitOnItemClick` is enabled. */
|
|
1158
1270
|
maybeSubmit() {
|
|
1159
1271
|
if (this.submitOnItemClick()) {
|
|
1160
|
-
this.
|
|
1272
|
+
this.nativeFormControl.requestSubmit();
|
|
1161
1273
|
}
|
|
1162
1274
|
}
|
|
1163
1275
|
selectHighlighted(event = new Event('combobox.item-press')) {
|
|
@@ -1281,7 +1393,7 @@ class RdxComboboxRoot extends RdxFormUiControlBase {
|
|
|
1281
1393
|
this.cvaDisabled.set(isDisabled);
|
|
1282
1394
|
}
|
|
1283
1395
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.2", ngImport: i0, type: RdxComboboxRoot, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
|
|
1284
|
-
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "22.0.2", type: RdxComboboxRoot, isStandalone: true, selector: "[rdxComboboxRoot]", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, defaultValue: { classPropertyName: "defaultValue", publicName: "defaultValue", isSignal: true, isRequired: false, transformFunction: null }, inputValue: { classPropertyName: "inputValue", publicName: "inputValue", isSignal: true, isRequired: false, transformFunction: null }, open: { classPropertyName: "open", publicName: "open", isSignal: true, isRequired: false, transformFunction: null }, defaultOpen: { classPropertyName: "defaultOpen", publicName: "defaultOpen", isSignal: true, isRequired: false, transformFunction: null }, multipleInput: { classPropertyName: "multipleInput", publicName: "multiple", isSignal: true, isRequired: false, transformFunction: null }, selectionMode: { classPropertyName: "selectionMode", publicName: "selectionMode", isSignal: true, isRequired: false, transformFunction: null }, fillInputOnItemPress: { classPropertyName: "fillInputOnItemPress", publicName: "fillInputOnItemPress", isSignal: true, isRequired: false, transformFunction: null }, dirInput: { classPropertyName: "dirInput", publicName: "dir", 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 }, loopFocus: { classPropertyName: "loopFocus", publicName: "loopFocus", isSignal: true, isRequired: false, transformFunction: null }, autoHighlight: { classPropertyName: "autoHighlight", publicName: "autoHighlight", isSignal: true, isRequired: false, transformFunction: null }, highlightItemOnHover: { classPropertyName: "highlightItemOnHover", publicName: "highlightItemOnHover", isSignal: true, isRequired: false, transformFunction: null }, keepHighlight: { classPropertyName: "keepHighlight", publicName: "keepHighlight", isSignal: true, isRequired: false, transformFunction: null }, openOnInputClick: { classPropertyName: "openOnInputClick", publicName: "openOnInputClick", isSignal: true, isRequired: false, transformFunction: null }, modal: { classPropertyName: "modal", publicName: "modal", isSignal: true, isRequired: false, transformFunction: null }, submitOnItemClick: { classPropertyName: "submitOnItemClick", publicName: "submitOnItemClick", isSignal: true, isRequired: false, transformFunction: null }, filter: { classPropertyName: "filter", publicName: "filter", isSignal: true, isRequired: false, transformFunction: null }, locale: { classPropertyName: "locale", publicName: "locale", isSignal: true, isRequired: false, transformFunction: null }, limit: { classPropertyName: "limit", publicName: "limit", isSignal: true, isRequired: false, transformFunction: null }, items: { classPropertyName: "items", publicName: "items", isSignal: true, isRequired: false, transformFunction: null }, virtualized: { classPropertyName: "virtualized", publicName: "virtualized", isSignal: true, isRequired: false, transformFunction: null }, grid: { classPropertyName: "grid", publicName: "grid", isSignal: true, isRequired: false, transformFunction: null }, isItemEqualToValue: { classPropertyName: "isItemEqualToValue", publicName: "isItemEqualToValue", isSignal: true, isRequired: false, transformFunction: null }, itemToStringLabel: { classPropertyName: "itemToStringLabel", publicName: "itemToStringLabel", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange", inputValue: "inputValueChange", open: "openChange", onValueChange: "onValueChange", onInputValueChange: "onInputValueChange", onOpenChange: "onOpenChange", onItemHighlighted: "onItemHighlighted", onOpenChangeComplete: "onOpenChangeComplete" }, host: { properties: { "attr.data-disabled": "disabledState() ? \"\" : undefined" } }, providers: [
|
|
1396
|
+
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "22.0.2", type: RdxComboboxRoot, isStandalone: true, selector: "[rdxComboboxRoot]", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, defaultValue: { classPropertyName: "defaultValue", publicName: "defaultValue", isSignal: true, isRequired: false, transformFunction: null }, inputValue: { classPropertyName: "inputValue", publicName: "inputValue", isSignal: true, isRequired: false, transformFunction: null }, open: { classPropertyName: "open", publicName: "open", isSignal: true, isRequired: false, transformFunction: null }, defaultOpen: { classPropertyName: "defaultOpen", publicName: "defaultOpen", isSignal: true, isRequired: false, transformFunction: null }, multipleInput: { classPropertyName: "multipleInput", publicName: "multiple", isSignal: true, isRequired: false, transformFunction: null }, selectionMode: { classPropertyName: "selectionMode", publicName: "selectionMode", isSignal: true, isRequired: false, transformFunction: null }, fillInputOnItemPress: { classPropertyName: "fillInputOnItemPress", publicName: "fillInputOnItemPress", isSignal: true, isRequired: false, transformFunction: null }, dirInput: { classPropertyName: "dirInput", publicName: "dir", 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 }, name: { classPropertyName: "name", publicName: "name", isSignal: true, isRequired: false, transformFunction: null }, form: { classPropertyName: "form", publicName: "form", isSignal: true, isRequired: false, transformFunction: null }, loopFocus: { classPropertyName: "loopFocus", publicName: "loopFocus", isSignal: true, isRequired: false, transformFunction: null }, autoHighlight: { classPropertyName: "autoHighlight", publicName: "autoHighlight", isSignal: true, isRequired: false, transformFunction: null }, highlightItemOnHover: { classPropertyName: "highlightItemOnHover", publicName: "highlightItemOnHover", isSignal: true, isRequired: false, transformFunction: null }, keepHighlight: { classPropertyName: "keepHighlight", publicName: "keepHighlight", isSignal: true, isRequired: false, transformFunction: null }, openOnInputClick: { classPropertyName: "openOnInputClick", publicName: "openOnInputClick", isSignal: true, isRequired: false, transformFunction: null }, modal: { classPropertyName: "modal", publicName: "modal", isSignal: true, isRequired: false, transformFunction: null }, submitOnItemClick: { classPropertyName: "submitOnItemClick", publicName: "submitOnItemClick", isSignal: true, isRequired: false, transformFunction: null }, filter: { classPropertyName: "filter", publicName: "filter", isSignal: true, isRequired: false, transformFunction: null }, locale: { classPropertyName: "locale", publicName: "locale", isSignal: true, isRequired: false, transformFunction: null }, limit: { classPropertyName: "limit", publicName: "limit", isSignal: true, isRequired: false, transformFunction: null }, items: { classPropertyName: "items", publicName: "items", isSignal: true, isRequired: false, transformFunction: null }, virtualized: { classPropertyName: "virtualized", publicName: "virtualized", isSignal: true, isRequired: false, transformFunction: null }, grid: { classPropertyName: "grid", publicName: "grid", isSignal: true, isRequired: false, transformFunction: null }, isItemEqualToValue: { classPropertyName: "isItemEqualToValue", publicName: "isItemEqualToValue", isSignal: true, isRequired: false, transformFunction: null }, itemToStringLabel: { classPropertyName: "itemToStringLabel", publicName: "itemToStringLabel", isSignal: true, isRequired: false, transformFunction: null }, itemToStringValue: { classPropertyName: "itemToStringValue", publicName: "itemToStringValue", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange", inputValue: "inputValueChange", open: "openChange", onValueChange: "onValueChange", onInputValueChange: "onInputValueChange", onOpenChange: "onOpenChange", onItemHighlighted: "onItemHighlighted", onOpenChangeComplete: "onOpenChangeComplete" }, host: { properties: { "attr.data-disabled": "disabledState() ? \"\" : undefined" } }, providers: [
|
|
1285
1397
|
provideComboboxRootContext(context),
|
|
1286
1398
|
{ provide: NG_VALUE_ACCESSOR, useExisting: RdxComboboxRoot, multi: true },
|
|
1287
1399
|
// New floating foundation (ADR 0015/0017) — the dismissal capability reads this shared context.
|
|
@@ -1306,7 +1418,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.2", ngImpor
|
|
|
1306
1418
|
'[attr.data-disabled]': 'disabledState() ? "" : undefined'
|
|
1307
1419
|
}
|
|
1308
1420
|
}]
|
|
1309
|
-
}], 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 }] }], inputValue: [{ type: i0.Input, args: [{ isSignal: true, alias: "inputValue", required: false }] }, { type: i0.Output, args: ["inputValueChange"] }], open: [{ type: i0.Input, args: [{ isSignal: true, alias: "open", required: false }] }, { type: i0.Output, args: ["openChange"] }], defaultOpen: [{ type: i0.Input, args: [{ isSignal: true, alias: "defaultOpen", required: false }] }], multipleInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "multiple", required: false }] }], selectionMode: [{ type: i0.Input, args: [{ isSignal: true, alias: "selectionMode", required: false }] }], fillInputOnItemPress: [{ type: i0.Input, args: [{ isSignal: true, alias: "fillInputOnItemPress", required: false }] }], dirInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "dir", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], readOnly: [{ type: i0.Input, args: [{ isSignal: true, alias: "readOnly", required: false }] }], required: [{ type: i0.Input, args: [{ isSignal: true, alias: "required", required: false }] }], loopFocus: [{ type: i0.Input, args: [{ isSignal: true, alias: "loopFocus", required: false }] }], autoHighlight: [{ type: i0.Input, args: [{ isSignal: true, alias: "autoHighlight", required: false }] }], highlightItemOnHover: [{ type: i0.Input, args: [{ isSignal: true, alias: "highlightItemOnHover", required: false }] }], keepHighlight: [{ type: i0.Input, args: [{ isSignal: true, alias: "keepHighlight", required: false }] }], openOnInputClick: [{ type: i0.Input, args: [{ isSignal: true, alias: "openOnInputClick", required: false }] }], modal: [{ type: i0.Input, args: [{ isSignal: true, alias: "modal", required: false }] }], submitOnItemClick: [{ type: i0.Input, args: [{ isSignal: true, alias: "submitOnItemClick", required: false }] }], filter: [{ type: i0.Input, args: [{ isSignal: true, alias: "filter", required: false }] }], locale: [{ type: i0.Input, args: [{ isSignal: true, alias: "locale", required: false }] }], limit: [{ type: i0.Input, args: [{ isSignal: true, alias: "limit", required: false }] }], items: [{ type: i0.Input, args: [{ isSignal: true, alias: "items", required: false }] }], virtualized: [{ type: i0.Input, args: [{ isSignal: true, alias: "virtualized", required: false }] }], grid: [{ type: i0.Input, args: [{ isSignal: true, alias: "grid", required: false }] }], isItemEqualToValue: [{ type: i0.Input, args: [{ isSignal: true, alias: "isItemEqualToValue", required: false }] }], itemToStringLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "itemToStringLabel", required: false }] }], onValueChange: [{ type: i0.Output, args: ["onValueChange"] }], onInputValueChange: [{ type: i0.Output, args: ["onInputValueChange"] }], onOpenChange: [{ type: i0.Output, args: ["onOpenChange"] }], onItemHighlighted: [{ type: i0.Output, args: ["onItemHighlighted"] }], onOpenChangeComplete: [{ type: i0.Output, args: ["onOpenChangeComplete"] }] } });
|
|
1421
|
+
}], 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 }] }], inputValue: [{ type: i0.Input, args: [{ isSignal: true, alias: "inputValue", required: false }] }, { type: i0.Output, args: ["inputValueChange"] }], open: [{ type: i0.Input, args: [{ isSignal: true, alias: "open", required: false }] }, { type: i0.Output, args: ["openChange"] }], defaultOpen: [{ type: i0.Input, args: [{ isSignal: true, alias: "defaultOpen", required: false }] }], multipleInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "multiple", required: false }] }], selectionMode: [{ type: i0.Input, args: [{ isSignal: true, alias: "selectionMode", required: false }] }], fillInputOnItemPress: [{ type: i0.Input, args: [{ isSignal: true, alias: "fillInputOnItemPress", required: false }] }], dirInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "dir", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], readOnly: [{ type: i0.Input, args: [{ isSignal: true, alias: "readOnly", required: false }] }], required: [{ type: i0.Input, args: [{ isSignal: true, alias: "required", required: false }] }], name: [{ type: i0.Input, args: [{ isSignal: true, alias: "name", required: false }] }], form: [{ type: i0.Input, args: [{ isSignal: true, alias: "form", required: false }] }], loopFocus: [{ type: i0.Input, args: [{ isSignal: true, alias: "loopFocus", required: false }] }], autoHighlight: [{ type: i0.Input, args: [{ isSignal: true, alias: "autoHighlight", required: false }] }], highlightItemOnHover: [{ type: i0.Input, args: [{ isSignal: true, alias: "highlightItemOnHover", required: false }] }], keepHighlight: [{ type: i0.Input, args: [{ isSignal: true, alias: "keepHighlight", required: false }] }], openOnInputClick: [{ type: i0.Input, args: [{ isSignal: true, alias: "openOnInputClick", required: false }] }], modal: [{ type: i0.Input, args: [{ isSignal: true, alias: "modal", required: false }] }], submitOnItemClick: [{ type: i0.Input, args: [{ isSignal: true, alias: "submitOnItemClick", required: false }] }], filter: [{ type: i0.Input, args: [{ isSignal: true, alias: "filter", required: false }] }], locale: [{ type: i0.Input, args: [{ isSignal: true, alias: "locale", required: false }] }], limit: [{ type: i0.Input, args: [{ isSignal: true, alias: "limit", required: false }] }], items: [{ type: i0.Input, args: [{ isSignal: true, alias: "items", required: false }] }], virtualized: [{ type: i0.Input, args: [{ isSignal: true, alias: "virtualized", required: false }] }], grid: [{ type: i0.Input, args: [{ isSignal: true, alias: "grid", required: false }] }], isItemEqualToValue: [{ type: i0.Input, args: [{ isSignal: true, alias: "isItemEqualToValue", required: false }] }], itemToStringLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "itemToStringLabel", required: false }] }], itemToStringValue: [{ type: i0.Input, args: [{ isSignal: true, alias: "itemToStringValue", required: false }] }], onValueChange: [{ type: i0.Output, args: ["onValueChange"] }], onInputValueChange: [{ type: i0.Output, args: ["onInputValueChange"] }], onOpenChange: [{ type: i0.Output, args: ["onOpenChange"] }], onItemHighlighted: [{ type: i0.Output, args: ["onItemHighlighted"] }], onOpenChangeComplete: [{ type: i0.Output, args: ["onOpenChangeComplete"] }] } });
|
|
1310
1422
|
|
|
1311
1423
|
/**
|
|
1312
1424
|
* An overlay rendered beneath the popup in `modal` mode. Place it inside the portal/presence; style
|
|
@@ -1637,18 +1749,38 @@ class RdxComboboxGroup {
|
|
|
1637
1749
|
this.rootContext = injectComboboxRootContext();
|
|
1638
1750
|
this.labelId = signal(undefined, /* @ts-ignore */
|
|
1639
1751
|
...(ngDevMode ? [{ debugName: "labelId" }] : /* istanbul ignore next */ []));
|
|
1640
|
-
|
|
1641
|
-
|
|
1642
|
-
this.
|
|
1752
|
+
// Group membership is unordered, so a stable Set avoids copying a growing array for every child
|
|
1753
|
+
// registration. The tick keeps the two derived host states reactive.
|
|
1754
|
+
this.items = new Set();
|
|
1755
|
+
this.itemsTick = signal(0, /* @ts-ignore */
|
|
1756
|
+
...(ngDevMode ? [{ debugName: "itemsTick" }] : /* istanbul ignore next */ []));
|
|
1757
|
+
this.hasItems = computed(() => {
|
|
1758
|
+
this.itemsTick();
|
|
1759
|
+
return this.items.size > 0;
|
|
1760
|
+
}, /* @ts-ignore */
|
|
1643
1761
|
...(ngDevMode ? [{ debugName: "hasItems" }] : /* istanbul ignore next */ []));
|
|
1644
|
-
this.hasVisibleItems = computed(() =>
|
|
1762
|
+
this.hasVisibleItems = computed(() => {
|
|
1763
|
+
this.itemsTick();
|
|
1764
|
+
for (const item of this.items) {
|
|
1765
|
+
if (this.rootContext.isVisible(item)) {
|
|
1766
|
+
return true;
|
|
1767
|
+
}
|
|
1768
|
+
}
|
|
1769
|
+
return false;
|
|
1770
|
+
}, /* @ts-ignore */
|
|
1645
1771
|
...(ngDevMode ? [{ debugName: "hasVisibleItems" }] : /* istanbul ignore next */ []));
|
|
1646
1772
|
}
|
|
1647
1773
|
registerItem(item) {
|
|
1648
|
-
this.items.
|
|
1774
|
+
if (this.items.has(item)) {
|
|
1775
|
+
return;
|
|
1776
|
+
}
|
|
1777
|
+
this.items.add(item);
|
|
1778
|
+
this.itemsTick.update((tick) => tick + 1);
|
|
1649
1779
|
}
|
|
1650
1780
|
unregisterItem(item) {
|
|
1651
|
-
this.items.
|
|
1781
|
+
if (this.items.delete(item)) {
|
|
1782
|
+
this.itemsTick.update((tick) => tick + 1);
|
|
1783
|
+
}
|
|
1652
1784
|
}
|
|
1653
1785
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.2", ngImport: i0, type: RdxComboboxGroup, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
|
|
1654
1786
|
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "22.0.2", type: RdxComboboxGroup, isStandalone: true, selector: "[rdxComboboxGroup]", host: { attributes: { "role": "group" }, properties: { "attr.aria-labelledby": "labelId()", "hidden": "hasItems() && !hasVisibleItems()" } }, providers: [provideComboboxGroupContext(groupContext)], exportAs: ["rdxComboboxGroup"], ngImport: i0 }); }
|
|
@@ -2003,7 +2135,7 @@ class RdxComboboxInput {
|
|
|
2003
2135
|
}
|
|
2004
2136
|
}
|
|
2005
2137
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.2", ngImport: i0, type: RdxComboboxInput, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
|
|
2006
|
-
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "22.0.2", type: RdxComboboxInput, isStandalone: true, selector: "input[rdxComboboxInput]", inputs: { id: { classPropertyName: "id", publicName: "id", isSignal: true, isRequired: false, transformFunction: null }, invalid: { classPropertyName: "invalid", publicName: "invalid", isSignal: true, isRequired: false, transformFunction: null } }, host: { attributes: { "role": "combobox", "autocomplete": "off", "aria-autocomplete": "list" }, listeners: { "input": "onInput($event)", "click": "onClick($event)", "focus": "onFocus()", "blur": "onBlur()", "keydown": "onKeydown($event)", "compositionstart": "composing = true", "compositionend": "onCompositionEnd($event)" }, properties: { "attr.id": "id()", "attr.aria-haspopup": "rootContext.grid() ? \"grid\" : \"listbox\"", "attr.aria-expanded": "rootContext.open()", "attr.aria-controls": "rootContext.listId", "attr.aria-labelledby": "rootContext.labelId()", "attr.aria-activedescendant": "rootContext.activeId()", "attr.aria-describedby": "describedBy()", "attr.aria-invalid": "displayValid() === false ? \"true\" : undefined", "attr.aria-required": "requiredState() ? \"true\" : undefined", "attr.aria-disabled": "disabledState() ? \"true\" : undefined", "attr.disabled": "disabledState() ? \"\" : undefined", "attr.readonly": "rootContext.readonly() ? \"\" : undefined", "attr.required": "requiredState() ? \"\" : undefined", "value": "rootContext.inputValue()", "attr.data-popup-open": "dataAttr(rootContext.open())", "attr.data-list-empty": "dataAttr(rootContext.visibleCount() === 0)", "attr.data-placeholder": "dataAttr(isEmptyValue())", "attr.data-invalid": "dataAttr(displayValid() === false)", "attr.data-valid": "dataAttr(displayValid() === true)", "attr.data-disabled": "dataAttr(disabledState())", "attr.data-required": "dataAttr(requiredState())", "attr.data-touched": "dataAttr(touchedState())", "attr.data-dirty": "dataAttr(dirtyState())", "attr.data-filled": "dataAttr(filledState())", "attr.data-focused": "dataAttr(focusedState())" } }, exportAs: ["rdxComboboxInput"], hostDirectives: [{ directive: i1.RdxPopperAnchor }, { directive: i1$1.RdxFloatingInsideElement }], ngImport: i0 }); }
|
|
2138
|
+
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "22.0.2", type: RdxComboboxInput, isStandalone: true, selector: "input[rdxComboboxInput]", inputs: { id: { classPropertyName: "id", publicName: "id", isSignal: true, isRequired: false, transformFunction: null }, invalid: { classPropertyName: "invalid", publicName: "invalid", isSignal: true, isRequired: false, transformFunction: null } }, host: { attributes: { "role": "combobox", "autocomplete": "off", "aria-autocomplete": "list" }, listeners: { "input": "onInput($event)", "click": "onClick($event)", "focus": "onFocus()", "blur": "onBlur()", "keydown": "onKeydown($event)", "compositionstart": "composing = true", "compositionend": "onCompositionEnd($event)" }, properties: { "attr.id": "id()", "attr.aria-haspopup": "rootContext.grid() ? \"grid\" : \"listbox\"", "attr.aria-expanded": "rootContext.open()", "attr.aria-controls": "rootContext.listId", "attr.aria-labelledby": "rootContext.labelId()", "attr.aria-activedescendant": "rootContext.activeId()", "attr.aria-describedby": "describedBy()", "attr.aria-invalid": "displayValid() === false ? \"true\" : undefined", "attr.aria-required": "requiredState() ? \"true\" : undefined", "attr.aria-disabled": "disabledState() ? \"true\" : undefined", "attr.disabled": "disabledState() ? \"\" : undefined", "attr.readonly": "rootContext.readonly() ? \"\" : undefined", "attr.required": "requiredState() ? \"\" : undefined", "attr.name": "rootContext.inputOwnsFormValue() ? rootContext.name() : undefined", "attr.form": "rootContext.form()", "value": "rootContext.inputValue()", "attr.data-popup-open": "dataAttr(rootContext.open())", "attr.data-list-empty": "dataAttr(rootContext.visibleCount() === 0)", "attr.data-placeholder": "dataAttr(isEmptyValue())", "attr.data-invalid": "dataAttr(displayValid() === false)", "attr.data-valid": "dataAttr(displayValid() === true)", "attr.data-disabled": "dataAttr(disabledState())", "attr.data-required": "dataAttr(requiredState())", "attr.data-touched": "dataAttr(touchedState())", "attr.data-dirty": "dataAttr(dirtyState())", "attr.data-filled": "dataAttr(filledState())", "attr.data-focused": "dataAttr(focusedState())" } }, exportAs: ["rdxComboboxInput"], hostDirectives: [{ directive: i1.RdxPopperAnchor }, { directive: i1$1.RdxFloatingInsideElement }], ngImport: i0 }); }
|
|
2007
2139
|
}
|
|
2008
2140
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.2", ngImport: i0, type: RdxComboboxInput, decorators: [{
|
|
2009
2141
|
type: Directive,
|
|
@@ -2028,6 +2160,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.2", ngImpor
|
|
|
2028
2160
|
'[attr.disabled]': 'disabledState() ? "" : undefined',
|
|
2029
2161
|
'[attr.readonly]': 'rootContext.readonly() ? "" : undefined',
|
|
2030
2162
|
'[attr.required]': 'requiredState() ? "" : undefined',
|
|
2163
|
+
'[attr.name]': 'rootContext.inputOwnsFormValue() ? rootContext.name() : undefined',
|
|
2164
|
+
'[attr.form]': 'rootContext.form()',
|
|
2031
2165
|
'[value]': 'rootContext.inputValue()',
|
|
2032
2166
|
'[attr.data-popup-open]': 'dataAttr(rootContext.open())',
|
|
2033
2167
|
'[attr.data-list-empty]': 'dataAttr(rootContext.visibleCount() === 0)',
|