@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.
@@ -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, runInInjectionContext, effect, afterNextRender, untracked, NgZone, isDevMode, computed, Directive, model, EventEmitter, booleanAttribute, numberAttribute, Output, ViewContainerRef, Pipe, AfterRenderPhase, input } from '@angular/core';
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(classMap)
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
- previousEl.classList.remove(...tokens);
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(classMap)) {
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
- currentEl.classList.add(...tokenArray);
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
- if (!signal()) {
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
- el.classList.remove(...tokenArray);
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(classMap);
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
- const elements = buildElementSignal(el);
2429
- return buildSignalEffects({
2430
- map: attributeMap,
2431
- eachItemFn: ({ key, value }) => {
2432
- const valueString = `${value}`;
2433
- if (ALWAYS_TRUE_ATTRIBUTE_KEYS.includes(key)) {
2434
- if (value) {
2435
- elements().currentElement?.setAttribute(key, '');
2436
- }
2437
- else {
2438
- elements().currentElement?.removeAttribute(key);
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
- else {
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
- elements().currentElement?.setAttribute(key, valueString);
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
- const elements = buildElementSignal(el);
2456
- return buildSignalEffects({
2457
- map: styleMap,
2458
- eachItemFn: ({ key, value }) => {
2459
- if (value === null || value === undefined) {
2460
- elements().currentElement?.style.removeProperty(key);
2461
- }
2462
- else {
2463
- const valueString = `${value}`;
2464
- elements().currentElement?.style.setProperty(key, valueString);
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: el.getBoundingClientRect(),
2633
+ boundingClientRect: elBounds,
2665
2634
  intersectionRatio,
2666
- intersectionRect: el.getBoundingClientRect(),
2635
+ intersectionRect: elBounds,
2667
2636
  isIntersecting,
2668
- rootBounds: root().currentElement?.getBoundingClientRect() ?? null,
2637
+ rootBounds: rootBounds ?? null,
2669
2638
  target: el,
2670
2639
  time: performance.now(),
2671
2640
  };