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,8 +1,7 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
|
-
import { inject, ElementRef, Injectable, Directive,
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import { isPlatformServer, DOCUMENT, isPlatformBrowser } from '@angular/common';
|
|
2
|
+
import { inject, ElementRef, Injectable, Directive, effect, untracked, CSP_NONCE, PLATFORM_ID, signal, Injector, DestroyRef } from '@angular/core';
|
|
3
|
+
import { DOCUMENT, isPlatformBrowser, isPlatformServer } from '@angular/common';
|
|
4
|
+
import { isUndefined, safeTakeUntilDestroyed } from 'ng-primitives/utils';
|
|
6
5
|
import { Observable, merge } from 'rxjs';
|
|
7
6
|
import { map } from 'rxjs/operators';
|
|
8
7
|
|
|
@@ -117,132 +116,6 @@ function setupExitAnimation({ element }) {
|
|
|
117
116
|
};
|
|
118
117
|
}
|
|
119
118
|
|
|
120
|
-
function setupFocus({ focus, blur, focusWithin = false, disabled = signal(false), }) {
|
|
121
|
-
/**
|
|
122
|
-
* Access the element reference.
|
|
123
|
-
*/
|
|
124
|
-
const elementRef = inject(ElementRef);
|
|
125
|
-
/**
|
|
126
|
-
* Access the focus monitor.
|
|
127
|
-
*/
|
|
128
|
-
const focusMonitor = inject(FocusMonitor);
|
|
129
|
-
/**
|
|
130
|
-
* Access the renderer.
|
|
131
|
-
*/
|
|
132
|
-
const renderer = inject(Renderer2);
|
|
133
|
-
/**
|
|
134
|
-
* Whether the element is currently focused.
|
|
135
|
-
*/
|
|
136
|
-
const isFocused = signal(false);
|
|
137
|
-
focusMonitor
|
|
138
|
-
.monitor(elementRef, focusWithin)
|
|
139
|
-
.pipe(safeTakeUntilDestroyed())
|
|
140
|
-
.subscribe(focusOrigin => {
|
|
141
|
-
if (disabled()) {
|
|
142
|
-
return;
|
|
143
|
-
}
|
|
144
|
-
isFocused.set(focusOrigin !== null);
|
|
145
|
-
if (focusOrigin !== null) {
|
|
146
|
-
if (focus) {
|
|
147
|
-
focus();
|
|
148
|
-
}
|
|
149
|
-
renderer.setAttribute(elementRef.nativeElement, 'data-focus', '');
|
|
150
|
-
}
|
|
151
|
-
else {
|
|
152
|
-
if (blur) {
|
|
153
|
-
blur();
|
|
154
|
-
}
|
|
155
|
-
renderer.removeAttribute(elementRef.nativeElement, 'data-focus');
|
|
156
|
-
}
|
|
157
|
-
});
|
|
158
|
-
return { isFocused };
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
function setupFocusVisible({ focusChange, disabled = signal(false), }) {
|
|
162
|
-
const elementRef = inject(ElementRef);
|
|
163
|
-
const renderer = inject(Renderer2);
|
|
164
|
-
const focusMonitor = inject(FocusMonitor);
|
|
165
|
-
// Whether the element is currently focused.
|
|
166
|
-
const isFocused = signal(false);
|
|
167
|
-
// handle focus state
|
|
168
|
-
focusMonitor
|
|
169
|
-
.monitor(elementRef.nativeElement)
|
|
170
|
-
.pipe(safeTakeUntilDestroyed())
|
|
171
|
-
.subscribe(origin =>
|
|
172
|
-
// null indicates the element was blurred
|
|
173
|
-
origin === null ? onBlur() : onFocus(origin));
|
|
174
|
-
// if the component becomes disabled and it is focused, hide the focus
|
|
175
|
-
onBooleanChange(disabled, () => focus(false));
|
|
176
|
-
function onFocus(origin) {
|
|
177
|
-
if (disabled() || isFocused()) {
|
|
178
|
-
return;
|
|
179
|
-
}
|
|
180
|
-
// for some elements the focus visible state should always appear on focus
|
|
181
|
-
if (alwaysShowFocus()) {
|
|
182
|
-
focus(true);
|
|
183
|
-
return;
|
|
184
|
-
}
|
|
185
|
-
// if the focus origin is keyboard or program(focused programmatically), then the focus is visible
|
|
186
|
-
if (origin === 'keyboard') {
|
|
187
|
-
focus(true);
|
|
188
|
-
return;
|
|
189
|
-
}
|
|
190
|
-
}
|
|
191
|
-
function onBlur() {
|
|
192
|
-
if (disabled() || !isFocused()) {
|
|
193
|
-
return;
|
|
194
|
-
}
|
|
195
|
-
focus(false);
|
|
196
|
-
}
|
|
197
|
-
/**
|
|
198
|
-
* Trigger the focus signal along with the focusChange event.
|
|
199
|
-
*/
|
|
200
|
-
function focus(value) {
|
|
201
|
-
if (isFocused() === value) {
|
|
202
|
-
return;
|
|
203
|
-
}
|
|
204
|
-
isFocused.set(value);
|
|
205
|
-
focusChange?.(value);
|
|
206
|
-
if (value) {
|
|
207
|
-
renderer.setAttribute(elementRef.nativeElement, 'data-focus-visible', '');
|
|
208
|
-
}
|
|
209
|
-
else {
|
|
210
|
-
renderer.removeAttribute(elementRef.nativeElement, 'data-focus-visible');
|
|
211
|
-
}
|
|
212
|
-
}
|
|
213
|
-
function alwaysShowFocus() {
|
|
214
|
-
const nonTextInputTypes = [
|
|
215
|
-
'checkbox',
|
|
216
|
-
'radio',
|
|
217
|
-
'range',
|
|
218
|
-
'color',
|
|
219
|
-
'file',
|
|
220
|
-
'image',
|
|
221
|
-
'button',
|
|
222
|
-
'submit',
|
|
223
|
-
'reset',
|
|
224
|
-
];
|
|
225
|
-
// if this is an input element and it is a text input
|
|
226
|
-
if (elementRef.nativeElement instanceof HTMLInputElement &&
|
|
227
|
-
!nonTextInputTypes.includes(elementRef.nativeElement.type)) {
|
|
228
|
-
return true;
|
|
229
|
-
}
|
|
230
|
-
// if this is a textarea
|
|
231
|
-
if (elementRef.nativeElement instanceof HTMLTextAreaElement) {
|
|
232
|
-
return true;
|
|
233
|
-
}
|
|
234
|
-
// if this is an element with contenteditable
|
|
235
|
-
if (elementRef.nativeElement.isContentEditable ||
|
|
236
|
-
elementRef.nativeElement.hasAttribute('contenteditable')) {
|
|
237
|
-
return true;
|
|
238
|
-
}
|
|
239
|
-
return false;
|
|
240
|
-
}
|
|
241
|
-
return {
|
|
242
|
-
isFocused,
|
|
243
|
-
};
|
|
244
|
-
}
|
|
245
|
-
|
|
246
119
|
/**
|
|
247
120
|
* This implementation is heavily inspired by the great work on ngextension!
|
|
248
121
|
* https://github.com/ngxtension/ngxtension-platform/blob/main/libs/ngxtension/explicit-effect/src/explicit-effect.ts
|
|
@@ -260,6 +133,89 @@ function explicitEffect(deps, fn, options) {
|
|
|
260
133
|
}, options);
|
|
261
134
|
}
|
|
262
135
|
|
|
136
|
+
/**
|
|
137
|
+
* A utility service for injecting styles into the document.
|
|
138
|
+
* Angular doesn't allow directives to specify styles, only components.
|
|
139
|
+
* As we ship directives, occasionally we need to associate styles with them.
|
|
140
|
+
* This service allows us to programmatically inject styles into the document.
|
|
141
|
+
*/
|
|
142
|
+
class StyleInjector {
|
|
143
|
+
constructor() {
|
|
144
|
+
/**
|
|
145
|
+
* Access the CSP nonce
|
|
146
|
+
*/
|
|
147
|
+
this.cspNonce = inject(CSP_NONCE, { optional: true });
|
|
148
|
+
/**
|
|
149
|
+
* Access the document.
|
|
150
|
+
*/
|
|
151
|
+
this.document = inject(DOCUMENT);
|
|
152
|
+
/**
|
|
153
|
+
* Detect the platform.
|
|
154
|
+
*/
|
|
155
|
+
this.platformId = inject(PLATFORM_ID);
|
|
156
|
+
/**
|
|
157
|
+
* Store the map of style elements with their unique identifiers.
|
|
158
|
+
*/
|
|
159
|
+
this.styleElements = new Map();
|
|
160
|
+
if (isPlatformBrowser(this.platformId)) {
|
|
161
|
+
this.collectServerStyles();
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* Inject a style into the document.
|
|
166
|
+
* @param id The unique identifier for the style.
|
|
167
|
+
* @param style The style to inject.
|
|
168
|
+
*/
|
|
169
|
+
add(id, style) {
|
|
170
|
+
if (this.styleElements.has(id)) {
|
|
171
|
+
return;
|
|
172
|
+
}
|
|
173
|
+
const styleElement = this.document.createElement('style');
|
|
174
|
+
styleElement.setAttribute('data-ngp-style', id);
|
|
175
|
+
styleElement.textContent = style;
|
|
176
|
+
// If a CSP nonce is provided, set it on the style element
|
|
177
|
+
if (this.cspNonce) {
|
|
178
|
+
styleElement.setAttribute('nonce', this.cspNonce);
|
|
179
|
+
}
|
|
180
|
+
this.document.head.appendChild(styleElement);
|
|
181
|
+
this.styleElements.set(id, styleElement);
|
|
182
|
+
}
|
|
183
|
+
/**
|
|
184
|
+
* Remove a style from the document.
|
|
185
|
+
* @param id The unique identifier for the style.
|
|
186
|
+
*/
|
|
187
|
+
remove(id) {
|
|
188
|
+
const styleElement = this.styleElements.get(id);
|
|
189
|
+
if (styleElement) {
|
|
190
|
+
this.document.head.removeChild(styleElement);
|
|
191
|
+
this.styleElements.delete(id);
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
/**
|
|
195
|
+
* Collect any styles that were rendered by the server.
|
|
196
|
+
*/
|
|
197
|
+
collectServerStyles() {
|
|
198
|
+
const styleElements = this.document.querySelectorAll('style[data-ngp-style]');
|
|
199
|
+
styleElements.forEach(styleElement => {
|
|
200
|
+
const id = styleElement.getAttribute('data-ngp-style');
|
|
201
|
+
if (id) {
|
|
202
|
+
this.styleElements.set(id, styleElement);
|
|
203
|
+
}
|
|
204
|
+
});
|
|
205
|
+
}
|
|
206
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.11", ngImport: i0, type: StyleInjector, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
207
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.11", ngImport: i0, type: StyleInjector, providedIn: 'root' }); }
|
|
208
|
+
}
|
|
209
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.11", ngImport: i0, type: StyleInjector, decorators: [{
|
|
210
|
+
type: Injectable,
|
|
211
|
+
args: [{
|
|
212
|
+
providedIn: 'root',
|
|
213
|
+
}]
|
|
214
|
+
}], ctorParameters: () => [] });
|
|
215
|
+
function injectStyleInjector() {
|
|
216
|
+
return inject(StyleInjector);
|
|
217
|
+
}
|
|
218
|
+
|
|
263
219
|
/**
|
|
264
220
|
* A simple helper function to create a resize observer as an RxJS Observable.
|
|
265
221
|
* @param element The element to observe for resize events.
|
|
@@ -373,302 +329,6 @@ function onDomRemoval(element, callback) {
|
|
|
373
329
|
});
|
|
374
330
|
}
|
|
375
331
|
|
|
376
|
-
/**
|
|
377
|
-
* We use a service here as this value is a singleton
|
|
378
|
-
* and allows us to register the dom events once.
|
|
379
|
-
*/
|
|
380
|
-
class GlobalPointerEvents {
|
|
381
|
-
constructor() {
|
|
382
|
-
/**
|
|
383
|
-
* Whether global mouse events should be ignored.
|
|
384
|
-
*/
|
|
385
|
-
this.ignoreEmulatedMouseEvents = false;
|
|
386
|
-
/**
|
|
387
|
-
* Access the document.
|
|
388
|
-
*/
|
|
389
|
-
this.document = inject(DOCUMENT);
|
|
390
|
-
/**
|
|
391
|
-
* Determine the platform id.
|
|
392
|
-
*/
|
|
393
|
-
this.platformId = inject(PLATFORM_ID);
|
|
394
|
-
// we only want to setup events on the client
|
|
395
|
-
if (isPlatformBrowser(this.platformId)) {
|
|
396
|
-
this.setupGlobalTouchEvents();
|
|
397
|
-
}
|
|
398
|
-
}
|
|
399
|
-
setupGlobalTouchEvents() {
|
|
400
|
-
this.document.addEventListener('pointerup', this.handleGlobalPointerEvent.bind(this));
|
|
401
|
-
this.document.addEventListener('touchend', this.setGlobalIgnoreEmulatedMouseEvents.bind(this));
|
|
402
|
-
}
|
|
403
|
-
setGlobalIgnoreEmulatedMouseEvents() {
|
|
404
|
-
this.ignoreEmulatedMouseEvents = true;
|
|
405
|
-
// Clear globalIgnoreEmulatedMouseEvents after a short timeout. iOS fires onPointerEnter
|
|
406
|
-
// with pointerType="mouse" immediately after onPointerUp and before onFocus. On other
|
|
407
|
-
// devices that don't have this quirk, we don't want to ignore a mouse hover sometime in
|
|
408
|
-
// the distant future because a user previously touched the element.
|
|
409
|
-
setTimeout(() => (this.ignoreEmulatedMouseEvents = false), 50);
|
|
410
|
-
}
|
|
411
|
-
handleGlobalPointerEvent(event) {
|
|
412
|
-
if (event.pointerType === 'touch') {
|
|
413
|
-
this.setGlobalIgnoreEmulatedMouseEvents();
|
|
414
|
-
}
|
|
415
|
-
}
|
|
416
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.11", ngImport: i0, type: GlobalPointerEvents, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
417
|
-
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.11", ngImport: i0, type: GlobalPointerEvents, providedIn: 'root' }); }
|
|
418
|
-
}
|
|
419
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.11", ngImport: i0, type: GlobalPointerEvents, decorators: [{
|
|
420
|
-
type: Injectable,
|
|
421
|
-
args: [{
|
|
422
|
-
providedIn: 'root',
|
|
423
|
-
}]
|
|
424
|
-
}], ctorParameters: () => [] });
|
|
425
|
-
/**
|
|
426
|
-
* Programatically add the hover functionality to an element.
|
|
427
|
-
* This is useful in cases where we can't necessarily use a HostDirective,
|
|
428
|
-
* because there is a chance the directive has already been used.
|
|
429
|
-
*/
|
|
430
|
-
function setupHover({ hoverStart, hoverEnd, disabled = signal(false), }) {
|
|
431
|
-
/**
|
|
432
|
-
* Access the element.
|
|
433
|
-
*/
|
|
434
|
-
const elementRef = inject(ElementRef);
|
|
435
|
-
/**
|
|
436
|
-
* Access the global pointer events handler.
|
|
437
|
-
*/
|
|
438
|
-
const globalPointerEvents = inject(GlobalPointerEvents);
|
|
439
|
-
/**
|
|
440
|
-
* Access the disposable helper.
|
|
441
|
-
*/
|
|
442
|
-
const disposables = injectDisposables();
|
|
443
|
-
/**
|
|
444
|
-
* Store the current hover state.
|
|
445
|
-
*/
|
|
446
|
-
const hovered = signal(false);
|
|
447
|
-
/**
|
|
448
|
-
* Whether this element should ignore emulated mouse events.
|
|
449
|
-
*/
|
|
450
|
-
let ignoreEmulatedMouseEvents = false;
|
|
451
|
-
/**
|
|
452
|
-
* Setup event listeners.
|
|
453
|
-
*/
|
|
454
|
-
disposables.addEventListener(elementRef.nativeElement, 'pointerenter', onPointerEnter);
|
|
455
|
-
disposables.addEventListener(elementRef.nativeElement, 'pointerleave', onPointerLeave);
|
|
456
|
-
disposables.addEventListener(elementRef.nativeElement, 'touchstart', onTouchStart);
|
|
457
|
-
disposables.addEventListener(elementRef.nativeElement, 'mouseenter', onMouseEnter);
|
|
458
|
-
disposables.addEventListener(elementRef.nativeElement, 'mouseleave', onMouseLeave);
|
|
459
|
-
// anytime the disabled state changes to true, we must reset the hover state
|
|
460
|
-
if (disabled) {
|
|
461
|
-
onBooleanChange(disabled, reset);
|
|
462
|
-
}
|
|
463
|
-
// if the element is removed from the dom, we want to reset the hover state
|
|
464
|
-
onDomRemoval(elementRef.nativeElement, reset);
|
|
465
|
-
// anytime the hover state changes we want to update the attribute
|
|
466
|
-
effect(() => hovered()
|
|
467
|
-
? elementRef.nativeElement.setAttribute('data-hover', '')
|
|
468
|
-
: elementRef.nativeElement.removeAttribute('data-hover'));
|
|
469
|
-
/**
|
|
470
|
-
* Reset the hover state.
|
|
471
|
-
*/
|
|
472
|
-
function reset() {
|
|
473
|
-
onHoverEnd('mouse');
|
|
474
|
-
}
|
|
475
|
-
/**
|
|
476
|
-
* Trigger the hover start events.
|
|
477
|
-
* @param event
|
|
478
|
-
* @param pointerType
|
|
479
|
-
*/
|
|
480
|
-
function onHoverStart(event, pointerType) {
|
|
481
|
-
if (disabled() ||
|
|
482
|
-
pointerType === 'touch' ||
|
|
483
|
-
hovered() ||
|
|
484
|
-
!event.currentTarget?.contains(event.target)) {
|
|
485
|
-
return;
|
|
486
|
-
}
|
|
487
|
-
hovered.set(true);
|
|
488
|
-
hoverStart?.();
|
|
489
|
-
}
|
|
490
|
-
/**
|
|
491
|
-
* Trigger the hover end events.
|
|
492
|
-
* @param pointerType
|
|
493
|
-
*/
|
|
494
|
-
function onHoverEnd(pointerType) {
|
|
495
|
-
if (pointerType === 'touch' || !hovered()) {
|
|
496
|
-
return;
|
|
497
|
-
}
|
|
498
|
-
hovered.set(false);
|
|
499
|
-
hoverEnd?.();
|
|
500
|
-
}
|
|
501
|
-
function onPointerEnter(event) {
|
|
502
|
-
if (globalPointerEvents.ignoreEmulatedMouseEvents && event.pointerType === 'mouse') {
|
|
503
|
-
return;
|
|
504
|
-
}
|
|
505
|
-
onHoverStart(event, event.pointerType);
|
|
506
|
-
}
|
|
507
|
-
function onPointerLeave(event) {
|
|
508
|
-
if (!disabled() && event.currentTarget?.contains(event.target)) {
|
|
509
|
-
onHoverEnd(event.pointerType);
|
|
510
|
-
}
|
|
511
|
-
}
|
|
512
|
-
function onTouchStart() {
|
|
513
|
-
ignoreEmulatedMouseEvents = true;
|
|
514
|
-
}
|
|
515
|
-
function onMouseEnter(event) {
|
|
516
|
-
if (!ignoreEmulatedMouseEvents && !globalPointerEvents.ignoreEmulatedMouseEvents) {
|
|
517
|
-
onHoverStart(event, 'mouse');
|
|
518
|
-
}
|
|
519
|
-
ignoreEmulatedMouseEvents = false;
|
|
520
|
-
}
|
|
521
|
-
function onMouseLeave(event) {
|
|
522
|
-
if (!disabled() && event.currentTarget?.contains(event.target)) {
|
|
523
|
-
onHoverEnd('mouse');
|
|
524
|
-
}
|
|
525
|
-
}
|
|
526
|
-
return { hovered };
|
|
527
|
-
}
|
|
528
|
-
|
|
529
|
-
function setupPress({ pressStart, pressEnd, disabled = signal(false), }) {
|
|
530
|
-
const elementRef = inject(ElementRef);
|
|
531
|
-
const disposables = injectDisposables();
|
|
532
|
-
/**
|
|
533
|
-
* Whether the element is currently pressed.
|
|
534
|
-
*/
|
|
535
|
-
const pressed = signal(false);
|
|
536
|
-
// setup event listeners
|
|
537
|
-
disposables.addEventListener(elementRef.nativeElement, 'pointerdown', onPointerDown);
|
|
538
|
-
// anytime the press state changes we want to update the attribute
|
|
539
|
-
effect(() => pressed() && !disabled()
|
|
540
|
-
? elementRef.nativeElement.setAttribute('data-press', '')
|
|
541
|
-
: elementRef.nativeElement.removeAttribute('data-press'));
|
|
542
|
-
/**
|
|
543
|
-
* Reset the press state.
|
|
544
|
-
*/
|
|
545
|
-
function reset() {
|
|
546
|
-
// if we are not pressing, then do nothing
|
|
547
|
-
if (!pressed()) {
|
|
548
|
-
return;
|
|
549
|
-
}
|
|
550
|
-
// clear any existing disposables
|
|
551
|
-
disposableListeners.forEach(dispose => dispose());
|
|
552
|
-
pressed.set(false);
|
|
553
|
-
pressEnd?.();
|
|
554
|
-
}
|
|
555
|
-
/**
|
|
556
|
-
* Store the list of disposables.
|
|
557
|
-
*/
|
|
558
|
-
let disposableListeners = [];
|
|
559
|
-
function onPointerDown() {
|
|
560
|
-
if (disabled()) {
|
|
561
|
-
return;
|
|
562
|
-
}
|
|
563
|
-
// clear any existing disposables
|
|
564
|
-
disposableListeners.forEach(dispose => dispose());
|
|
565
|
-
// update the press state
|
|
566
|
-
pressed.set(true);
|
|
567
|
-
pressStart?.();
|
|
568
|
-
// setup global event listeners to catch events on elements outside the directive
|
|
569
|
-
const ownerDocument = elementRef.nativeElement.ownerDocument ?? document;
|
|
570
|
-
// if the pointer up event happens on any elements, then we are no longer pressing on this element
|
|
571
|
-
const pointerUp = disposables.addEventListener(ownerDocument, 'pointerup', () => reset(), false);
|
|
572
|
-
// Instead of relying on the `pointerleave` event, which is not consistently called on iOS Safari,
|
|
573
|
-
// we use the `pointermove` event to determine if we are still "pressing".
|
|
574
|
-
// By checking if the target is still within the element, we can determine if the press is ongoing.
|
|
575
|
-
const pointerMove = disposables.addEventListener(ownerDocument, 'pointermove', () => onPointerMove, false);
|
|
576
|
-
// if the pointer is cancelled, then we are no longer pressing on this element
|
|
577
|
-
const pointerCancel = disposables.addEventListener(ownerDocument, 'pointercancel', () => reset(), false);
|
|
578
|
-
disposableListeners = [pointerUp, pointerMove, pointerCancel];
|
|
579
|
-
}
|
|
580
|
-
function onPointerMove(event) {
|
|
581
|
-
if (elementRef.nativeElement !== event.target &&
|
|
582
|
-
!elementRef.nativeElement.contains(event.target)) {
|
|
583
|
-
reset();
|
|
584
|
-
}
|
|
585
|
-
}
|
|
586
|
-
return { pressed };
|
|
587
|
-
}
|
|
588
|
-
|
|
589
|
-
/**
|
|
590
|
-
* A utility service for injecting styles into the document.
|
|
591
|
-
* Angular doesn't allow directives to specify styles, only components.
|
|
592
|
-
* As we ship directives, occasionally we need to associate styles with them.
|
|
593
|
-
* This service allows us to programmatically inject styles into the document.
|
|
594
|
-
*/
|
|
595
|
-
class StyleInjector {
|
|
596
|
-
constructor() {
|
|
597
|
-
/**
|
|
598
|
-
* Access the CSP nonce
|
|
599
|
-
*/
|
|
600
|
-
this.cspNonce = inject(CSP_NONCE, { optional: true });
|
|
601
|
-
/**
|
|
602
|
-
* Access the document.
|
|
603
|
-
*/
|
|
604
|
-
this.document = inject(DOCUMENT);
|
|
605
|
-
/**
|
|
606
|
-
* Detect the platform.
|
|
607
|
-
*/
|
|
608
|
-
this.platformId = inject(PLATFORM_ID);
|
|
609
|
-
/**
|
|
610
|
-
* Store the map of style elements with their unique identifiers.
|
|
611
|
-
*/
|
|
612
|
-
this.styleElements = new Map();
|
|
613
|
-
if (isPlatformBrowser(this.platformId)) {
|
|
614
|
-
this.collectServerStyles();
|
|
615
|
-
}
|
|
616
|
-
}
|
|
617
|
-
/**
|
|
618
|
-
* Inject a style into the document.
|
|
619
|
-
* @param id The unique identifier for the style.
|
|
620
|
-
* @param style The style to inject.
|
|
621
|
-
*/
|
|
622
|
-
add(id, style) {
|
|
623
|
-
if (this.styleElements.has(id)) {
|
|
624
|
-
return;
|
|
625
|
-
}
|
|
626
|
-
const styleElement = this.document.createElement('style');
|
|
627
|
-
styleElement.setAttribute('data-ngp-style', id);
|
|
628
|
-
styleElement.textContent = style;
|
|
629
|
-
// If a CSP nonce is provided, set it on the style element
|
|
630
|
-
if (this.cspNonce) {
|
|
631
|
-
styleElement.setAttribute('nonce', this.cspNonce);
|
|
632
|
-
}
|
|
633
|
-
this.document.head.appendChild(styleElement);
|
|
634
|
-
this.styleElements.set(id, styleElement);
|
|
635
|
-
}
|
|
636
|
-
/**
|
|
637
|
-
* Remove a style from the document.
|
|
638
|
-
* @param id The unique identifier for the style.
|
|
639
|
-
*/
|
|
640
|
-
remove(id) {
|
|
641
|
-
const styleElement = this.styleElements.get(id);
|
|
642
|
-
if (styleElement) {
|
|
643
|
-
this.document.head.removeChild(styleElement);
|
|
644
|
-
this.styleElements.delete(id);
|
|
645
|
-
}
|
|
646
|
-
}
|
|
647
|
-
/**
|
|
648
|
-
* Collect any styles that were rendered by the server.
|
|
649
|
-
*/
|
|
650
|
-
collectServerStyles() {
|
|
651
|
-
const styleElements = this.document.querySelectorAll('style[data-ngp-style]');
|
|
652
|
-
styleElements.forEach(styleElement => {
|
|
653
|
-
const id = styleElement.getAttribute('data-ngp-style');
|
|
654
|
-
if (id) {
|
|
655
|
-
this.styleElements.set(id, styleElement);
|
|
656
|
-
}
|
|
657
|
-
});
|
|
658
|
-
}
|
|
659
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.11", ngImport: i0, type: StyleInjector, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
660
|
-
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.11", ngImport: i0, type: StyleInjector, providedIn: 'root' }); }
|
|
661
|
-
}
|
|
662
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.11", ngImport: i0, type: StyleInjector, decorators: [{
|
|
663
|
-
type: Injectable,
|
|
664
|
-
args: [{
|
|
665
|
-
providedIn: 'root',
|
|
666
|
-
}]
|
|
667
|
-
}], ctorParameters: () => [] });
|
|
668
|
-
function injectStyleInjector() {
|
|
669
|
-
return inject(StyleInjector);
|
|
670
|
-
}
|
|
671
|
-
|
|
672
332
|
/**
|
|
673
333
|
* This function sets up a mutation observer to listen for changes in the DOM.
|
|
674
334
|
* It will stop listening when the `disabled` signal is true, and re-enable when it is false.
|
|
@@ -740,5 +400,5 @@ function scrollIntoViewIfNeeded(element) {
|
|
|
740
400
|
* Generated bundle index. Do not edit.
|
|
741
401
|
*/
|
|
742
402
|
|
|
743
|
-
export { NgpExitAnimation, NgpExitAnimationManager, StyleInjector, explicitEffect, fromMutationObserver, fromResizeEvent, injectDimensions, injectElementRef, injectExitAnimationManager, injectStyleInjector, observeResize, onDomRemoval, provideExitAnimationManager, scrollIntoViewIfNeeded, setupExitAnimation,
|
|
403
|
+
export { NgpExitAnimation, NgpExitAnimationManager, StyleInjector, explicitEffect, fromMutationObserver, fromResizeEvent, injectDimensions, injectElementRef, injectExitAnimationManager, injectStyleInjector, observeResize, onDomRemoval, provideExitAnimationManager, scrollIntoViewIfNeeded, setupExitAnimation, setupOverflowListener };
|
|
744
404
|
//# sourceMappingURL=ng-primitives-internal.mjs.map
|