UNPKG

@taiga-ui/cdk

Version:

Base library for creating Angular components and applications using Taiga UI principles regarding of actual visual appearance

97 lines (89 loc) 5.07 kB
import { DOCUMENT } from '@angular/common'; import { InjectionToken, inject, RendererFactory2, NgZone } from '@angular/core'; import { WA_WINDOW } from '@ng-web-apis/common'; import { tuiTypedFromEvent, tuiZonefreeScheduler } from '@taiga-ui/cdk/observables'; import { tuiGetDocumentOrShadowRoot, tuiGetActualTarget, tuiWindowSize } from '@taiga-ui/cdk/utils/dom'; import { tuiIsFocusable } from '@taiga-ui/cdk/utils/focus'; import { Subject, startWith, switchMap, timer, map, share, merge, filter, takeUntil, repeat, withLatestFrom, of, take, distinctUntilChanged } from 'rxjs'; import { WA_IS_IOS, WA_IS_ANDROID } from '@ng-web-apis/platform'; import { toObservable } from '@angular/core/rxjs-interop'; // TODO: Remove when fixed: https://issues.chromium.org/issues/41484175 const TUI_REMOVED_ELEMENT = new InjectionToken(ngDevMode ? 'TUI_REMOVED_ELEMENT' : '', { factory: () => { const element$ = new Subject(); const renderer = inject(RendererFactory2).createRenderer(null, null); const proto = Object.getPrototypeOf(renderer.delegate ?? renderer); const { removeChild } = proto; proto.removeChild = function (...args) { element$.next(args[1]); removeChild.apply(this, args); }; return element$.pipe(startWith(null), switchMap((element) => timer(0).pipe(map(() => null), startWith(element))), share()); }, }); // Checks if focusout event should be considered leaving active zone function isValidFocusout(target, removedElement = null) { return ( // Not due to switching tabs/going to DevTools tuiGetDocumentOrShadowRoot(target).activeElement !== target && // Not due to button/input becoming disabled or under disabled fieldset !target.matches(':disabled') && // Not due to element being removed from DOM !removedElement?.contains(target) && // Not due to scrollable element became non-scrollable (target.getAttribute('tabIndex') === '-1' || tuiIsFocusable(target))); } function shadowRootActiveElement(root) { return merge(tuiTypedFromEvent(root, 'focusin').pipe(map(({ target }) => target)), tuiTypedFromEvent(root, 'focusout').pipe(filter(({ target, relatedTarget }) => !!relatedTarget && isValidFocusout(target)), map(({ relatedTarget }) => relatedTarget))); } /** * Active element on the document for ActiveZone */ const TUI_ACTIVE_ELEMENT = new InjectionToken(ngDevMode ? 'TUI_ACTIVE_ELEMENT' : '', { factory: () => { const removedElement$ = inject(TUI_REMOVED_ELEMENT); const win = inject(WA_WINDOW); const doc = inject(DOCUMENT); const zone = inject(NgZone); const focusout$ = tuiTypedFromEvent(win, 'focusout', { capture: true }); const focusin$ = tuiTypedFromEvent(win, 'focusin', { capture: true }); const blur$ = tuiTypedFromEvent(win, 'blur'); const mousedown$ = tuiTypedFromEvent(win, 'mousedown'); const mouseup$ = tuiTypedFromEvent(win, 'mouseup'); const pointerdown$ = tuiTypedFromEvent(win, 'pointerdown'); const pointercancel$ = tuiTypedFromEvent(win, 'pointercancel'); return merge(focusout$.pipe(takeUntil(pointerdown$.pipe(filter((e) => !e.defaultPrevented))), repeat({ delay: () => merge(mouseup$, pointercancel$) }), withLatestFrom(removedElement$), filter(([event, removedElement]) => isValidFocusout(tuiGetActualTarget(event), removedElement)), map(([{ relatedTarget }]) => relatedTarget)), blur$.pipe(map(() => doc.activeElement), filter((element) => !!element?.matches('iframe'))), focusin$.pipe(switchMap((event) => { const target = tuiGetActualTarget(event); const root = tuiGetDocumentOrShadowRoot(target) || doc; return root === doc ? of(target) : shadowRootActiveElement(root).pipe(startWith(target)); })), mousedown$.pipe(map(tuiGetActualTarget), switchMap((target) => !doc.activeElement || doc.activeElement === doc.body ? of(target) : focusout$.pipe(take(1), map(() => target), takeUntil(timer(0, tuiZonefreeScheduler(zone))))))).pipe(distinctUntilChanged(), share()); }, }); const TUI_FALLBACK_VALUE = new InjectionToken(ngDevMode ? 'TUI_FALLBACK_VALUE' : '', { factory: () => null }); function tuiFallbackValueProvider(useValue) { return { provide: TUI_FALLBACK_VALUE, useValue, }; } const TUI_PLATFORM = new InjectionToken(ngDevMode ? 'TUI_PLATFORM' : '', { factory: () => { if (inject(WA_IS_IOS)) { return 'ios'; } return inject(WA_IS_ANDROID) ? 'android' : 'web'; }, }); /** * @deprecated: use {@link tuiWindowSize} */ const TUI_WINDOW_SIZE = new InjectionToken(ngDevMode ? 'TUI_WINDOW_SIZE' : '', { factory: () => toObservable(tuiWindowSize(inject(WA_WINDOW))) }); /** * Generated bundle index. Do not edit. */ export { TUI_ACTIVE_ELEMENT, TUI_FALLBACK_VALUE, TUI_PLATFORM, TUI_REMOVED_ELEMENT, TUI_WINDOW_SIZE, tuiFallbackValueProvider }; //# sourceMappingURL=taiga-ui-cdk-tokens.mjs.map