ng-primitives 0.82.0 → 0.84.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/avatar/avatar/avatar.d.ts +1 -2
- package/fesm2022/ng-primitives-avatar.mjs +3 -6
- package/fesm2022/ng-primitives-avatar.mjs.map +1 -1
- package/fesm2022/ng-primitives-button.mjs +2 -2
- package/fesm2022/ng-primitives-button.mjs.map +1 -1
- package/fesm2022/ng-primitives-checkbox.mjs +2 -2
- package/fesm2022/ng-primitives-checkbox.mjs.map +1 -1
- package/fesm2022/ng-primitives-combobox.mjs +5 -5
- package/fesm2022/ng-primitives-combobox.mjs.map +1 -1
- package/fesm2022/ng-primitives-file-upload.mjs +3 -4
- package/fesm2022/ng-primitives-file-upload.mjs.map +1 -1
- package/fesm2022/ng-primitives-input.mjs +2 -2
- package/fesm2022/ng-primitives-input.mjs.map +1 -1
- package/fesm2022/ng-primitives-interactions.mjs +458 -44
- package/fesm2022/ng-primitives-interactions.mjs.map +1 -1
- package/fesm2022/ng-primitives-internal.mjs +87 -427
- package/fesm2022/ng-primitives-internal.mjs.map +1 -1
- package/fesm2022/ng-primitives-listbox.mjs +4 -4
- package/fesm2022/ng-primitives-listbox.mjs.map +1 -1
- package/fesm2022/ng-primitives-select.mjs +4 -4
- package/fesm2022/ng-primitives-select.mjs.map +1 -1
- package/fesm2022/ng-primitives-slider.mjs +3 -3
- package/fesm2022/ng-primitives-slider.mjs.map +1 -1
- package/fesm2022/ng-primitives-switch.mjs +3 -3
- package/fesm2022/ng-primitives-switch.mjs.map +1 -1
- package/fesm2022/ng-primitives-tabs.mjs +4 -4
- package/fesm2022/ng-primitives-tabs.mjs.map +1 -1
- package/fesm2022/ng-primitives-textarea.mjs +2 -2
- package/fesm2022/ng-primitives-textarea.mjs.map +1 -1
- package/fesm2022/ng-primitives-tooltip.mjs +3 -2
- package/fesm2022/ng-primitives-tooltip.mjs.map +1 -1
- package/interactions/config/interactions-config.d.ts +30 -0
- package/{internal/interactions/focus.d.ts → interactions/focus/focus-interaction.d.ts} +4 -1
- package/{internal/interactions/focus-visible.d.ts → interactions/focus-visible/focus-visible-interaction.d.ts} +4 -1
- package/{internal/interactions/hover.d.ts → interactions/hover/hover-interaction.d.ts} +2 -1
- package/interactions/index.d.ts +11 -1
- package/interactions/interactions/interactions.d.ts +20 -0
- package/{internal/interactions/press.d.ts → interactions/press/press-interaction.d.ts} +4 -1
- package/internal/index.d.ts +0 -1
- package/package.json +44 -44
- package/toast/toast/toast.d.ts +1 -1
- package/interactions/setup-interactions/interaction.d.ts +0 -6
- package/interactions/setup-interactions/setup-interactions.d.ts +0 -13
- package/internal/interactions/index.d.ts +0 -4
|
@@ -1,7 +1,456 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
|
-
import { input, booleanAttribute, output, Directive,
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
2
|
+
import { InjectionToken, inject, signal, ElementRef, Renderer2, PLATFORM_ID, Injectable, effect, input, booleanAttribute, output, Directive, HostListener } from '@angular/core';
|
|
3
|
+
import { onDomRemoval, injectElementRef } from 'ng-primitives/internal';
|
|
4
|
+
import { FocusMonitor } from '@angular/cdk/a11y';
|
|
5
|
+
import { safeTakeUntilDestroyed, onBooleanChange, injectDisposables } from 'ng-primitives/utils';
|
|
6
|
+
import { DOCUMENT, isPlatformBrowser } from '@angular/common';
|
|
7
|
+
|
|
8
|
+
const defaultInteractionsConfig = {
|
|
9
|
+
disabled: false,
|
|
10
|
+
hover: true,
|
|
11
|
+
focus: true,
|
|
12
|
+
focusVisible: true,
|
|
13
|
+
press: true,
|
|
14
|
+
};
|
|
15
|
+
const NgpInteractionsConfigToken = new InjectionToken('NgpInteractionsConfigToken');
|
|
16
|
+
/**
|
|
17
|
+
* Provide the default Interactions configuration
|
|
18
|
+
* @param config The Interactions configuration
|
|
19
|
+
* @returns The provider
|
|
20
|
+
*/
|
|
21
|
+
function provideInteractionsConfig(config) {
|
|
22
|
+
return [
|
|
23
|
+
{
|
|
24
|
+
provide: NgpInteractionsConfigToken,
|
|
25
|
+
useValue: { ...defaultInteractionsConfig, ...config },
|
|
26
|
+
},
|
|
27
|
+
];
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Inject the Interactions configuration
|
|
31
|
+
* @returns The global Interactions configuration
|
|
32
|
+
*/
|
|
33
|
+
function injectInteractionsConfig() {
|
|
34
|
+
return inject(NgpInteractionsConfigToken, { optional: true }) ?? defaultInteractionsConfig;
|
|
35
|
+
}
|
|
36
|
+
function isHoverEnabled() {
|
|
37
|
+
const config = injectInteractionsConfig();
|
|
38
|
+
return !config.disabled && !!config.hover;
|
|
39
|
+
}
|
|
40
|
+
function isFocusEnabled() {
|
|
41
|
+
const config = injectInteractionsConfig();
|
|
42
|
+
return !config.disabled && !!config.focus;
|
|
43
|
+
}
|
|
44
|
+
function isFocusVisibleEnabled() {
|
|
45
|
+
const config = injectInteractionsConfig();
|
|
46
|
+
return !config.disabled && !!config.focusVisible;
|
|
47
|
+
}
|
|
48
|
+
function isPressEnabled() {
|
|
49
|
+
const config = injectInteractionsConfig();
|
|
50
|
+
return !config.disabled && !!config.press;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* @internal
|
|
55
|
+
*/
|
|
56
|
+
function ngpFocusVisibleInteraction({ focusChange, disabled = signal(false), }) {
|
|
57
|
+
const canFocusVisible = isFocusVisibleEnabled();
|
|
58
|
+
if (!canFocusVisible) {
|
|
59
|
+
return { isFocused: signal(false) };
|
|
60
|
+
}
|
|
61
|
+
const elementRef = inject(ElementRef);
|
|
62
|
+
const renderer = inject(Renderer2);
|
|
63
|
+
const focusMonitor = inject(FocusMonitor);
|
|
64
|
+
// Whether the element is currently focused.
|
|
65
|
+
const isFocused = signal(false);
|
|
66
|
+
// handle focus state
|
|
67
|
+
focusMonitor
|
|
68
|
+
.monitor(elementRef.nativeElement)
|
|
69
|
+
.pipe(safeTakeUntilDestroyed())
|
|
70
|
+
.subscribe(origin =>
|
|
71
|
+
// null indicates the element was blurred
|
|
72
|
+
origin === null ? onBlur() : onFocus(origin));
|
|
73
|
+
// if the component becomes disabled and it is focused, hide the focus
|
|
74
|
+
onBooleanChange(disabled, () => focus(false));
|
|
75
|
+
function onFocus(origin) {
|
|
76
|
+
if (disabled() || isFocused()) {
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
// for some elements the focus visible state should always appear on focus
|
|
80
|
+
if (alwaysShowFocus()) {
|
|
81
|
+
focus(true);
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
// if the focus origin is keyboard or program(focused programmatically), then the focus is visible
|
|
85
|
+
if (origin === 'keyboard') {
|
|
86
|
+
focus(true);
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
function onBlur() {
|
|
91
|
+
if (disabled() || !isFocused()) {
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
focus(false);
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Trigger the focus signal along with the focusChange event.
|
|
98
|
+
*/
|
|
99
|
+
function focus(value) {
|
|
100
|
+
if (isFocused() === value) {
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
isFocused.set(value);
|
|
104
|
+
focusChange?.(value);
|
|
105
|
+
if (value) {
|
|
106
|
+
renderer.setAttribute(elementRef.nativeElement, 'data-focus-visible', '');
|
|
107
|
+
}
|
|
108
|
+
else {
|
|
109
|
+
renderer.removeAttribute(elementRef.nativeElement, 'data-focus-visible');
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
function alwaysShowFocus() {
|
|
113
|
+
const nonTextInputTypes = [
|
|
114
|
+
'checkbox',
|
|
115
|
+
'radio',
|
|
116
|
+
'range',
|
|
117
|
+
'color',
|
|
118
|
+
'file',
|
|
119
|
+
'image',
|
|
120
|
+
'button',
|
|
121
|
+
'submit',
|
|
122
|
+
'reset',
|
|
123
|
+
];
|
|
124
|
+
// if this is an input element and it is a text input
|
|
125
|
+
if (elementRef.nativeElement instanceof HTMLInputElement &&
|
|
126
|
+
!nonTextInputTypes.includes(elementRef.nativeElement.type)) {
|
|
127
|
+
return true;
|
|
128
|
+
}
|
|
129
|
+
// if this is a textarea
|
|
130
|
+
if (elementRef.nativeElement instanceof HTMLTextAreaElement) {
|
|
131
|
+
return true;
|
|
132
|
+
}
|
|
133
|
+
// if this is an element with contenteditable
|
|
134
|
+
if (elementRef.nativeElement.isContentEditable ||
|
|
135
|
+
elementRef.nativeElement.hasAttribute('contenteditable')) {
|
|
136
|
+
return true;
|
|
137
|
+
}
|
|
138
|
+
return false;
|
|
139
|
+
}
|
|
140
|
+
return {
|
|
141
|
+
isFocused,
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* @internal
|
|
147
|
+
*/
|
|
148
|
+
function ngpFocusInteraction({ focus, blur, focusWithin = false, disabled = signal(false), }) {
|
|
149
|
+
const canFocus = isFocusEnabled();
|
|
150
|
+
if (!canFocus) {
|
|
151
|
+
return { isFocused: signal(false) };
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* Access the element reference.
|
|
155
|
+
*/
|
|
156
|
+
const elementRef = inject(ElementRef);
|
|
157
|
+
/**
|
|
158
|
+
* Access the focus monitor.
|
|
159
|
+
*/
|
|
160
|
+
const focusMonitor = inject(FocusMonitor);
|
|
161
|
+
/**
|
|
162
|
+
* Access the renderer.
|
|
163
|
+
*/
|
|
164
|
+
const renderer = inject(Renderer2);
|
|
165
|
+
/**
|
|
166
|
+
* Whether the element is currently focused.
|
|
167
|
+
*/
|
|
168
|
+
const isFocused = signal(false);
|
|
169
|
+
focusMonitor
|
|
170
|
+
.monitor(elementRef, focusWithin)
|
|
171
|
+
.pipe(safeTakeUntilDestroyed())
|
|
172
|
+
.subscribe(focusOrigin => {
|
|
173
|
+
if (disabled()) {
|
|
174
|
+
return;
|
|
175
|
+
}
|
|
176
|
+
isFocused.set(focusOrigin !== null);
|
|
177
|
+
if (focusOrigin !== null) {
|
|
178
|
+
if (focus) {
|
|
179
|
+
focus();
|
|
180
|
+
}
|
|
181
|
+
renderer.setAttribute(elementRef.nativeElement, 'data-focus', '');
|
|
182
|
+
}
|
|
183
|
+
else {
|
|
184
|
+
if (blur) {
|
|
185
|
+
blur();
|
|
186
|
+
}
|
|
187
|
+
renderer.removeAttribute(elementRef.nativeElement, 'data-focus');
|
|
188
|
+
}
|
|
189
|
+
});
|
|
190
|
+
return { isFocused };
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
/**
|
|
194
|
+
* We use a service here as this value is a singleton
|
|
195
|
+
* and allows us to register the dom events once.
|
|
196
|
+
*/
|
|
197
|
+
class GlobalPointerEvents {
|
|
198
|
+
constructor() {
|
|
199
|
+
/**
|
|
200
|
+
* Whether global mouse events should be ignored.
|
|
201
|
+
*/
|
|
202
|
+
this.ignoreEmulatedMouseEvents = false;
|
|
203
|
+
/**
|
|
204
|
+
* Access the document.
|
|
205
|
+
*/
|
|
206
|
+
this.document = inject(DOCUMENT);
|
|
207
|
+
/**
|
|
208
|
+
* Determine the platform id.
|
|
209
|
+
*/
|
|
210
|
+
this.platformId = inject(PLATFORM_ID);
|
|
211
|
+
// we only want to setup events on the client
|
|
212
|
+
if (isPlatformBrowser(this.platformId)) {
|
|
213
|
+
this.setupGlobalTouchEvents();
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
setupGlobalTouchEvents() {
|
|
217
|
+
this.document.addEventListener('pointerup', this.handleGlobalPointerEvent.bind(this));
|
|
218
|
+
this.document.addEventListener('touchend', this.setGlobalIgnoreEmulatedMouseEvents.bind(this));
|
|
219
|
+
}
|
|
220
|
+
setGlobalIgnoreEmulatedMouseEvents() {
|
|
221
|
+
this.ignoreEmulatedMouseEvents = true;
|
|
222
|
+
// Clear globalIgnoreEmulatedMouseEvents after a short timeout. iOS fires onPointerEnter
|
|
223
|
+
// with pointerType="mouse" immediately after onPointerUp and before onFocus. On other
|
|
224
|
+
// devices that don't have this quirk, we don't want to ignore a mouse hover sometime in
|
|
225
|
+
// the distant future because a user previously touched the element.
|
|
226
|
+
setTimeout(() => (this.ignoreEmulatedMouseEvents = false), 50);
|
|
227
|
+
}
|
|
228
|
+
handleGlobalPointerEvent(event) {
|
|
229
|
+
if (event.pointerType === 'touch') {
|
|
230
|
+
this.setGlobalIgnoreEmulatedMouseEvents();
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.11", ngImport: i0, type: GlobalPointerEvents, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
234
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.11", ngImport: i0, type: GlobalPointerEvents, providedIn: 'root' }); }
|
|
235
|
+
}
|
|
236
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.11", ngImport: i0, type: GlobalPointerEvents, decorators: [{
|
|
237
|
+
type: Injectable,
|
|
238
|
+
args: [{
|
|
239
|
+
providedIn: 'root',
|
|
240
|
+
}]
|
|
241
|
+
}], ctorParameters: () => [] });
|
|
242
|
+
/**
|
|
243
|
+
* Programatically add the hover functionality to an element.
|
|
244
|
+
* This is useful in cases where we can't necessarily use a HostDirective,
|
|
245
|
+
* because there is a chance the directive has already been used.
|
|
246
|
+
* @internal
|
|
247
|
+
*/
|
|
248
|
+
function ngpHoverInteraction({ hoverStart, hoverEnd, disabled = signal(false), }) {
|
|
249
|
+
const canHover = isHoverEnabled();
|
|
250
|
+
if (!canHover) {
|
|
251
|
+
return { hovered: signal(false) };
|
|
252
|
+
}
|
|
253
|
+
/**
|
|
254
|
+
* Access the element.
|
|
255
|
+
*/
|
|
256
|
+
const elementRef = inject(ElementRef);
|
|
257
|
+
/**
|
|
258
|
+
* Access the global pointer events handler.
|
|
259
|
+
*/
|
|
260
|
+
const globalPointerEvents = inject(GlobalPointerEvents);
|
|
261
|
+
/**
|
|
262
|
+
* Access the disposable helper.
|
|
263
|
+
*/
|
|
264
|
+
const disposables = injectDisposables();
|
|
265
|
+
/**
|
|
266
|
+
* Store the current hover state.
|
|
267
|
+
*/
|
|
268
|
+
const hovered = signal(false);
|
|
269
|
+
/**
|
|
270
|
+
* Whether this element should ignore emulated mouse events.
|
|
271
|
+
*/
|
|
272
|
+
let ignoreEmulatedMouseEvents = false;
|
|
273
|
+
/**
|
|
274
|
+
* Setup event listeners.
|
|
275
|
+
*/
|
|
276
|
+
disposables.addEventListener(elementRef.nativeElement, 'pointerenter', onPointerEnter);
|
|
277
|
+
disposables.addEventListener(elementRef.nativeElement, 'pointerleave', onPointerLeave);
|
|
278
|
+
disposables.addEventListener(elementRef.nativeElement, 'touchstart', onTouchStart);
|
|
279
|
+
disposables.addEventListener(elementRef.nativeElement, 'mouseenter', onMouseEnter);
|
|
280
|
+
disposables.addEventListener(elementRef.nativeElement, 'mouseleave', onMouseLeave);
|
|
281
|
+
// anytime the disabled state changes to true, we must reset the hover state
|
|
282
|
+
if (disabled) {
|
|
283
|
+
onBooleanChange(disabled, reset);
|
|
284
|
+
}
|
|
285
|
+
// if the element is removed from the dom, we want to reset the hover state
|
|
286
|
+
onDomRemoval(elementRef.nativeElement, reset);
|
|
287
|
+
// anytime the hover state changes we want to update the attribute
|
|
288
|
+
effect(() => hovered()
|
|
289
|
+
? elementRef.nativeElement.setAttribute('data-hover', '')
|
|
290
|
+
: elementRef.nativeElement.removeAttribute('data-hover'));
|
|
291
|
+
/**
|
|
292
|
+
* Reset the hover state.
|
|
293
|
+
*/
|
|
294
|
+
function reset() {
|
|
295
|
+
onHoverEnd('mouse');
|
|
296
|
+
}
|
|
297
|
+
/**
|
|
298
|
+
* Trigger the hover start events.
|
|
299
|
+
* @param event
|
|
300
|
+
* @param pointerType
|
|
301
|
+
*/
|
|
302
|
+
function onHoverStart(event, pointerType) {
|
|
303
|
+
if (disabled() ||
|
|
304
|
+
pointerType === 'touch' ||
|
|
305
|
+
hovered() ||
|
|
306
|
+
!event.currentTarget?.contains(event.target)) {
|
|
307
|
+
return;
|
|
308
|
+
}
|
|
309
|
+
hovered.set(true);
|
|
310
|
+
hoverStart?.();
|
|
311
|
+
}
|
|
312
|
+
/**
|
|
313
|
+
* Trigger the hover end events.
|
|
314
|
+
* @param pointerType
|
|
315
|
+
*/
|
|
316
|
+
function onHoverEnd(pointerType) {
|
|
317
|
+
if (pointerType === 'touch' || !hovered()) {
|
|
318
|
+
return;
|
|
319
|
+
}
|
|
320
|
+
hovered.set(false);
|
|
321
|
+
hoverEnd?.();
|
|
322
|
+
}
|
|
323
|
+
function onPointerEnter(event) {
|
|
324
|
+
if (globalPointerEvents.ignoreEmulatedMouseEvents && event.pointerType === 'mouse') {
|
|
325
|
+
return;
|
|
326
|
+
}
|
|
327
|
+
onHoverStart(event, event.pointerType);
|
|
328
|
+
}
|
|
329
|
+
function onPointerLeave(event) {
|
|
330
|
+
if (!disabled() && event.currentTarget?.contains(event.target)) {
|
|
331
|
+
onHoverEnd(event.pointerType);
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
function onTouchStart() {
|
|
335
|
+
ignoreEmulatedMouseEvents = true;
|
|
336
|
+
}
|
|
337
|
+
function onMouseEnter(event) {
|
|
338
|
+
if (!ignoreEmulatedMouseEvents && !globalPointerEvents.ignoreEmulatedMouseEvents) {
|
|
339
|
+
onHoverStart(event, 'mouse');
|
|
340
|
+
}
|
|
341
|
+
ignoreEmulatedMouseEvents = false;
|
|
342
|
+
}
|
|
343
|
+
function onMouseLeave(event) {
|
|
344
|
+
if (!disabled() && event.currentTarget?.contains(event.target)) {
|
|
345
|
+
onHoverEnd('mouse');
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
return { hovered };
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
/**
|
|
352
|
+
* @internal
|
|
353
|
+
*/
|
|
354
|
+
function ngpPressInteraction({ pressStart, pressEnd, disabled = signal(false), }) {
|
|
355
|
+
const canPress = isPressEnabled();
|
|
356
|
+
if (!canPress) {
|
|
357
|
+
return { pressed: signal(false) };
|
|
358
|
+
}
|
|
359
|
+
const elementRef = inject(ElementRef);
|
|
360
|
+
const disposables = injectDisposables();
|
|
361
|
+
/**
|
|
362
|
+
* Whether the element is currently pressed.
|
|
363
|
+
*/
|
|
364
|
+
const pressed = signal(false);
|
|
365
|
+
// setup event listeners
|
|
366
|
+
disposables.addEventListener(elementRef.nativeElement, 'pointerdown', onPointerDown);
|
|
367
|
+
// anytime the press state changes we want to update the attribute
|
|
368
|
+
effect(() => pressed() && !disabled()
|
|
369
|
+
? elementRef.nativeElement.setAttribute('data-press', '')
|
|
370
|
+
: elementRef.nativeElement.removeAttribute('data-press'));
|
|
371
|
+
/**
|
|
372
|
+
* Reset the press state.
|
|
373
|
+
*/
|
|
374
|
+
function reset() {
|
|
375
|
+
// if we are not pressing, then do nothing
|
|
376
|
+
if (!pressed()) {
|
|
377
|
+
return;
|
|
378
|
+
}
|
|
379
|
+
// clear any existing disposables
|
|
380
|
+
disposableListeners.forEach(dispose => dispose());
|
|
381
|
+
pressed.set(false);
|
|
382
|
+
pressEnd?.();
|
|
383
|
+
}
|
|
384
|
+
/**
|
|
385
|
+
* Store the list of disposables.
|
|
386
|
+
*/
|
|
387
|
+
let disposableListeners = [];
|
|
388
|
+
function onPointerDown() {
|
|
389
|
+
if (disabled()) {
|
|
390
|
+
return;
|
|
391
|
+
}
|
|
392
|
+
// clear any existing disposables
|
|
393
|
+
disposableListeners.forEach(dispose => dispose());
|
|
394
|
+
// update the press state
|
|
395
|
+
pressed.set(true);
|
|
396
|
+
pressStart?.();
|
|
397
|
+
// setup global event listeners to catch events on elements outside the directive
|
|
398
|
+
const ownerDocument = elementRef.nativeElement.ownerDocument ?? document;
|
|
399
|
+
// if the pointer up event happens on any elements, then we are no longer pressing on this element
|
|
400
|
+
const pointerUp = disposables.addEventListener(ownerDocument, 'pointerup', () => reset(), false);
|
|
401
|
+
// Instead of relying on the `pointerleave` event, which is not consistently called on iOS Safari,
|
|
402
|
+
// we use the `pointermove` event to determine if we are still "pressing".
|
|
403
|
+
// By checking if the target is still within the element, we can determine if the press is ongoing.
|
|
404
|
+
const pointerMove = disposables.addEventListener(ownerDocument, 'pointermove', () => onPointerMove, false);
|
|
405
|
+
// if the pointer is cancelled, then we are no longer pressing on this element
|
|
406
|
+
const pointerCancel = disposables.addEventListener(ownerDocument, 'pointercancel', () => reset(), false);
|
|
407
|
+
disposableListeners = [pointerUp, pointerMove, pointerCancel];
|
|
408
|
+
}
|
|
409
|
+
function onPointerMove(event) {
|
|
410
|
+
if (elementRef.nativeElement !== event.target &&
|
|
411
|
+
!elementRef.nativeElement.contains(event.target)) {
|
|
412
|
+
reset();
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
return { pressed };
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
/**
|
|
419
|
+
* Setup the interactions without relying on HostDirectives.
|
|
420
|
+
* @internal
|
|
421
|
+
*/
|
|
422
|
+
function ngpInteractions({ focus, hover, press, focusWithin, focusVisible, disabled = signal(false), }) {
|
|
423
|
+
const elementRef = injectElementRef();
|
|
424
|
+
// If the interaction has already been setup, we can skip the setup.
|
|
425
|
+
if (hasInteraction(elementRef.nativeElement, 'interactions')) {
|
|
426
|
+
return;
|
|
427
|
+
}
|
|
428
|
+
if (hover) {
|
|
429
|
+
ngpHoverInteraction({ disabled });
|
|
430
|
+
}
|
|
431
|
+
if (press) {
|
|
432
|
+
ngpPressInteraction({ disabled });
|
|
433
|
+
}
|
|
434
|
+
if (focus) {
|
|
435
|
+
ngpFocusInteraction({ focusWithin, disabled });
|
|
436
|
+
}
|
|
437
|
+
if (focusVisible) {
|
|
438
|
+
ngpFocusVisibleInteraction({ disabled });
|
|
439
|
+
}
|
|
440
|
+
}
|
|
441
|
+
/**
|
|
442
|
+
* This function checks to see if a given interaction has already been setup on a given element.
|
|
443
|
+
* If it has, it returns the existing interaction state.
|
|
444
|
+
* If it has not, it sets up the interaction state for future checks.
|
|
445
|
+
*/
|
|
446
|
+
function hasInteraction(element, interaction) {
|
|
447
|
+
const hasInteraction = `__ngp-${interaction}` in element;
|
|
448
|
+
// if the interaction has not been setup, we mark it as setup for future checks
|
|
449
|
+
if (!hasInteraction) {
|
|
450
|
+
element[`__ngp-${interaction}`] = true;
|
|
451
|
+
}
|
|
452
|
+
return hasInteraction;
|
|
453
|
+
}
|
|
5
454
|
|
|
6
455
|
/**
|
|
7
456
|
* Apply the `ngpFocusVisible` directive to an element that should be visually focused. This is similar to `ngpFocus`
|
|
@@ -23,7 +472,7 @@ class NgpFocusVisible {
|
|
|
23
472
|
alias: 'ngpFocusVisible',
|
|
24
473
|
});
|
|
25
474
|
// setup the focus visible listener
|
|
26
|
-
|
|
475
|
+
ngpFocusVisibleInteraction({
|
|
27
476
|
disabled: this.disabled,
|
|
28
477
|
focusChange: value => this.focusChange.emit(value),
|
|
29
478
|
});
|
|
@@ -57,7 +506,7 @@ class NgpFocus {
|
|
|
57
506
|
*/
|
|
58
507
|
this.focus = output({ alias: 'ngpFocus' });
|
|
59
508
|
// setup the focus listener
|
|
60
|
-
|
|
509
|
+
ngpFocusInteraction({
|
|
61
510
|
disabled: this.disabled,
|
|
62
511
|
focus: () => this.focus.emit(true),
|
|
63
512
|
blur: () => this.focus.emit(false),
|
|
@@ -105,7 +554,7 @@ class NgpHover {
|
|
|
105
554
|
*/
|
|
106
555
|
this.hoverChange = output({ alias: 'ngpHover' });
|
|
107
556
|
// setup the hover listener
|
|
108
|
-
|
|
557
|
+
ngpHoverInteraction({
|
|
109
558
|
hoverStart: () => {
|
|
110
559
|
this.hoverStart.emit();
|
|
111
560
|
this.hoverChange.emit(true);
|
|
@@ -365,7 +814,7 @@ class NgpPress {
|
|
|
365
814
|
alias: 'ngpPress',
|
|
366
815
|
});
|
|
367
816
|
// setup the press listener
|
|
368
|
-
|
|
817
|
+
ngpPressInteraction({
|
|
369
818
|
pressStart: () => {
|
|
370
819
|
this.pressStart.emit();
|
|
371
820
|
this.pressChange.emit(true);
|
|
@@ -388,46 +837,11 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.11", ngImpo
|
|
|
388
837
|
}]
|
|
389
838
|
}], ctorParameters: () => [] });
|
|
390
839
|
|
|
391
|
-
|
|
392
|
-
* This function checks to see if a given interaction has already been setup on a given element.
|
|
393
|
-
* If it has, it returns the existing interaction state.
|
|
394
|
-
* If it has not, it sets up the interaction state for future checks.
|
|
395
|
-
*/
|
|
396
|
-
function hasInteraction(element, interaction) {
|
|
397
|
-
const hasInteraction = `__ngp-${interaction}` in element;
|
|
398
|
-
// if the interaction has not been setup, we mark it as setup for future checks
|
|
399
|
-
if (!hasInteraction) {
|
|
400
|
-
element[`__ngp-${interaction}`] = true;
|
|
401
|
-
}
|
|
402
|
-
return hasInteraction;
|
|
403
|
-
}
|
|
404
|
-
|
|
405
|
-
/**
|
|
406
|
-
* Setup the interactions without relying on HostDirectives.
|
|
407
|
-
*/
|
|
408
|
-
function setupInteractions({ focus, hover, press, focusWithin, focusVisible, disabled = signal(false), }) {
|
|
409
|
-
const elementRef = injectElementRef();
|
|
410
|
-
// If the interaction has already been setup, we can skip the setup.
|
|
411
|
-
if (hasInteraction(elementRef.nativeElement, 'interactions')) {
|
|
412
|
-
return;
|
|
413
|
-
}
|
|
414
|
-
if (hover) {
|
|
415
|
-
setupHover({ disabled });
|
|
416
|
-
}
|
|
417
|
-
if (press) {
|
|
418
|
-
setupPress({ disabled });
|
|
419
|
-
}
|
|
420
|
-
if (focus) {
|
|
421
|
-
setupFocus({ focusWithin, disabled });
|
|
422
|
-
}
|
|
423
|
-
if (focusVisible) {
|
|
424
|
-
setupFocusVisible({ disabled });
|
|
425
|
-
}
|
|
426
|
-
}
|
|
840
|
+
// re-export ngpInteractions as setupInteractions for backwards compatibility
|
|
427
841
|
|
|
428
842
|
/**
|
|
429
843
|
* Generated bundle index. Do not edit.
|
|
430
844
|
*/
|
|
431
845
|
|
|
432
|
-
export { NgpFocus, NgpFocusVisible, NgpHover, NgpMove, NgpPress, setupInteractions };
|
|
846
|
+
export { NgpFocus, NgpFocusVisible, NgpHover, NgpMove, NgpPress, ngpFocusInteraction, ngpFocusVisibleInteraction, ngpHoverInteraction, ngpInteractions, ngpPressInteraction, provideInteractionsConfig, ngpInteractions as setupInteractions };
|
|
433
847
|
//# sourceMappingURL=ng-primitives-interactions.mjs.map
|