@ethlete/core 4.13.0 → 4.14.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/CHANGELOG.md +6 -0
- package/esm2022/lib/utils/signal.utils.mjs +60 -91
- package/fesm2022/ethlete-core.mjs +60 -91
- package/fesm2022/ethlete-core.mjs.map +1 -1
- package/lib/props/create-prop-handlers.d.ts +6 -6
- package/lib/props/props.directive.d.ts +6 -6
- package/lib/utils/signal.utils.d.ts +24 -26
- package/package.json +1 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
|
-
import { inject, Component, ChangeDetectionStrategy, ViewEncapsulation, Input, HostBinding, InjectionToken, assertInInjectionContext, DestroyRef, ElementRef, TemplateRef, Injectable, isSignal, signal, QueryList, Injector,
|
|
2
|
+
import { inject, Component, ChangeDetectionStrategy, ViewEncapsulation, Input, HostBinding, InjectionToken, assertInInjectionContext, DestroyRef, ElementRef, TemplateRef, Injectable, isSignal, signal, QueryList, Injector, effect, untracked, runInInjectionContext, afterNextRender, NgZone, isDevMode, computed, Directive, model, EventEmitter, booleanAttribute, numberAttribute, Output, ViewContainerRef, Pipe, AfterRenderPhase, input } from '@angular/core';
|
|
3
3
|
import { DomSanitizer, Meta, Title } from '@angular/platform-browser';
|
|
4
4
|
import { Subject, BehaviorSubject, takeUntil, switchMap, of, tap, map, startWith, Observable, combineLatest, timer, distinctUntilChanged, shareReplay, filter, take, fromEvent, pairwise, debounceTime, finalize, merge, skip, takeWhile } from 'rxjs';
|
|
5
5
|
import { END, HOME, PAGE_DOWN, PAGE_UP, UP_ARROW, DOWN_ARROW } from '@angular/cdk/keycodes';
|
|
@@ -2303,51 +2303,7 @@ const buildElementSignal = (el) => {
|
|
|
2303
2303
|
previousElement: previousElements?.[0] ?? null,
|
|
2304
2304
|
}))), { initialValue: { currentElement: null, previousElement: null, previousElements: [], currentElements: [] } });
|
|
2305
2305
|
};
|
|
2306
|
-
const buildSignalEffects = (config) => {
|
|
2307
|
-
const injector = inject(Injector);
|
|
2308
|
-
const { map, eachItemFn, cleanupFn } = config;
|
|
2309
|
-
const effectRefMap = {};
|
|
2310
|
-
const has = (token) => token in effectRefMap;
|
|
2311
|
-
const push = (tokenString, signal) => {
|
|
2312
|
-
if (has(tokenString))
|
|
2313
|
-
return;
|
|
2314
|
-
const tokenArray = tokenString.split(' ').filter((token) => !!token);
|
|
2315
|
-
for (const token of tokenArray) {
|
|
2316
|
-
runInInjectionContext(injector, () => {
|
|
2317
|
-
const ref = effect(() => {
|
|
2318
|
-
const value = signal();
|
|
2319
|
-
eachItemFn({ key: token, value });
|
|
2320
|
-
});
|
|
2321
|
-
effectRefMap[token] = ref;
|
|
2322
|
-
});
|
|
2323
|
-
}
|
|
2324
|
-
};
|
|
2325
|
-
const pushMany = (map) => {
|
|
2326
|
-
for (const [tokenString, signal] of Object.entries(map)) {
|
|
2327
|
-
push(tokenString, signal);
|
|
2328
|
-
}
|
|
2329
|
-
};
|
|
2330
|
-
const remove = (...tokens) => {
|
|
2331
|
-
for (const tokenString of tokens) {
|
|
2332
|
-
effectRefMap[tokenString]?.destroy();
|
|
2333
|
-
cleanupFn({ key: tokenString, value: map[tokenString]?.() });
|
|
2334
|
-
delete effectRefMap[tokenString];
|
|
2335
|
-
}
|
|
2336
|
-
};
|
|
2337
|
-
const removeMany = (tokens) => {
|
|
2338
|
-
for (const token of tokens) {
|
|
2339
|
-
remove(token);
|
|
2340
|
-
}
|
|
2341
|
-
};
|
|
2342
|
-
pushMany(map);
|
|
2343
|
-
return { remove, removeMany, has, push, pushMany };
|
|
2344
|
-
};
|
|
2345
|
-
const signalIsRendered = () => {
|
|
2346
|
-
const isRendered = signal(false);
|
|
2347
|
-
afterNextRender(() => isRendered.set(true));
|
|
2348
|
-
return isRendered.asReadonly();
|
|
2349
|
-
};
|
|
2350
|
-
const signalClasses = (el, classMap) => {
|
|
2306
|
+
const buildSignalEffects = (el, config) => {
|
|
2351
2307
|
const elements = buildElementSignal(el);
|
|
2352
2308
|
const injector = inject(Injector);
|
|
2353
2309
|
effect(() => {
|
|
@@ -2355,24 +2311,22 @@ const signalClasses = (el, classMap) => {
|
|
|
2355
2311
|
for (const previousEl of previousElements) {
|
|
2356
2312
|
if (currentElements.includes(previousEl))
|
|
2357
2313
|
continue;
|
|
2358
|
-
const tokens = Object.keys(
|
|
2314
|
+
const tokens = Object.keys(config.tokenMap)
|
|
2359
2315
|
.map((key) => key.split(' '))
|
|
2360
2316
|
.flat();
|
|
2361
2317
|
if (!tokens.length)
|
|
2362
2318
|
continue;
|
|
2363
|
-
|
|
2319
|
+
config.cleanupFn(previousEl, tokens);
|
|
2364
2320
|
}
|
|
2365
2321
|
for (const currentEl of currentElements) {
|
|
2366
2322
|
if (previousElements.includes(currentEl))
|
|
2367
2323
|
continue;
|
|
2368
|
-
for (const [tokens, condition] of Object.entries(
|
|
2324
|
+
for (const [tokens, condition] of Object.entries(config.tokenMap)) {
|
|
2369
2325
|
untracked(() => {
|
|
2370
|
-
if (!condition())
|
|
2371
|
-
return;
|
|
2372
2326
|
const tokenArray = tokens.split(' ');
|
|
2373
2327
|
if (!tokenArray.length)
|
|
2374
2328
|
return;
|
|
2375
|
-
|
|
2329
|
+
config.updateFn(currentEl, tokenArray, condition());
|
|
2376
2330
|
});
|
|
2377
2331
|
}
|
|
2378
2332
|
}
|
|
@@ -2389,12 +2343,7 @@ const signalClasses = (el, classMap) => {
|
|
|
2389
2343
|
const tokenArray = tokens.split(' ');
|
|
2390
2344
|
if (!tokenArray.length)
|
|
2391
2345
|
continue;
|
|
2392
|
-
|
|
2393
|
-
el.classList.remove(...tokenArray);
|
|
2394
|
-
}
|
|
2395
|
-
else {
|
|
2396
|
-
el.classList.add(...tokenArray);
|
|
2397
|
-
}
|
|
2346
|
+
config.updateFn(el, tokenArray, signal());
|
|
2398
2347
|
}
|
|
2399
2348
|
});
|
|
2400
2349
|
});
|
|
@@ -2411,7 +2360,7 @@ const signalClasses = (el, classMap) => {
|
|
|
2411
2360
|
const tokenArray = tokens.split(' ');
|
|
2412
2361
|
if (!tokenArray.length)
|
|
2413
2362
|
continue;
|
|
2414
|
-
|
|
2363
|
+
config.cleanupFn(el, tokenArray);
|
|
2415
2364
|
}
|
|
2416
2365
|
};
|
|
2417
2366
|
const removeMany = (tokens) => {
|
|
@@ -2419,52 +2368,70 @@ const signalClasses = (el, classMap) => {
|
|
|
2419
2368
|
remove(token);
|
|
2420
2369
|
}
|
|
2421
2370
|
};
|
|
2422
|
-
pushMany(
|
|
2371
|
+
pushMany(config.tokenMap);
|
|
2423
2372
|
return { remove, removeMany, has, push, pushMany };
|
|
2424
2373
|
};
|
|
2374
|
+
const signalIsRendered = () => {
|
|
2375
|
+
const isRendered = signal(false);
|
|
2376
|
+
afterNextRender(() => isRendered.set(true));
|
|
2377
|
+
return isRendered.asReadonly();
|
|
2378
|
+
};
|
|
2379
|
+
const signalClasses = (el, classMap) => {
|
|
2380
|
+
return buildSignalEffects(el, {
|
|
2381
|
+
tokenMap: classMap,
|
|
2382
|
+
cleanupFn: (el, tokens) => el.classList.remove(...tokens),
|
|
2383
|
+
updateFn: (el, tokens, condition) => {
|
|
2384
|
+
if (!condition) {
|
|
2385
|
+
el.classList.remove(...tokens);
|
|
2386
|
+
}
|
|
2387
|
+
else {
|
|
2388
|
+
el.classList.add(...tokens);
|
|
2389
|
+
}
|
|
2390
|
+
},
|
|
2391
|
+
});
|
|
2392
|
+
};
|
|
2425
2393
|
const signalHostClasses = (classMap) => signalClasses(inject(ElementRef), classMap);
|
|
2426
2394
|
const ALWAYS_TRUE_ATTRIBUTE_KEYS = ['disabled', 'readonly', 'required', 'checked', 'selected', 'hidden', 'inert'];
|
|
2427
2395
|
const signalAttributes = (el, attributeMap) => {
|
|
2428
|
-
|
|
2429
|
-
|
|
2430
|
-
|
|
2431
|
-
|
|
2432
|
-
const
|
|
2433
|
-
|
|
2434
|
-
|
|
2435
|
-
|
|
2436
|
-
|
|
2437
|
-
|
|
2438
|
-
|
|
2396
|
+
return buildSignalEffects(el, {
|
|
2397
|
+
tokenMap: attributeMap,
|
|
2398
|
+
cleanupFn: (el, tokens) => tokens.forEach((token) => el.removeAttribute(token)),
|
|
2399
|
+
updateFn: (el, tokens, condition) => {
|
|
2400
|
+
for (const token of tokens) {
|
|
2401
|
+
if (ALWAYS_TRUE_ATTRIBUTE_KEYS.includes(token)) {
|
|
2402
|
+
if (condition) {
|
|
2403
|
+
el.setAttribute(token, '');
|
|
2404
|
+
}
|
|
2405
|
+
else {
|
|
2406
|
+
el.removeAttribute(token);
|
|
2407
|
+
}
|
|
2408
|
+
continue;
|
|
2439
2409
|
}
|
|
2440
|
-
|
|
2441
|
-
|
|
2442
|
-
if (value === null || value === undefined) {
|
|
2443
|
-
elements().currentElement?.removeAttribute(key);
|
|
2410
|
+
if (condition === null || condition === undefined) {
|
|
2411
|
+
el.removeAttribute(token);
|
|
2444
2412
|
}
|
|
2445
2413
|
else {
|
|
2446
|
-
|
|
2414
|
+
el.setAttribute(token, `${condition}`);
|
|
2447
2415
|
}
|
|
2448
2416
|
}
|
|
2449
2417
|
},
|
|
2450
|
-
cleanupFn: ({ key }) => elements().currentElement?.removeAttribute(key),
|
|
2451
2418
|
});
|
|
2452
2419
|
};
|
|
2453
2420
|
const signalHostAttributes = (attributeMap) => signalAttributes(inject(ElementRef), attributeMap);
|
|
2454
2421
|
const signalStyles = (el, styleMap) => {
|
|
2455
|
-
|
|
2456
|
-
|
|
2457
|
-
|
|
2458
|
-
|
|
2459
|
-
|
|
2460
|
-
|
|
2461
|
-
|
|
2462
|
-
|
|
2463
|
-
|
|
2464
|
-
|
|
2422
|
+
return buildSignalEffects(el, {
|
|
2423
|
+
tokenMap: styleMap,
|
|
2424
|
+
cleanupFn: (el, tokens) => tokens.forEach((token) => el.style.removeProperty(token)),
|
|
2425
|
+
updateFn: (el, tokens, condition) => {
|
|
2426
|
+
for (const token of tokens) {
|
|
2427
|
+
if (condition === null || condition === undefined) {
|
|
2428
|
+
el.style.removeProperty(token);
|
|
2429
|
+
}
|
|
2430
|
+
else {
|
|
2431
|
+
el.style.setProperty(token, `${condition}`);
|
|
2432
|
+
}
|
|
2465
2433
|
}
|
|
2466
2434
|
},
|
|
2467
|
-
cleanupFn: ({ key }) => elements().currentElement?.style.removeProperty(key),
|
|
2468
2435
|
});
|
|
2469
2436
|
};
|
|
2470
2437
|
const signalHostStyles = (styleMap) => signalStyles(inject(ElementRef), styleMap);
|
|
@@ -2642,6 +2609,7 @@ const signalElementIntersection = (el, options) => {
|
|
|
2642
2609
|
}
|
|
2643
2610
|
if (els.currentElements.length && !!enabled) {
|
|
2644
2611
|
const rootEl = untracked(() => root().currentElement);
|
|
2612
|
+
const rootBounds = rootEl?.getBoundingClientRect();
|
|
2645
2613
|
// check sync for intersections since the intersection observer async and we probably want to know the initial state
|
|
2646
2614
|
const entries = els.currentElements
|
|
2647
2615
|
.map((el) => {
|
|
@@ -2660,12 +2628,13 @@ const signalElementIntersection = (el, options) => {
|
|
|
2660
2628
|
const blockIntersectionRatio = visibility.blockIntersection / 100;
|
|
2661
2629
|
const isIntersecting = inlineIntersectionRatio > 0 && blockIntersectionRatio > 0;
|
|
2662
2630
|
const intersectionRatio = Math.min(inlineIntersectionRatio, blockIntersectionRatio);
|
|
2631
|
+
const elBounds = el.getBoundingClientRect();
|
|
2663
2632
|
const intersectionEntry = {
|
|
2664
|
-
boundingClientRect:
|
|
2633
|
+
boundingClientRect: elBounds,
|
|
2665
2634
|
intersectionRatio,
|
|
2666
|
-
intersectionRect:
|
|
2635
|
+
intersectionRect: elBounds,
|
|
2667
2636
|
isIntersecting,
|
|
2668
|
-
rootBounds:
|
|
2637
|
+
rootBounds: rootBounds ?? null,
|
|
2669
2638
|
target: el,
|
|
2670
2639
|
time: performance.now(),
|
|
2671
2640
|
};
|