@radix-ng/primitives 1.0.0-beta.3 → 1.0.0-beta.4
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 +1 -1
- package/fesm2022/radix-ng-primitives-accordion.mjs +5 -3
- package/fesm2022/radix-ng-primitives-accordion.mjs.map +1 -1
- package/fesm2022/radix-ng-primitives-alert-dialog.mjs +3 -2
- package/fesm2022/radix-ng-primitives-alert-dialog.mjs.map +1 -1
- package/fesm2022/radix-ng-primitives-autocomplete.mjs +617 -659
- package/fesm2022/radix-ng-primitives-autocomplete.mjs.map +1 -1
- package/fesm2022/radix-ng-primitives-calendar.mjs +5 -3
- package/fesm2022/radix-ng-primitives-calendar.mjs.map +1 -1
- package/fesm2022/radix-ng-primitives-combobox.mjs +1305 -572
- package/fesm2022/radix-ng-primitives-combobox.mjs.map +1 -1
- package/fesm2022/radix-ng-primitives-config.mjs +13 -4
- package/fesm2022/radix-ng-primitives-config.mjs.map +1 -1
- package/fesm2022/radix-ng-primitives-context-menu.mjs +51 -10
- package/fesm2022/radix-ng-primitives-context-menu.mjs.map +1 -1
- package/fesm2022/radix-ng-primitives-core.mjs +1345 -64
- package/fesm2022/radix-ng-primitives-core.mjs.map +1 -1
- package/fesm2022/radix-ng-primitives-date-field.mjs +5 -3
- package/fesm2022/radix-ng-primitives-date-field.mjs.map +1 -1
- package/fesm2022/radix-ng-primitives-dialog.mjs +240 -112
- package/fesm2022/radix-ng-primitives-dialog.mjs.map +1 -1
- package/fesm2022/radix-ng-primitives-direction-provider.mjs +70 -0
- package/fesm2022/radix-ng-primitives-direction-provider.mjs.map +1 -0
- package/fesm2022/radix-ng-primitives-dismissable-layer.mjs +519 -184
- package/fesm2022/radix-ng-primitives-dismissable-layer.mjs.map +1 -1
- package/fesm2022/radix-ng-primitives-drawer.mjs +3 -3
- package/fesm2022/radix-ng-primitives-drawer.mjs.map +1 -1
- package/fesm2022/radix-ng-primitives-field.mjs +3 -2
- package/fesm2022/radix-ng-primitives-field.mjs.map +1 -1
- package/fesm2022/radix-ng-primitives-floating-focus-manager.mjs +517 -0
- package/fesm2022/radix-ng-primitives-floating-focus-manager.mjs.map +1 -0
- package/fesm2022/radix-ng-primitives-focus-scope.mjs +296 -70
- package/fesm2022/radix-ng-primitives-focus-scope.mjs.map +1 -1
- package/fesm2022/radix-ng-primitives-menu.mjs +861 -286
- package/fesm2022/radix-ng-primitives-menu.mjs.map +1 -1
- package/fesm2022/radix-ng-primitives-menubar.mjs +32 -4
- package/fesm2022/radix-ng-primitives-menubar.mjs.map +1 -1
- package/fesm2022/radix-ng-primitives-navigation-menu.mjs +144 -159
- package/fesm2022/radix-ng-primitives-navigation-menu.mjs.map +1 -1
- package/fesm2022/radix-ng-primitives-popover.mjs +220 -205
- package/fesm2022/radix-ng-primitives-popover.mjs.map +1 -1
- package/fesm2022/radix-ng-primitives-popper.mjs +94 -51
- package/fesm2022/radix-ng-primitives-popper.mjs.map +1 -1
- package/fesm2022/radix-ng-primitives-presence.mjs +1 -1
- package/fesm2022/radix-ng-primitives-presence.mjs.map +1 -1
- package/fesm2022/radix-ng-primitives-preview-card.mjs +141 -173
- package/fesm2022/radix-ng-primitives-preview-card.mjs.map +1 -1
- package/fesm2022/radix-ng-primitives-roving-focus.mjs +4 -2
- package/fesm2022/radix-ng-primitives-roving-focus.mjs.map +1 -1
- package/fesm2022/radix-ng-primitives-scroll-area.mjs +5 -4
- package/fesm2022/radix-ng-primitives-scroll-area.mjs.map +1 -1
- package/fesm2022/radix-ng-primitives-select.mjs +211 -156
- package/fesm2022/radix-ng-primitives-select.mjs.map +1 -1
- package/fesm2022/radix-ng-primitives-slider.mjs +5 -3
- package/fesm2022/radix-ng-primitives-slider.mjs.map +1 -1
- package/fesm2022/radix-ng-primitives-stepper.mjs +5 -3
- package/fesm2022/radix-ng-primitives-stepper.mjs.map +1 -1
- package/fesm2022/radix-ng-primitives-time-field.mjs +5 -3
- package/fesm2022/radix-ng-primitives-time-field.mjs.map +1 -1
- package/fesm2022/radix-ng-primitives-toast.mjs +15 -36
- package/fesm2022/radix-ng-primitives-toast.mjs.map +1 -1
- package/fesm2022/radix-ng-primitives-toggle-group.mjs +5 -3
- package/fesm2022/radix-ng-primitives-toggle-group.mjs.map +1 -1
- package/fesm2022/radix-ng-primitives-toolbar.mjs +5 -3
- package/fesm2022/radix-ng-primitives-toolbar.mjs.map +1 -1
- package/fesm2022/radix-ng-primitives-tooltip.mjs +73 -110
- package/fesm2022/radix-ng-primitives-tooltip.mjs.map +1 -1
- package/package.json +10 -1
- package/types/radix-ng-primitives-accordion.d.ts +4 -3
- package/types/radix-ng-primitives-autocomplete.d.ts +217 -152
- package/types/radix-ng-primitives-calendar.d.ts +5 -3
- package/types/radix-ng-primitives-combobox.d.ts +672 -283
- package/types/radix-ng-primitives-config.d.ts +1 -1
- package/types/radix-ng-primitives-context-menu.d.ts +15 -5
- package/types/radix-ng-primitives-core.d.ts +762 -14
- package/types/radix-ng-primitives-date-field.d.ts +3 -2
- package/types/radix-ng-primitives-dialog.d.ts +77 -32
- package/types/radix-ng-primitives-direction-provider.d.ts +41 -0
- package/types/radix-ng-primitives-dismissable-layer.d.ts +147 -99
- package/types/radix-ng-primitives-field.d.ts +1 -0
- package/types/radix-ng-primitives-floating-focus-manager.d.ts +175 -0
- package/types/radix-ng-primitives-focus-scope.d.ts +132 -1
- package/types/radix-ng-primitives-menu.d.ts +186 -103
- package/types/radix-ng-primitives-navigation-menu.d.ts +37 -75
- package/types/radix-ng-primitives-popover.d.ts +59 -92
- package/types/radix-ng-primitives-popper.d.ts +39 -9
- package/types/radix-ng-primitives-preview-card.d.ts +39 -72
- package/types/radix-ng-primitives-roving-focus.d.ts +7 -6
- package/types/radix-ng-primitives-scroll-area.d.ts +2 -2
- package/types/radix-ng-primitives-select.d.ts +145 -108
- package/types/radix-ng-primitives-slider.d.ts +5 -4
- package/types/radix-ng-primitives-stepper.d.ts +4 -3
- package/types/radix-ng-primitives-time-field.d.ts +3 -2
- package/types/radix-ng-primitives-toast.d.ts +7 -7
- package/types/radix-ng-primitives-toggle-group.d.ts +5 -4
- package/types/radix-ng-primitives-toolbar.d.ts +3 -2
- package/types/radix-ng-primitives-tooltip.d.ts +24 -67
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
|
-
import { inject, model,
|
|
3
|
-
import
|
|
2
|
+
import { inject, model, signal, computed, ElementRef, input, booleanAttribute, output, untracked, effect, Directive, InjectionToken, Injector, DestroyRef, afterNextRender, linkedSignal, isDevMode, forwardRef } from '@angular/core';
|
|
3
|
+
import * as i3 from '@radix-ng/primitives/core';
|
|
4
|
+
import { isEqual, getActiveElement, createContext, createFloatingRootContext, useTransitionStatus, isNullish, provideFloatingTree, provideFloatingRootContext, injectId, RDX_FLOATING_ROOT_CONTEXT, RDX_FLOATING_REGISTRATION, useListHighlight, useAnchoredScrollLock, RdxFloatingNodeRegistration, handleAndDispatchCustomEvent, rdxDevError, setupInternalBackdrop } from '@radix-ng/primitives/core';
|
|
5
|
+
import { injectDirection } from '@radix-ng/primitives/direction-provider';
|
|
6
|
+
import { getInteractionTypeFromEvent } from '@radix-ng/primitives/floating-focus-manager';
|
|
4
7
|
import * as i1 from '@radix-ng/primitives/popper';
|
|
5
|
-
import { RdxPopper, RdxPopperContent, RdxPopperContentWrapper, RdxPopperAnchor } from '@radix-ng/primitives/popper';
|
|
8
|
+
import { RdxPopper, RdxPopperContent, RdxPopperContentWrapper, legacyPopperVars, provideRdxPopperContentWrapper, provideRdxPopperContentConfig, RdxPopperAnchor } from '@radix-ng/primitives/popper';
|
|
6
9
|
import * as i4 from '@radix-ng/primitives/collection';
|
|
7
10
|
import { RdxCollectionProvider, RdxCollectionItem } from '@radix-ng/primitives/collection';
|
|
8
|
-
import {
|
|
9
|
-
import * as i3 from '@radix-ng/primitives/dismissable-layer';
|
|
10
|
-
import { RdxDismissableLayer, provideRdxDismissableLayerConfig } from '@radix-ng/primitives/dismissable-layer';
|
|
11
|
+
import { RdxDismiss } from '@radix-ng/primitives/dismissable-layer';
|
|
11
12
|
import * as i2 from '@radix-ng/primitives/focus-scope';
|
|
12
13
|
import { RdxFocusScope } from '@radix-ng/primitives/focus-scope';
|
|
13
14
|
import * as i1$1 from '@radix-ng/primitives/portal';
|
|
@@ -52,6 +53,17 @@ function focusFirst(candidates) {
|
|
|
52
53
|
}
|
|
53
54
|
}
|
|
54
55
|
|
|
56
|
+
function createChangeEventDetails(reason, event) {
|
|
57
|
+
let canceled = false;
|
|
58
|
+
return {
|
|
59
|
+
reason,
|
|
60
|
+
event,
|
|
61
|
+
cancel: () => {
|
|
62
|
+
canceled = true;
|
|
63
|
+
},
|
|
64
|
+
isCanceled: () => canceled
|
|
65
|
+
};
|
|
66
|
+
}
|
|
55
67
|
const context$2 = () => {
|
|
56
68
|
const context = inject(RdxSelectRoot);
|
|
57
69
|
return {
|
|
@@ -65,6 +77,10 @@ const context$2 = () => {
|
|
|
65
77
|
isItemEqualToValue: context.isItemEqualToValue,
|
|
66
78
|
itemToStringLabel: context.itemToStringLabel,
|
|
67
79
|
open: context.open,
|
|
80
|
+
openedByTouch: context.openedByTouch,
|
|
81
|
+
openMethod: context.openMethod,
|
|
82
|
+
openInteractionType: context.openInteractionType,
|
|
83
|
+
closeInteractionType: context.closeInteractionType,
|
|
68
84
|
disabled: context.disabled,
|
|
69
85
|
modal: context.modal,
|
|
70
86
|
isEmptyModelValue: context.isEmptyModelValue,
|
|
@@ -84,32 +100,48 @@ const context$2 = () => {
|
|
|
84
100
|
context.optionsSet().delete(existingOption);
|
|
85
101
|
}
|
|
86
102
|
},
|
|
87
|
-
onValueChange: context.
|
|
103
|
+
onValueChange: (value, reason, event) => context.setValue(value, reason, event),
|
|
88
104
|
onTriggerChange: (node) => {
|
|
89
105
|
context.triggerElement.set(node.nativeElement);
|
|
90
106
|
},
|
|
91
107
|
onValueElementChange: (node) => {
|
|
92
108
|
context.valueElement.set(node);
|
|
93
109
|
},
|
|
94
|
-
onOpenChange: (value) =>
|
|
95
|
-
context.open.set(value);
|
|
96
|
-
}
|
|
110
|
+
onOpenChange: (value, reason, event) => context.setOpen(value, reason, event)
|
|
97
111
|
};
|
|
98
112
|
};
|
|
99
113
|
const [injectSelectRootContext, provideSelectRootContext] = createContext('RdxSelectRootContext', 'components/select');
|
|
100
114
|
class RdxSelectRoot {
|
|
101
115
|
constructor() {
|
|
102
116
|
this.open = model(false, ...(ngDevMode ? [{ debugName: "open" }] : /* istanbul ignore next */ []));
|
|
117
|
+
/** Whether the current open was initiated by **touch** (ADR 0016 §3 — gates the anchored scroll lock). */
|
|
118
|
+
this.openedByTouch = signal(false, ...(ngDevMode ? [{ debugName: "openedByTouch" }] : /* istanbul ignore next */ []));
|
|
119
|
+
/** How the select was opened. Base UI names this state `openMethod`. */
|
|
120
|
+
this.openInteractionType = signal(null, ...(ngDevMode ? [{ debugName: "openInteractionType" }] : /* istanbul ignore next */ []));
|
|
121
|
+
/** How the select was closed. */
|
|
122
|
+
this.closeInteractionType = signal(null, ...(ngDevMode ? [{ debugName: "closeInteractionType" }] : /* istanbul ignore next */ []));
|
|
123
|
+
/** Public Base UI-aligned alias for the open interaction type. */
|
|
124
|
+
this.openMethod = computed(() => this.openInteractionType(), ...(ngDevMode ? [{ debugName: "openMethod" }] : /* istanbul ignore next */ []));
|
|
125
|
+
/** Per-popup floating root context (ADR 0015) — `open` / `triggers` / reference for the dismissal engine. */
|
|
126
|
+
this.floatingContext = createFloatingRootContext({
|
|
127
|
+
ownerDocument: inject(ElementRef).nativeElement.ownerDocument,
|
|
128
|
+
open: () => this.open()
|
|
129
|
+
});
|
|
103
130
|
this.value = model(...(ngDevMode ? [undefined, { debugName: "value" }] : /* istanbul ignore next */ []));
|
|
104
131
|
this.multiple = input(false, { ...(ngDevMode ? { debugName: "multiple" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
105
132
|
this.disabled = input(false, { ...(ngDevMode ? { debugName: "disabled" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
106
133
|
/** Whether the popup is modal: locks page scroll and makes outside content inert while open. */
|
|
107
134
|
this.modal = input(true, { ...(ngDevMode ? { debugName: "modal" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
108
|
-
this.
|
|
135
|
+
this.dirInput = input(undefined, { ...(ngDevMode ? { debugName: "dirInput" } : /* istanbul ignore next */ {}), alias: 'dir' });
|
|
136
|
+
this.dir = injectDirection(this.dirInput);
|
|
109
137
|
/** How item values are compared for equality — a function `(a, b) => boolean` or an object key. */
|
|
110
138
|
this.isItemEqualToValue = input(...(ngDevMode ? [undefined, { debugName: "isItemEqualToValue" }] : /* istanbul ignore next */ []));
|
|
111
139
|
/** Converts a value to its display label (used by `RdxSelectValue`). */
|
|
112
140
|
this.itemToStringLabel = input(...(ngDevMode ? [undefined, { debugName: "itemToStringLabel" }] : /* istanbul ignore next */ []));
|
|
141
|
+
/** Emits before an open-state change is committed; call `eventDetails.cancel()` to veto it. */
|
|
142
|
+
this.onOpenChange = output();
|
|
143
|
+
/** Emits before a value change is committed; call `eventDetails.cancel()` to veto it. */
|
|
144
|
+
this.onValueChange = output();
|
|
113
145
|
/** Emits after the open/close transition (including any exit animation) finishes. */
|
|
114
146
|
this.onOpenChangeComplete = output();
|
|
115
147
|
this.transition = useTransitionStatus((open) => this.onOpenChangeComplete.emit(open));
|
|
@@ -150,34 +182,89 @@ class RdxSelectRoot {
|
|
|
150
182
|
previousOpen = open;
|
|
151
183
|
untracked(() => this.transition.start(open));
|
|
152
184
|
});
|
|
185
|
+
// A fresh open starts non-touch; the trigger flips it on a touch open. Reset whenever it closes.
|
|
186
|
+
effect(() => {
|
|
187
|
+
if (!this.open()) {
|
|
188
|
+
untracked(() => this.openedByTouch.set(false));
|
|
189
|
+
}
|
|
190
|
+
});
|
|
191
|
+
// Bridge the trigger into the floating context: the dismissal capability treats a press on the
|
|
192
|
+
// trigger (the reference) as "inside", and uses it for positioning containment (ADR 0015).
|
|
193
|
+
effect((onCleanup) => {
|
|
194
|
+
const trigger = this.triggerElement();
|
|
195
|
+
this.floatingContext.setReferenceElement(trigger);
|
|
196
|
+
if (trigger) {
|
|
197
|
+
this.floatingContext.triggers.add(trigger);
|
|
198
|
+
onCleanup(() => this.floatingContext.triggers.delete(trigger));
|
|
199
|
+
}
|
|
200
|
+
});
|
|
153
201
|
}
|
|
154
202
|
getOption(value) {
|
|
155
203
|
return Array.from(this.optionsSet()).find((option) => valueComparator(value, option.value, this.isItemEqualToValue()));
|
|
156
204
|
}
|
|
157
|
-
|
|
205
|
+
setValue(value, reason = 'none', event = new Event('select.value-change')) {
|
|
206
|
+
const nextValue = this.multiple()
|
|
207
|
+
? (() => {
|
|
208
|
+
const current = this.value();
|
|
209
|
+
const array = Array.isArray(current) ? [...current] : [];
|
|
210
|
+
const index = array.findIndex((i) => compare(i, value, this.isItemEqualToValue()));
|
|
211
|
+
index === -1 ? array.push(value) : array.splice(index, 1);
|
|
212
|
+
return [...array];
|
|
213
|
+
})()
|
|
214
|
+
: value;
|
|
215
|
+
const eventDetails = createChangeEventDetails(reason, event);
|
|
216
|
+
this.onValueChange.emit({ value: nextValue, eventDetails });
|
|
217
|
+
if (eventDetails.isCanceled()) {
|
|
218
|
+
return false;
|
|
219
|
+
}
|
|
158
220
|
if (this.multiple()) {
|
|
159
|
-
|
|
160
|
-
const array = Array.isArray(current) ? [...current] : [];
|
|
161
|
-
const index = array.findIndex((i) => compare(i, value, this.isItemEqualToValue()));
|
|
162
|
-
index === -1 ? array.push(value) : array.splice(index, 1);
|
|
163
|
-
this.value.set([...array]);
|
|
221
|
+
this.value.set(nextValue);
|
|
164
222
|
}
|
|
165
223
|
else {
|
|
166
|
-
this.value.set(
|
|
224
|
+
this.value.set(nextValue);
|
|
167
225
|
}
|
|
226
|
+
return true;
|
|
227
|
+
}
|
|
228
|
+
setOpen(open, reason = 'none', event) {
|
|
229
|
+
const resolvedEvent = event ?? new Event('select.open-change');
|
|
230
|
+
const interactionType = getInteractionTypeFromEvent(event);
|
|
231
|
+
const eventDetails = createChangeEventDetails(reason, resolvedEvent);
|
|
232
|
+
this.onOpenChange.emit({ open, eventDetails });
|
|
233
|
+
if (eventDetails.isCanceled()) {
|
|
234
|
+
return false;
|
|
235
|
+
}
|
|
236
|
+
this.open.set(open);
|
|
237
|
+
if (open) {
|
|
238
|
+
this.openedByTouch.set(event?.pointerType === 'touch');
|
|
239
|
+
this.openInteractionType.set(interactionType);
|
|
240
|
+
}
|
|
241
|
+
else {
|
|
242
|
+
this.closeInteractionType.set(interactionType);
|
|
243
|
+
}
|
|
244
|
+
return true;
|
|
168
245
|
}
|
|
169
246
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxSelectRoot, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
|
|
170
|
-
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.2.9", type: RdxSelectRoot, isStandalone: true, selector: "[rdxSelectRoot]", inputs: { open: { classPropertyName: "open", publicName: "open", isSignal: true, isRequired: false, transformFunction: null }, value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, multiple: { classPropertyName: "multiple", publicName: "multiple", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, modal: { classPropertyName: "modal", publicName: "modal", isSignal: true, isRequired: false, transformFunction: null },
|
|
247
|
+
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.2.9", type: RdxSelectRoot, isStandalone: true, selector: "[rdxSelectRoot]", inputs: { open: { classPropertyName: "open", publicName: "open", isSignal: true, isRequired: false, transformFunction: null }, value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, multiple: { classPropertyName: "multiple", publicName: "multiple", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, modal: { classPropertyName: "modal", publicName: "modal", isSignal: true, isRequired: false, transformFunction: null }, dirInput: { classPropertyName: "dirInput", publicName: "dir", 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: { open: "openChange", value: "valueChange", onOpenChange: "onOpenChange", onValueChange: "onValueChange", onOpenChangeComplete: "onOpenChangeComplete" }, providers: [
|
|
248
|
+
provideSelectRootContext(context$2),
|
|
249
|
+
// New floating foundation (ADR 0015/0017) — the dismissal capability reads this shared context.
|
|
250
|
+
provideFloatingTree(),
|
|
251
|
+
provideFloatingRootContext(() => inject(RdxSelectRoot).floatingContext)
|
|
252
|
+
], exportAs: ["rdxSelectRoot"], hostDirectives: [{ directive: i1.RdxPopper }], ngImport: i0 }); }
|
|
171
253
|
}
|
|
172
254
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxSelectRoot, decorators: [{
|
|
173
255
|
type: Directive,
|
|
174
256
|
args: [{
|
|
175
257
|
selector: '[rdxSelectRoot]',
|
|
176
258
|
exportAs: 'rdxSelectRoot',
|
|
177
|
-
providers: [
|
|
259
|
+
providers: [
|
|
260
|
+
provideSelectRootContext(context$2),
|
|
261
|
+
// New floating foundation (ADR 0015/0017) — the dismissal capability reads this shared context.
|
|
262
|
+
provideFloatingTree(),
|
|
263
|
+
provideFloatingRootContext(() => inject(RdxSelectRoot).floatingContext)
|
|
264
|
+
],
|
|
178
265
|
hostDirectives: [RdxPopper]
|
|
179
266
|
}]
|
|
180
|
-
}], ctorParameters: () => [], propDecorators: { open: [{ type: i0.Input, args: [{ isSignal: true, alias: "open", required: false }] }, { type: i0.Output, args: ["openChange"] }], value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }, { type: i0.Output, args: ["valueChange"] }], multiple: [{ type: i0.Input, args: [{ isSignal: true, alias: "multiple", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], modal: [{ type: i0.Input, args: [{ isSignal: true, alias: "modal", required: false }] }],
|
|
267
|
+
}], ctorParameters: () => [], propDecorators: { open: [{ type: i0.Input, args: [{ isSignal: true, alias: "open", required: false }] }, { type: i0.Output, args: ["openChange"] }], value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }, { type: i0.Output, args: ["valueChange"] }], multiple: [{ type: i0.Input, args: [{ isSignal: true, alias: "multiple", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], modal: [{ type: i0.Input, args: [{ isSignal: true, alias: "modal", required: false }] }], dirInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "dir", required: false }] }], isItemEqualToValue: [{ type: i0.Input, args: [{ isSignal: true, alias: "isItemEqualToValue", required: false }] }], itemToStringLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "itemToStringLabel", required: false }] }], onOpenChange: [{ type: i0.Output, args: ["onOpenChange"] }], onValueChange: [{ type: i0.Output, args: ["onValueChange"] }], onOpenChangeComplete: [{ type: i0.Output, args: ["onOpenChangeComplete"] }] } });
|
|
181
268
|
|
|
182
269
|
/**
|
|
183
270
|
* An overlay rendered beneath the popup in `modal` mode. Place it inside the portal/presence; style
|
|
@@ -312,7 +399,8 @@ const RDX_SELECT_POSITIONER_TOKEN = new InjectionToken('RDX_SELECT_POSITIONER_TO
|
|
|
312
399
|
*/
|
|
313
400
|
class RdxSelectPopup {
|
|
314
401
|
constructor() {
|
|
315
|
-
this.
|
|
402
|
+
this.floatingContext = inject(RDX_FLOATING_ROOT_CONTEXT);
|
|
403
|
+
this.registration = inject(RDX_FLOATING_REGISTRATION, { optional: true });
|
|
316
404
|
this.currentElement = inject(ElementRef);
|
|
317
405
|
this.collection = inject(RdxCollectionProvider);
|
|
318
406
|
this.injector = inject(Injector);
|
|
@@ -347,12 +435,12 @@ class RdxSelectPopup {
|
|
|
347
435
|
* Event handler called when the escape key is down.
|
|
348
436
|
* Can be prevented.
|
|
349
437
|
*/
|
|
350
|
-
this.escapeKeyDown =
|
|
438
|
+
this.escapeKeyDown = output();
|
|
351
439
|
/**
|
|
352
|
-
* Event handler called when a `pointerdown` event happens outside of the
|
|
440
|
+
* Event handler called when a `pointerdown` event happens outside of the popup.
|
|
353
441
|
* Can be prevented.
|
|
354
442
|
*/
|
|
355
|
-
this.pointerDownOutside =
|
|
443
|
+
this.pointerDownOutside = output();
|
|
356
444
|
this.content = signal(null, ...(ngDevMode ? [{ debugName: "content" }] : /* istanbul ignore next */ []));
|
|
357
445
|
/**
|
|
358
446
|
* The positioner — now an **ancestor** element — provides {@link RDX_SELECT_POSITIONER_TOKEN}
|
|
@@ -383,13 +471,33 @@ class RdxSelectPopup {
|
|
|
383
471
|
item.element.scrollIntoView?.({ block: 'nearest' });
|
|
384
472
|
}
|
|
385
473
|
});
|
|
386
|
-
// Lock page scroll while
|
|
387
|
-
|
|
474
|
+
// Activation policy (ADR 0016 §2 + §3). Lock page scroll while the popup is OPEN and either modal
|
|
475
|
+
// **or** item-aligned — Base UI `(alignItemWithTriggerActive || modal) && open` (AC #3): an
|
|
476
|
+
// item-aligned select overlays the trigger, so the page must not scroll behind it even when
|
|
477
|
+
// `modal === false`. The gate keys on `open` (not mounted) so it releases at close-start. A
|
|
478
|
+
// **touch** open never uses item-aligned mode (the positioner falls back), so the lock there is
|
|
479
|
+
// driven by `modal` alone and the anchored helper only engages when the popup is viewport-width (§3).
|
|
480
|
+
const itemAlignedActive = computed(() => this.positioner?.alignItemWithTriggerActive?.() ?? false, ...(ngDevMode ? [{ debugName: "itemAlignedActive" }] : /* istanbul ignore next */ []));
|
|
481
|
+
useAnchoredScrollLock(computed(() => (itemAlignedActive() || this.rootContext.modal()) && this.rootContext.open()), {
|
|
482
|
+
touchOpen: () => this.rootContext.openedByTouch(),
|
|
483
|
+
element: () => this.currentElement.nativeElement
|
|
484
|
+
});
|
|
388
485
|
// The popup's animation determines when the open/close transition (onOpenChangeComplete) is done.
|
|
389
486
|
const unregisterTransition = this.rootContext.registerTransitionElement(this.currentElement.nativeElement);
|
|
390
487
|
inject(DestroyRef).onDestroy(unregisterTransition);
|
|
391
|
-
|
|
392
|
-
this.
|
|
488
|
+
// The popup (listbox) is this layer's floating element — the inside surface for containment.
|
|
489
|
+
this.floatingContext.setFloatingElement(this.currentElement.nativeElement);
|
|
490
|
+
// Dismissal (ADR 0015): Escape or an outside press closes the select. Focus-out does NOT close it
|
|
491
|
+
// — the listbox holds focus while open (items are navigated virtually), so a focus-out is not a
|
|
492
|
+
// dismissal (the legacy preventDefaulted it too).
|
|
493
|
+
new RdxDismiss(this.floatingContext, () => this.registration?.node() ?? null, {
|
|
494
|
+
escapeKey: () => true,
|
|
495
|
+
outsidePress: () => true,
|
|
496
|
+
focusOutside: () => false,
|
|
497
|
+
onEscapeKeyDown: (event) => this.escapeKeyDown.emit(event),
|
|
498
|
+
onPointerDownOutside: (event) => this.pointerDownOutside.emit(event),
|
|
499
|
+
onDismiss: (reason, event) => this.rootContext.onOpenChange(false, reason === 'escape-key' ? 'escape-key' : reason === 'focus-outside' ? 'focus-out' : 'outside-press', event)
|
|
500
|
+
});
|
|
393
501
|
const focusScope = inject(RdxFocusScope);
|
|
394
502
|
afterNextRender(() => {
|
|
395
503
|
focusScope.unmountAutoFocus.subscribe((event) => {
|
|
@@ -427,8 +535,9 @@ class RdxSelectPopup {
|
|
|
427
535
|
}
|
|
428
536
|
else {
|
|
429
537
|
// otherwise, if the event was outside the content, close.
|
|
430
|
-
if (!this.content()?.contains(event.target))
|
|
431
|
-
this.rootContext.onOpenChange(false);
|
|
538
|
+
if (!this.content()?.contains(event.target)) {
|
|
539
|
+
this.rootContext.onOpenChange(false, 'outside-press', event);
|
|
540
|
+
}
|
|
432
541
|
}
|
|
433
542
|
document.removeEventListener('pointermove', handlePointerMove);
|
|
434
543
|
this.rootContext.triggerPointerDownPosRef.set(null);
|
|
@@ -447,6 +556,21 @@ class RdxSelectPopup {
|
|
|
447
556
|
});
|
|
448
557
|
});
|
|
449
558
|
});
|
|
559
|
+
effect((onCleanup) => {
|
|
560
|
+
if (!itemAlignedActive() || !this.rootContext.open()) {
|
|
561
|
+
return;
|
|
562
|
+
}
|
|
563
|
+
const popup = this.content();
|
|
564
|
+
const view = popup?.ownerDocument.defaultView;
|
|
565
|
+
if (!view) {
|
|
566
|
+
return;
|
|
567
|
+
}
|
|
568
|
+
const handleResize = (event) => {
|
|
569
|
+
this.rootContext.onOpenChange(false, 'window-resize', event);
|
|
570
|
+
};
|
|
571
|
+
view.addEventListener('resize', handleResize);
|
|
572
|
+
onCleanup(() => view.removeEventListener('resize', handleResize));
|
|
573
|
+
});
|
|
450
574
|
}
|
|
451
575
|
/** Highlights the selected item (or the first enabled one) when the popup opens. */
|
|
452
576
|
highlightSelectedItem() {
|
|
@@ -481,9 +605,10 @@ class RdxSelectPopup {
|
|
|
481
605
|
event.preventDefault();
|
|
482
606
|
const item = this.highlight.highlightedItem();
|
|
483
607
|
if (item && !item.disabled()) {
|
|
484
|
-
this.rootContext.onValueChange(item.value());
|
|
485
|
-
if (!this.rootContext.multiple())
|
|
486
|
-
this.rootContext.onOpenChange(false);
|
|
608
|
+
this.rootContext.onValueChange(item.value(), 'item-press', event);
|
|
609
|
+
if (!this.rootContext.multiple()) {
|
|
610
|
+
this.rootContext.onOpenChange(false, 'item-press', event);
|
|
611
|
+
}
|
|
487
612
|
}
|
|
488
613
|
return;
|
|
489
614
|
}
|
|
@@ -507,28 +632,14 @@ class RdxSelectPopup {
|
|
|
507
632
|
}
|
|
508
633
|
}
|
|
509
634
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxSelectPopup, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
|
|
510
|
-
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.2.9", type: RdxSelectPopup, isStandalone: true, selector: "[rdxSelectPopup]", outputs: { escapeKeyDown: "escapeKeyDown", pointerDownOutside: "pointerDownOutside" }, host: { attributes: { "role": "listbox", "tabindex": "-1" }, listeners: { "keydown": "handleKeyDown($event)" }, properties: { "id": "rootContext.contentId", "attr.aria-activedescendant": "highlight.activeId()", "attr.aria-multiselectable": "rootContext.multiple() ? \"true\" : undefined", "attr.data-state": "rootContext.open() ? \"open\" : \"closed\"", "attr.data-open": "rootContext.open() ? \"\" : undefined", "attr.data-closed": "rootContext.open() ? undefined : \"\"", "attr.data-starting-style": "rootContext.transitionStatus() === \"starting\" ? \"\" : undefined", "attr.data-ending-style": "rootContext.transitionStatus() === \"ending\" ? \"\" : undefined", "dir": "rootContext.dir()", "style": "{\n display: 'flex',\n flexDirection: 'column',\n outline: 'none'\n }" } }, providers: [
|
|
511
|
-
provideSelectPopupContext(context$1),
|
|
512
|
-
provideRdxDismissableLayerConfig(() => {
|
|
513
|
-
return {
|
|
514
|
-
disableOutsidePointerEvents: injectSelectRootContext().modal
|
|
515
|
-
};
|
|
516
|
-
})
|
|
517
|
-
], hostDirectives: [{ directive: i1.RdxPopperContent }, { directive: i2.RdxFocusScope }, { directive: i3.RdxDismissableLayer }, { directive: i4.RdxCollectionProvider }], ngImport: i0 }); }
|
|
635
|
+
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.2.9", type: RdxSelectPopup, isStandalone: true, selector: "[rdxSelectPopup]", outputs: { escapeKeyDown: "escapeKeyDown", pointerDownOutside: "pointerDownOutside" }, host: { attributes: { "role": "listbox", "tabindex": "-1" }, listeners: { "keydown": "handleKeyDown($event)" }, properties: { "id": "rootContext.contentId", "attr.aria-activedescendant": "highlight.activeId()", "attr.aria-multiselectable": "rootContext.multiple() ? \"true\" : undefined", "attr.data-state": "rootContext.open() ? \"open\" : \"closed\"", "attr.data-open": "rootContext.open() ? \"\" : undefined", "attr.data-closed": "rootContext.open() ? undefined : \"\"", "attr.data-starting-style": "rootContext.transitionStatus() === \"starting\" ? \"\" : undefined", "attr.data-ending-style": "rootContext.transitionStatus() === \"ending\" ? \"\" : undefined", "dir": "rootContext.dir()", "style": "{\n display: 'flex',\n flexDirection: 'column',\n outline: 'none'\n }" } }, providers: [provideSelectPopupContext(context$1)], hostDirectives: [{ directive: i1.RdxPopperContent }, { directive: i2.RdxFocusScope }, { directive: i3.RdxFloatingNodeRegistration }, { directive: i4.RdxCollectionProvider }], ngImport: i0 }); }
|
|
518
636
|
}
|
|
519
637
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxSelectPopup, decorators: [{
|
|
520
638
|
type: Directive,
|
|
521
639
|
args: [{
|
|
522
640
|
selector: '[rdxSelectPopup]',
|
|
523
|
-
hostDirectives: [RdxPopperContent, RdxFocusScope,
|
|
524
|
-
providers: [
|
|
525
|
-
provideSelectPopupContext(context$1),
|
|
526
|
-
provideRdxDismissableLayerConfig(() => {
|
|
527
|
-
return {
|
|
528
|
-
disableOutsidePointerEvents: injectSelectRootContext().modal
|
|
529
|
-
};
|
|
530
|
-
})
|
|
531
|
-
],
|
|
641
|
+
hostDirectives: [RdxPopperContent, RdxFocusScope, RdxFloatingNodeRegistration, RdxCollectionProvider],
|
|
642
|
+
providers: [provideSelectPopupContext(context$1)],
|
|
532
643
|
host: {
|
|
533
644
|
role: 'listbox',
|
|
534
645
|
tabindex: '-1',
|
|
@@ -594,9 +705,9 @@ class RdxSelectItem {
|
|
|
594
705
|
handleAndDispatchCustomEvent(this.SELECT_SELECT, async (event) => {
|
|
595
706
|
if (event.defaultPrevented)
|
|
596
707
|
return;
|
|
597
|
-
this.rootContext.onValueChange(this.value());
|
|
708
|
+
this.rootContext.onValueChange(this.value(), 'item-press', event.detail.originalEvent);
|
|
598
709
|
if (!this.rootContext.multiple()) {
|
|
599
|
-
this.rootContext.onOpenChange(false);
|
|
710
|
+
this.rootContext.onOpenChange(false, 'item-press', event.detail.originalEvent);
|
|
600
711
|
}
|
|
601
712
|
}, eventDetail);
|
|
602
713
|
}
|
|
@@ -773,9 +884,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
|
|
|
773
884
|
class RdxSelectPortalMisuseGuard {
|
|
774
885
|
constructor() {
|
|
775
886
|
if (isDevMode()) {
|
|
776
|
-
|
|
887
|
+
rdxDevError('select/portal-on-element', '`rdxSelectPortal` is now a structural directive. ' +
|
|
777
888
|
'Use `*rdxSelectPortal` on the popup element or `<ng-template rdxSelectPortal>`. ' +
|
|
778
|
-
'rdxSelectPortalPresence has been removed.
|
|
889
|
+
'rdxSelectPortalPresence has been removed.', 'components/select');
|
|
779
890
|
}
|
|
780
891
|
}
|
|
781
892
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxSelectPortalMisuseGuard, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
|
|
@@ -788,112 +899,53 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
|
|
|
788
899
|
}]
|
|
789
900
|
}], ctorParameters: () => [] });
|
|
790
901
|
|
|
791
|
-
|
|
902
|
+
/**
|
|
903
|
+
* Positions the select popup against the trigger using the popper engine.
|
|
904
|
+
*
|
|
905
|
+
* A "thin" positioner (ADR 0012): it inherits the full popper positioning surface — the inputs
|
|
906
|
+
* (`side`, `sideOffset`, `align`, …), the `placed` output, and the host bindings — from
|
|
907
|
+
* {@link RdxPopperContentWrapper}, and declares select's Base UI-aligned defaults via the config
|
|
908
|
+
* provider. It also satisfies {@link RdxPositionerImpl} (via the inherited `placed`) so the popup can
|
|
909
|
+
* resolve it through {@link RDX_SELECT_POSITIONER_TOKEN}, the same as the item-aligned positioner.
|
|
910
|
+
*/
|
|
911
|
+
class RdxSelectPositioner extends RdxPopperContentWrapper {
|
|
792
912
|
constructor() {
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
this.align = input('start', ...(ngDevMode ? [{ debugName: "align" }] : /* istanbul ignore next */ []));
|
|
806
|
-
/**
|
|
807
|
-
* An offset in pixels from the `start` or `end` alignment options.
|
|
808
|
-
*/
|
|
809
|
-
this.alignOffset = input(0, { ...(ngDevMode ? { debugName: "alignOffset" } : /* istanbul ignore next */ {}), transform: numberAttribute });
|
|
810
|
-
/**
|
|
811
|
-
* The padding between the arrow and the edges of the content.
|
|
812
|
-
* If your content has border-radius, this will prevent it from overflowing the corners.
|
|
813
|
-
*/
|
|
814
|
-
this.arrowPadding = input(0, { ...(ngDevMode ? { debugName: "arrowPadding" } : /* istanbul ignore next */ {}), transform: numberAttribute });
|
|
815
|
-
/**
|
|
816
|
-
* When `true`, overrides the `side` and `align` preferences to prevent collisions with boundary edges.
|
|
817
|
-
*/
|
|
818
|
-
this.avoidCollisions = input(true, { ...(ngDevMode ? { debugName: "avoidCollisions" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
819
|
-
/**
|
|
820
|
-
* The element used as the collision boundary.
|
|
821
|
-
* By default this is the viewport, though you can provide additional element(s) to be included in this check.
|
|
822
|
-
*/
|
|
823
|
-
this.collisionBoundary = input(...(ngDevMode ? [undefined, { debugName: "collisionBoundary" }] : /* istanbul ignore next */ []));
|
|
824
|
-
/**
|
|
825
|
-
* The distance in pixels from the boundary edges where collision detection should occur.
|
|
826
|
-
* Accepts a number (same for all sides), or a partial padding object, for example: `{ top: 20, left: 20 }`.
|
|
827
|
-
*/
|
|
828
|
-
this.collisionPadding = input(0, ...(ngDevMode ? [{ debugName: "collisionPadding" }] : /* istanbul ignore next */ []));
|
|
829
|
-
/**
|
|
830
|
-
* The sticky behavior on the `align` axis.
|
|
831
|
-
* - `partial` will keep the content in the boundary as long as the trigger is at least partially in the boundary
|
|
832
|
-
* - `always` will keep the content in the boundary regardless.
|
|
833
|
-
*/
|
|
834
|
-
this.sticky = input('partial', ...(ngDevMode ? [{ debugName: "sticky" }] : /* istanbul ignore next */ []));
|
|
835
|
-
/**
|
|
836
|
-
* Whether to hide the content when the trigger becomes fully occluded.
|
|
837
|
-
*/
|
|
838
|
-
this.hideWhenDetached = input(false, { ...(ngDevMode ? { debugName: "hideWhenDetached" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
839
|
-
/**
|
|
840
|
-
* Whether to update the position of the floating element on every animation frame if required.
|
|
841
|
-
*/
|
|
842
|
-
this.updatePositionStrategy = input('always', ...(ngDevMode ? [{ debugName: "updatePositionStrategy" }] : /* istanbul ignore next */ []));
|
|
843
|
-
/**
|
|
844
|
-
* Emits when the element is placed.
|
|
845
|
-
*/
|
|
846
|
-
this.placed = outputFromObservable(outputToObservable(inject(RdxPopperContentWrapper).placed));
|
|
913
|
+
super();
|
|
914
|
+
this.positionerStyle = { boxSizing: 'border-box', ...legacyPopperVars('select') };
|
|
915
|
+
const rootContext = injectSelectRootContext();
|
|
916
|
+
const injector = inject(Injector);
|
|
917
|
+
const host = inject(ElementRef).nativeElement;
|
|
918
|
+
// Modal select isolates the background with an internal backdrop (finding #1 / Base UI) instead of
|
|
919
|
+
// a global pointer lock; the trigger stays clickable through a cutout (toggle-close).
|
|
920
|
+
afterNextRender(() => setupInternalBackdrop(host, injector, {
|
|
921
|
+
isOpen: () => rootContext.open(),
|
|
922
|
+
shouldRender: () => rootContext.modal(),
|
|
923
|
+
cutout: () => rootContext.triggerElement()
|
|
924
|
+
}));
|
|
847
925
|
}
|
|
848
926
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxSelectPositioner, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
|
|
849
|
-
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
], hostDirectives: [{ directive: i1.RdxPopperContentWrapper, inputs: ["side", "side", "sideOffset", "sideOffset", "align", "align", "alignOffset", "alignOffset", "arrowPadding", "arrowPadding", "avoidCollisions", "avoidCollisions", "collisionBoundary", "collisionBoundary", "collisionPadding", "collisionPadding", "sticky", "sticky", "hideWhenDetached", "hideWhenDetached", "updatePositionStrategy", "updatePositionStrategy"] }], ngImport: i0 }); }
|
|
927
|
+
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.2.9", type: RdxSelectPositioner, isStandalone: true, selector: "[rdxSelectPositioner]", host: { properties: { "style": "positionerStyle" } }, providers: [
|
|
928
|
+
...provideRdxPopperContentWrapper(RdxSelectPositioner),
|
|
929
|
+
provideRdxPopperContentConfig({ align: 'start', updatePositionStrategy: 'always' }),
|
|
930
|
+
{ provide: RDX_SELECT_POSITIONER_TOKEN, useExisting: forwardRef(() => RdxSelectPositioner) }
|
|
931
|
+
], usesInheritance: true, ngImport: i0 }); }
|
|
855
932
|
}
|
|
856
933
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxSelectPositioner, decorators: [{
|
|
857
934
|
type: Directive,
|
|
858
935
|
args: [{
|
|
859
936
|
selector: '[rdxSelectPositioner]',
|
|
860
937
|
providers: [
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
}
|
|
865
|
-
],
|
|
866
|
-
hostDirectives: [
|
|
867
|
-
{
|
|
868
|
-
directive: RdxPopperContentWrapper,
|
|
869
|
-
inputs: [
|
|
870
|
-
'side',
|
|
871
|
-
'sideOffset',
|
|
872
|
-
'align',
|
|
873
|
-
'alignOffset',
|
|
874
|
-
'arrowPadding',
|
|
875
|
-
'avoidCollisions',
|
|
876
|
-
'collisionBoundary',
|
|
877
|
-
'collisionPadding',
|
|
878
|
-
'sticky',
|
|
879
|
-
'hideWhenDetached',
|
|
880
|
-
'updatePositionStrategy'
|
|
881
|
-
]
|
|
882
|
-
}
|
|
938
|
+
...provideRdxPopperContentWrapper(RdxSelectPositioner),
|
|
939
|
+
provideRdxPopperContentConfig({ align: 'start', updatePositionStrategy: 'always' }),
|
|
940
|
+
{ provide: RDX_SELECT_POSITIONER_TOKEN, useExisting: forwardRef(() => RdxSelectPositioner) }
|
|
883
941
|
],
|
|
884
942
|
host: {
|
|
885
|
-
//
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
'--radix-select-content-transform-origin': 'var(--radix-popper-transform-origin)',
|
|
889
|
-
'--radix-select-content-available-width': 'var(--radix-popper-available-width)',
|
|
890
|
-
'--radix-select-content-available-height': 'var(--radix-popper-available-height)',
|
|
891
|
-
'--radix-select-trigger-width': 'var(--radix-popper-anchor-width)',
|
|
892
|
-
'--radix-select-trigger-height': 'var(--radix-popper-anchor-height)',
|
|
893
|
-
}`
|
|
943
|
+
// The unified vars + placement attrs come from the wrapper (ADR 0012); only `box-sizing` and
|
|
944
|
+
// the deprecated `--radix-select-*` aliases (still consumed by demos) remain here.
|
|
945
|
+
'[style]': 'positionerStyle'
|
|
894
946
|
}
|
|
895
947
|
}]
|
|
896
|
-
}],
|
|
948
|
+
}], ctorParameters: () => [] });
|
|
897
949
|
|
|
898
950
|
/**
|
|
899
951
|
* A visual divider between groups of items.
|
|
@@ -947,18 +999,20 @@ class RdxSelectTrigger {
|
|
|
947
999
|
this.fieldRootContext?.setFilled(!this.rootContext.isEmptyModelValue());
|
|
948
1000
|
});
|
|
949
1001
|
}
|
|
950
|
-
handleOpen() {
|
|
1002
|
+
handleOpen(reason, event) {
|
|
951
1003
|
if (!this.isDisabled()) {
|
|
952
|
-
this.rootContext.onOpenChange(true);
|
|
1004
|
+
return this.rootContext.onOpenChange(true, reason, event);
|
|
953
1005
|
}
|
|
1006
|
+
return false;
|
|
954
1007
|
}
|
|
955
1008
|
handlePointerOpen(event) {
|
|
956
1009
|
const pointerEvent = event;
|
|
957
|
-
this.handleOpen()
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
1010
|
+
if (this.handleOpen('trigger-press', event)) {
|
|
1011
|
+
this.rootContext.triggerPointerDownPosRef.set({
|
|
1012
|
+
x: Math.round(pointerEvent.pageX),
|
|
1013
|
+
y: Math.round(pointerEvent.pageY)
|
|
1014
|
+
});
|
|
1015
|
+
}
|
|
962
1016
|
}
|
|
963
1017
|
onClickHandler(event) {
|
|
964
1018
|
// Whilst browsers generally have no issue focusing the trigger when clicking
|
|
@@ -996,7 +1050,8 @@ class RdxSelectTrigger {
|
|
|
996
1050
|
onKeydown(event) {
|
|
997
1051
|
const keyEvent = event;
|
|
998
1052
|
if (OPEN_KEYS.includes(keyEvent.key)) {
|
|
999
|
-
|
|
1053
|
+
const reason = keyEvent.key === 'ArrowUp' || keyEvent.key === 'ArrowDown' ? 'list-navigation' : 'trigger-press';
|
|
1054
|
+
this.handleOpen(reason, event);
|
|
1000
1055
|
event.preventDefault();
|
|
1001
1056
|
}
|
|
1002
1057
|
}
|