@signality/core 0.1.2 → 0.2.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/browser/device-pixel-ratio/index.d.ts +30 -0
- package/browser/file-dialog/index.d.ts +1 -2
- package/browser/index.d.ts +1 -0
- package/browser/listener/index.d.ts +1 -0
- package/browser/picture-in-picture/index.d.ts +1 -5
- package/browser/text-selection/index.d.ts +9 -2
- package/browser/web-notification/index.d.ts +3 -3
- package/fesm2022/signality-core-browser-clipboard.mjs +13 -30
- package/fesm2022/signality-core-browser-clipboard.mjs.map +1 -1
- package/fesm2022/signality-core-browser-device-pixel-ratio.mjs +45 -0
- package/fesm2022/signality-core-browser-device-pixel-ratio.mjs.map +1 -0
- package/fesm2022/signality-core-browser-eye-dropper.mjs +2 -3
- package/fesm2022/signality-core-browser-eye-dropper.mjs.map +1 -1
- package/fesm2022/signality-core-browser-file-dialog.mjs +2 -1
- package/fesm2022/signality-core-browser-file-dialog.mjs.map +1 -1
- package/fesm2022/signality-core-browser-fullscreen.mjs +8 -19
- package/fesm2022/signality-core-browser-fullscreen.mjs.map +1 -1
- package/fesm2022/signality-core-browser-gamepad.mjs +2 -10
- package/fesm2022/signality-core-browser-gamepad.mjs.map +1 -1
- package/fesm2022/signality-core-browser-listener.mjs +2 -1
- package/fesm2022/signality-core-browser-listener.mjs.map +1 -1
- package/fesm2022/signality-core-browser-media-query.mjs +2 -1
- package/fesm2022/signality-core-browser-media-query.mjs.map +1 -1
- package/fesm2022/signality-core-browser-picture-in-picture.mjs +10 -13
- package/fesm2022/signality-core-browser-picture-in-picture.mjs.map +1 -1
- package/fesm2022/signality-core-browser-speech-recognition.mjs +2 -1
- package/fesm2022/signality-core-browser-speech-recognition.mjs.map +1 -1
- package/fesm2022/signality-core-browser-speech-synthesis.mjs +2 -1
- package/fesm2022/signality-core-browser-speech-synthesis.mjs.map +1 -1
- package/fesm2022/signality-core-browser-storage.mjs +38 -68
- package/fesm2022/signality-core-browser-storage.mjs.map +1 -1
- package/fesm2022/signality-core-browser-text-direction.mjs +2 -1
- package/fesm2022/signality-core-browser-text-direction.mjs.map +1 -1
- package/fesm2022/signality-core-browser-text-selection.mjs +36 -4
- package/fesm2022/signality-core-browser-text-selection.mjs.map +1 -1
- package/fesm2022/signality-core-browser-vibration.mjs +16 -30
- package/fesm2022/signality-core-browser-vibration.mjs.map +1 -1
- package/fesm2022/signality-core-browser-web-notification.mjs +33 -53
- package/fesm2022/signality-core-browser-web-notification.mjs.map +1 -1
- package/fesm2022/signality-core-browser-web-share.mjs +3 -11
- package/fesm2022/signality-core-browser-web-share.mjs.map +1 -1
- package/fesm2022/signality-core-browser-web-worker.mjs +2 -1
- package/fesm2022/signality-core-browser-web-worker.mjs.map +1 -1
- package/fesm2022/signality-core-browser.mjs +1 -0
- package/fesm2022/signality-core-browser.mjs.map +1 -1
- package/fesm2022/signality-core-elements-dropzone.mjs +2 -1
- package/fesm2022/signality-core-elements-dropzone.mjs.map +1 -1
- package/fesm2022/signality-core-elements-element-focus-within.mjs +2 -1
- package/fesm2022/signality-core-elements-element-focus-within.mjs.map +1 -1
- package/fesm2022/signality-core-elements-element-focus.mjs +2 -1
- package/fesm2022/signality-core-elements-element-focus.mjs.map +1 -1
- package/fesm2022/signality-core-elements-element-size.mjs +2 -1
- package/fesm2022/signality-core-elements-element-size.mjs.map +1 -1
- package/fesm2022/signality-core-elements-on-click-outside.mjs +2 -1
- package/fesm2022/signality-core-elements-on-click-outside.mjs.map +1 -1
- package/fesm2022/signality-core-elements-on-disconnect.mjs +2 -1
- package/fesm2022/signality-core-elements-on-disconnect.mjs.map +1 -1
- package/fesm2022/signality-core-elements-on-long-press.mjs +2 -1
- package/fesm2022/signality-core-elements-on-long-press.mjs.map +1 -1
- package/fesm2022/signality-core-elements-scroll-position.mjs +2 -1
- package/fesm2022/signality-core-elements-scroll-position.mjs.map +1 -1
- package/fesm2022/signality-core-forms-cva.mjs +13 -3
- package/fesm2022/signality-core-forms-cva.mjs.map +1 -1
- package/fesm2022/signality-core-internal.mjs +35 -27
- package/fesm2022/signality-core-internal.mjs.map +1 -1
- package/fesm2022/signality-core-observers-intersection-observer.mjs +2 -1
- package/fesm2022/signality-core-observers-intersection-observer.mjs.map +1 -1
- package/fesm2022/signality-core-observers-mutation-observer.mjs +2 -1
- package/fesm2022/signality-core-observers-mutation-observer.mjs.map +1 -1
- package/fesm2022/signality-core-observers-resize-observer.mjs +2 -1
- package/fesm2022/signality-core-observers-resize-observer.mjs.map +1 -1
- package/fesm2022/signality-core-reactivity-debounced.mjs +2 -1
- package/fesm2022/signality-core-reactivity-debounced.mjs.map +1 -1
- package/fesm2022/signality-core-reactivity-throttled.mjs +2 -1
- package/fesm2022/signality-core-reactivity-throttled.mjs.map +1 -1
- package/fesm2022/signality-core-scheduling-debounce-callback.mjs +2 -1
- package/fesm2022/signality-core-scheduling-debounce-callback.mjs.map +1 -1
- package/fesm2022/signality-core-scheduling-interval.mjs +2 -1
- package/fesm2022/signality-core-scheduling-interval.mjs.map +1 -1
- package/fesm2022/signality-core-scheduling-throttle-callback.mjs +2 -1
- package/fesm2022/signality-core-scheduling-throttle-callback.mjs.map +1 -1
- package/fesm2022/signality-core-utilities.mjs +64 -0
- package/fesm2022/signality-core-utilities.mjs.map +1 -0
- package/fesm2022/signality-core.mjs +1 -0
- package/fesm2022/signality-core.mjs.map +1 -1
- package/forms/cva/index.d.ts +10 -5
- package/index.d.ts +1 -0
- package/internal/utils/index.d.ts +1 -2
- package/internal/utils/wait-for-value.d.ts +6 -0
- package/package.json +13 -5
- package/utilities/generate-id.d.ts +29 -0
- package/utilities/index.d.ts +3 -0
- /package/{internal/utils → utilities}/to-element.d.ts +0 -0
- /package/{internal/utils → utilities}/to-value.d.ts +0 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"signality-core-elements-element-focus.mjs","sources":["../../../projects/core/elements/element-focus/index.ts","../../../projects/core/elements/element-focus/signality-core-elements-element-focus.ts"],"sourcesContent":["import { type CreateSignalOptions, signal, type WritableSignal } from '@angular/core';\nimport { proxySignal, setupContext
|
|
1
|
+
{"version":3,"file":"signality-core-elements-element-focus.mjs","sources":["../../../projects/core/elements/element-focus/index.ts","../../../projects/core/elements/element-focus/signality-core-elements-element-focus.ts"],"sourcesContent":["import { type CreateSignalOptions, signal, type WritableSignal } from '@angular/core';\nimport { proxySignal, setupContext } from '@signality/core/internal';\nimport { toElement } from '@signality/core/utilities';\nimport type { MaybeElementSignal, WithInjector } from '@signality/core/types';\nimport { listener } from '@signality/core/browser/listener';\nimport { onDisconnect } from '@signality/core/elements/on-disconnect';\n\nexport interface ElementFocusOptions extends CreateSignalOptions<boolean>, WithInjector {\n /**\n * Track focus using the `:focus-visible` pseudo-class.\n * The browser uses heuristics to determine when focus should be visually indicated\n * (e.g., keyboard navigation, programmatic focus, or when the element requires user attention).\n *\n * @see {@link https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/Selectors/:focus-visible MDN: :focus-visible}\n * @default false\n */\n readonly focusVisible?: boolean;\n\n /**\n * Prevent scrolling to the element when it is focused.\n * @default false\n */\n readonly preventScroll?: boolean;\n}\n\n/**\n * Reactive tracking of focus state on an element.\n * Detects when an element gains or loses focus, and allows programmatically setting focus.\n *\n * @param target - The element to track focus state on\n * @param options - Optional configuration including focusVisible, preventScroll and injector\n * @returns A writable signal that is `true` when the element has focus\n *\n * @example\n * ```typescript\n * @Component({\n * template: `\n * <input #input [class.focused]=\"isFocused()\" />\n * <button (click)=\"isFocused.set(true)\">Focus Input</button>\n * <button (click)=\"isFocused.set(false)\">Blur Input</button>\n * `\n * })\n * export class FocusDemo {\n * readonly input = viewChild<ElementRef>('input');\n * readonly isFocused = elementFocus(this.input);\n * }\n * ```\n */\nexport function elementFocus(\n target: MaybeElementSignal<HTMLElement>,\n options?: ElementFocusOptions\n): WritableSignal<boolean> {\n const { runInContext } = setupContext(options?.injector, elementFocus);\n\n return runInContext(({ isServer }) => {\n if (isServer) {\n return signal(false, options);\n }\n\n const focusVisible = options?.focusVisible ?? false;\n const preventScroll = options?.preventScroll ?? false;\n\n const focused = signal<boolean>(false, options);\n\n listener(target, 'focus', e => {\n focused.set(focusVisible ? (e.target as HTMLElement).matches(':focus-visible') : true);\n });\n\n listener(target, 'blur', () => {\n focused.set(false);\n });\n\n onDisconnect(target, () => {\n focused.set(false);\n });\n\n return proxySignal(focused, {\n set: (value: boolean) => {\n const el = toElement(target);\n const hasFocus = el?.matches(':focus') ?? false;\n\n if (value && !hasFocus) {\n el?.focus({ preventScroll });\n } else if (!value && hasFocus) {\n el?.blur();\n }\n },\n });\n });\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":";;;;;;AAyBA;;;;;;;;;;;;;;;;;;;;;;AAsBG;AACG,SAAU,YAAY,CAC1B,MAAuC,EACvC,OAA6B,EAAA;AAE7B,IAAA,MAAM,EAAE,YAAY,EAAE,GAAG,YAAY,CAAC,OAAO,EAAE,QAAQ,EAAE,YAAY,CAAC;AAEtE,IAAA,OAAO,YAAY,CAAC,CAAC,EAAE,QAAQ,EAAE,KAAI;QACnC,IAAI,QAAQ,EAAE;AACZ,YAAA,OAAO,MAAM,CAAC,KAAK,EAAE,OAAO,CAAC;QAC/B;AAEA,QAAA,MAAM,YAAY,GAAG,OAAO,EAAE,YAAY,IAAI,KAAK;AACnD,QAAA,MAAM,aAAa,GAAG,OAAO,EAAE,aAAa,IAAI,KAAK;QAErD,MAAM,OAAO,GAAG,MAAM,CAAU,KAAK,EAAE,OAAO,CAAC;AAE/C,QAAA,QAAQ,CAAC,MAAM,EAAE,OAAO,EAAE,CAAC,IAAG;YAC5B,OAAO,CAAC,GAAG,CAAC,YAAY,GAAI,CAAC,CAAC,MAAsB,CAAC,OAAO,CAAC,gBAAgB,CAAC,GAAG,IAAI,CAAC;AACxF,QAAA,CAAC,CAAC;AAEF,QAAA,QAAQ,CAAC,MAAM,EAAE,MAAM,EAAE,MAAK;AAC5B,YAAA,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC;AACpB,QAAA,CAAC,CAAC;AAEF,QAAA,YAAY,CAAC,MAAM,EAAE,MAAK;AACxB,YAAA,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC;AACpB,QAAA,CAAC,CAAC;QAEF,OAAO,WAAW,CAAC,OAAO,EAAE;AAC1B,YAAA,GAAG,EAAE,CAAC,KAAc,KAAI;AACtB,gBAAA,MAAM,EAAE,GAAG,SAAS,CAAC,MAAM,CAAC;gBAC5B,MAAM,QAAQ,GAAG,EAAE,EAAE,OAAO,CAAC,QAAQ,CAAC,IAAI,KAAK;AAE/C,gBAAA,IAAI,KAAK,IAAI,CAAC,QAAQ,EAAE;AACtB,oBAAA,EAAE,EAAE,KAAK,CAAC,EAAE,aAAa,EAAE,CAAC;gBAC9B;AAAO,qBAAA,IAAI,CAAC,KAAK,IAAI,QAAQ,EAAE;oBAC7B,EAAE,EAAE,IAAI,EAAE;gBACZ;YACF,CAAC;AACF,SAAA,CAAC;AACJ,IAAA,CAAC,CAAC;AACJ;;ACzFA;;AAEG;;;;"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { signal } from '@angular/core';
|
|
2
|
-
import { setupContext, constSignal
|
|
2
|
+
import { setupContext, constSignal } from '@signality/core/internal';
|
|
3
|
+
import { toValue } from '@signality/core/utilities';
|
|
3
4
|
import { resizeObserver } from '@signality/core/observers/resize-observer';
|
|
4
5
|
import { onDisconnect } from '@signality/core/elements/on-disconnect';
|
|
5
6
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"signality-core-elements-element-size.mjs","sources":["../../../projects/core/elements/element-size/index.ts","../../../projects/core/elements/element-size/signality-core-elements-element-size.ts"],"sourcesContent":["import { type CreateSignalOptions, signal, type Signal } from '@angular/core';\nimport { constSignal, setupContext
|
|
1
|
+
{"version":3,"file":"signality-core-elements-element-size.mjs","sources":["../../../projects/core/elements/element-size/index.ts","../../../projects/core/elements/element-size/signality-core-elements-element-size.ts"],"sourcesContent":["import { type CreateSignalOptions, signal, type Signal } from '@angular/core';\nimport { constSignal, setupContext } from '@signality/core/internal';\nimport { toValue } from '@signality/core/utilities';\nimport type { MaybeElementSignal, MaybeSignal, WithInjector } from '@signality/core/types';\nimport { resizeObserver } from '@signality/core/observers/resize-observer';\nimport { onDisconnect } from '@signality/core/elements/on-disconnect';\n\nexport interface ElementSizeValue {\n readonly width: number;\n readonly height: number;\n}\n\nexport interface ElementSizeOptions extends CreateSignalOptions<ElementSizeValue>, WithInjector {\n /**\n * Which box model to observe. Can be a reactive signal.\n *\n * @default 'border-box'\n */\n readonly box?: MaybeSignal<ResizeObserverBoxOptions>;\n\n /**\n * Initial value for SSR and before the first measurement.\n *\n * @default { width: 0, height: 0 }\n */\n readonly initialValue?: ElementSizeValue;\n}\n\n/**\n * Signal-based wrapper around the [ResizeObserver API](https://developer.mozilla.org/en-US/docs/Web/API/ResizeObserver).\n *\n * @param target - The element to observe\n * @param options - Optional configuration including signal options (equal, debugName), box model, and injector\n * @returns A signal containing the current element dimensions\n *\n * @example\n * ```typescript\n * @Component({\n * template: `\n * <div #box>\n * Size: {{ size().width }} × {{ size().height }}px\n * </div>\n * `\n * })\n * export class ElementSizeDemo {\n * readonly box = viewChild<ElementRef>('box');\n * readonly size = elementSize(this.box);\n * }\n * ```\n */\nexport function elementSize(\n target: MaybeElementSignal<HTMLElement>,\n options?: ElementSizeOptions\n): Signal<ElementSizeValue> {\n const { runInContext } = setupContext(options?.injector, elementSize);\n const initialValue = options?.initialValue ?? DEFAULT_SIZE;\n\n return runInContext(({ isServer }) => {\n if (isServer) {\n return constSignal(initialValue);\n }\n\n const size = signal<ElementSizeValue>(initialValue, options);\n\n const updateSize = ([entry]: readonly ResizeObserverEntry[]) => {\n const box = toValue(options?.box) ?? 'border-box';\n\n if (box === 'content-box') {\n const contentBoxSize = entry.contentBoxSize?.[0];\n size.set({\n width: contentBoxSize?.inlineSize ?? entry.contentRect.width,\n height: contentBoxSize?.blockSize ?? entry.contentRect.height,\n });\n } else {\n const borderBoxSize = entry.borderBoxSize?.[0];\n size.set({\n width: borderBoxSize?.inlineSize ?? entry.contentRect.width,\n height: borderBoxSize?.blockSize ?? entry.contentRect.height,\n });\n }\n };\n\n resizeObserver(target, updateSize, options);\n\n onDisconnect(target, () => size.set(DEFAULT_SIZE));\n\n return size;\n });\n}\n\nconst DEFAULT_SIZE: ElementSizeValue = {\n width: 0,\n height: 0,\n};\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":";;;;;;AA4BA;;;;;;;;;;;;;;;;;;;;;AAqBG;AACG,SAAU,WAAW,CACzB,MAAuC,EACvC,OAA4B,EAAA;AAE5B,IAAA,MAAM,EAAE,YAAY,EAAE,GAAG,YAAY,CAAC,OAAO,EAAE,QAAQ,EAAE,WAAW,CAAC;AACrE,IAAA,MAAM,YAAY,GAAG,OAAO,EAAE,YAAY,IAAI,YAAY;AAE1D,IAAA,OAAO,YAAY,CAAC,CAAC,EAAE,QAAQ,EAAE,KAAI;QACnC,IAAI,QAAQ,EAAE;AACZ,YAAA,OAAO,WAAW,CAAC,YAAY,CAAC;QAClC;QAEA,MAAM,IAAI,GAAG,MAAM,CAAmB,YAAY,EAAE,OAAO,CAAC;AAE5D,QAAA,MAAM,UAAU,GAAG,CAAC,CAAC,KAAK,CAAiC,KAAI;YAC7D,MAAM,GAAG,GAAG,OAAO,CAAC,OAAO,EAAE,GAAG,CAAC,IAAI,YAAY;AAEjD,YAAA,IAAI,GAAG,KAAK,aAAa,EAAE;gBACzB,MAAM,cAAc,GAAG,KAAK,CAAC,cAAc,GAAG,CAAC,CAAC;gBAChD,IAAI,CAAC,GAAG,CAAC;oBACP,KAAK,EAAE,cAAc,EAAE,UAAU,IAAI,KAAK,CAAC,WAAW,CAAC,KAAK;oBAC5D,MAAM,EAAE,cAAc,EAAE,SAAS,IAAI,KAAK,CAAC,WAAW,CAAC,MAAM;AAC9D,iBAAA,CAAC;YACJ;iBAAO;gBACL,MAAM,aAAa,GAAG,KAAK,CAAC,aAAa,GAAG,CAAC,CAAC;gBAC9C,IAAI,CAAC,GAAG,CAAC;oBACP,KAAK,EAAE,aAAa,EAAE,UAAU,IAAI,KAAK,CAAC,WAAW,CAAC,KAAK;oBAC3D,MAAM,EAAE,aAAa,EAAE,SAAS,IAAI,KAAK,CAAC,WAAW,CAAC,MAAM;AAC7D,iBAAA,CAAC;YACJ;AACF,QAAA,CAAC;AAED,QAAA,cAAc,CAAC,MAAM,EAAE,UAAU,EAAE,OAAO,CAAC;AAE3C,QAAA,YAAY,CAAC,MAAM,EAAE,MAAM,IAAI,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC;AAElD,QAAA,OAAO,IAAI;AACb,IAAA,CAAC,CAAC;AACJ;AAEA,MAAM,YAAY,GAAqB;AACrC,IAAA,KAAK,EAAE,CAAC;AACR,IAAA,MAAM,EAAE,CAAC;CACV;;AC7FD;;AAEG;;;;"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { setupContext, NOOP_EFFECT_REF
|
|
1
|
+
import { setupContext, NOOP_EFFECT_REF } from '@signality/core/internal';
|
|
2
|
+
import { toElement } from '@signality/core/utilities';
|
|
2
3
|
import { setupSync, listener } from '@signality/core/browser/listener';
|
|
3
4
|
|
|
4
5
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"signality-core-elements-on-click-outside.mjs","sources":["../../../projects/core/elements/on-click-outside/index.ts","../../../projects/core/elements/on-click-outside/signality-core-elements-on-click-outside.ts"],"sourcesContent":["import { NOOP_EFFECT_REF, setupContext
|
|
1
|
+
{"version":3,"file":"signality-core-elements-on-click-outside.mjs","sources":["../../../projects/core/elements/on-click-outside/index.ts","../../../projects/core/elements/on-click-outside/signality-core-elements-on-click-outside.ts"],"sourcesContent":["import { NOOP_EFFECT_REF, setupContext } from '@signality/core/internal';\nimport { toElement } from '@signality/core/utilities';\nimport type { MaybeElementSignal, WithInjector } from '@signality/core/types';\nimport { listener, setupSync } from '@signality/core/browser/listener';\n\nexport interface OnClickOutsideOptions extends WithInjector {\n /**\n * Elements that should not trigger the outside click handler.\n */\n readonly ignore?: MaybeElementSignal<Element>[];\n}\n\nexport interface OnClickOutsideRef {\n /** Stops listening for outside clicks. */\n readonly destroy: () => void;\n}\n\n/**\n * Detects clicks outside a target element and invokes a callback.\n * Useful for closing dropdowns, modals, and popovers when the user clicks elsewhere.\n *\n * @param target - Element to detect clicks outside of\n * @param handler - Callback invoked when a click outside the target is detected\n * @param options - Optional configuration including ignore list and injector\n * @returns An OnClickOutsideRef with a destroy method to stop detection\n *\n * @example\n * ```typescript\n * @Component({\n * template: `\n * <div #dropdown class=\"dropdown\">\n * <p>Dropdown content</p>\n * </div>\n * `\n * })\n * export class Dropdown {\n * readonly dropdown = viewChild<ElementRef>('dropdown');\n * readonly isOpen = signal(true);\n *\n * constructor() {\n * onClickOutside(this.dropdown, () => {\n * this.isOpen.set(false);\n * });\n * }\n * }\n * ```\n */\nexport function onClickOutside(\n target: MaybeElementSignal<HTMLElement>,\n handler: (event: PointerEvent | FocusEvent) => void,\n options?: OnClickOutsideOptions\n): OnClickOutsideRef {\n const { runInContext } = setupContext(options?.injector, onClickOutside);\n\n return runInContext(({ isServer }) => {\n if (isServer) {\n return NOOP_EFFECT_REF;\n }\n\n const ignoreList = options?.ignore ?? [];\n\n let shouldFire = false;\n\n function isOutside(event: Event): boolean {\n const el = toElement(target);\n const path = event.composedPath();\n\n if (el && path.includes(el)) {\n return false;\n }\n\n if (ignoreList.length) {\n return !ignoreList.some(ignored => {\n const ignoredEl = toElement(ignored);\n return ignoredEl && path.includes(ignoredEl);\n });\n }\n\n return true;\n }\n\n const pointerDownListener = setupSync(() =>\n listener.capture(window, 'pointerdown', (e: PointerEvent) => {\n shouldFire = isOutside(e);\n })\n );\n\n const clickListener = setupSync(() =>\n listener.capture(window, 'pointerup', (e: PointerEvent) => {\n if (!shouldFire) {\n return;\n }\n\n shouldFire = false;\n\n if (!isOutside(e)) {\n return;\n }\n\n handler(e);\n })\n );\n\n const blurListener = setupSync(() =>\n listener(window, 'blur', (e: FocusEvent) => {\n setTimeout(() => {\n const active = document.activeElement;\n\n if (active?.tagName !== 'IFRAME') {\n return;\n }\n\n const el = toElement(target);\n\n if (el?.contains(active)) {\n return;\n }\n\n handler(e);\n }, 0);\n })\n );\n\n return {\n destroy: () => {\n pointerDownListener.destroy();\n clickListener.destroy();\n blurListener.destroy();\n },\n };\n });\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":";;;;AAiBA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA6BG;SACa,cAAc,CAC5B,MAAuC,EACvC,OAAmD,EACnD,OAA+B,EAAA;AAE/B,IAAA,MAAM,EAAE,YAAY,EAAE,GAAG,YAAY,CAAC,OAAO,EAAE,QAAQ,EAAE,cAAc,CAAC;AAExE,IAAA,OAAO,YAAY,CAAC,CAAC,EAAE,QAAQ,EAAE,KAAI;QACnC,IAAI,QAAQ,EAAE;AACZ,YAAA,OAAO,eAAe;QACxB;AAEA,QAAA,MAAM,UAAU,GAAG,OAAO,EAAE,MAAM,IAAI,EAAE;QAExC,IAAI,UAAU,GAAG,KAAK;QAEtB,SAAS,SAAS,CAAC,KAAY,EAAA;AAC7B,YAAA,MAAM,EAAE,GAAG,SAAS,CAAC,MAAM,CAAC;AAC5B,YAAA,MAAM,IAAI,GAAG,KAAK,CAAC,YAAY,EAAE;YAEjC,IAAI,EAAE,IAAI,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,EAAE;AAC3B,gBAAA,OAAO,KAAK;YACd;AAEA,YAAA,IAAI,UAAU,CAAC,MAAM,EAAE;AACrB,gBAAA,OAAO,CAAC,UAAU,CAAC,IAAI,CAAC,OAAO,IAAG;AAChC,oBAAA,MAAM,SAAS,GAAG,SAAS,CAAC,OAAO,CAAC;oBACpC,OAAO,SAAS,IAAI,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC;AAC9C,gBAAA,CAAC,CAAC;YACJ;AAEA,YAAA,OAAO,IAAI;QACb;AAEA,QAAA,MAAM,mBAAmB,GAAG,SAAS,CAAC,MACpC,QAAQ,CAAC,OAAO,CAAC,MAAM,EAAE,aAAa,EAAE,CAAC,CAAe,KAAI;AAC1D,YAAA,UAAU,GAAG,SAAS,CAAC,CAAC,CAAC;QAC3B,CAAC,CAAC,CACH;AAED,QAAA,MAAM,aAAa,GAAG,SAAS,CAAC,MAC9B,QAAQ,CAAC,OAAO,CAAC,MAAM,EAAE,WAAW,EAAE,CAAC,CAAe,KAAI;YACxD,IAAI,CAAC,UAAU,EAAE;gBACf;YACF;YAEA,UAAU,GAAG,KAAK;AAElB,YAAA,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE;gBACjB;YACF;YAEA,OAAO,CAAC,CAAC,CAAC;QACZ,CAAC,CAAC,CACH;AAED,QAAA,MAAM,YAAY,GAAG,SAAS,CAAC,MAC7B,QAAQ,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAa,KAAI;YACzC,UAAU,CAAC,MAAK;AACd,gBAAA,MAAM,MAAM,GAAG,QAAQ,CAAC,aAAa;AAErC,gBAAA,IAAI,MAAM,EAAE,OAAO,KAAK,QAAQ,EAAE;oBAChC;gBACF;AAEA,gBAAA,MAAM,EAAE,GAAG,SAAS,CAAC,MAAM,CAAC;AAE5B,gBAAA,IAAI,EAAE,EAAE,QAAQ,CAAC,MAAM,CAAC,EAAE;oBACxB;gBACF;gBAEA,OAAO,CAAC,CAAC,CAAC;YACZ,CAAC,EAAE,CAAC,CAAC;QACP,CAAC,CAAC,CACH;QAED,OAAO;YACL,OAAO,EAAE,MAAK;gBACZ,mBAAmB,CAAC,OAAO,EAAE;gBAC7B,aAAa,CAAC,OAAO,EAAE;gBACvB,YAAY,CAAC,OAAO,EAAE;YACxB,CAAC;SACF;AACH,IAAA,CAAC,CAAC;AACJ;;ACnIA;;AAEG;;;;"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { inject, ElementRef, DestroyRef, afterRenderEffect, afterEveryRender } from '@angular/core';
|
|
2
|
-
import { setupContext, NOOP_EFFECT_REF,
|
|
2
|
+
import { setupContext, NOOP_EFFECT_REF, isQuerySignal } from '@signality/core/internal';
|
|
3
|
+
import { toElement } from '@signality/core/utilities';
|
|
3
4
|
|
|
4
5
|
/**
|
|
5
6
|
* Executes a callback when an element is disconnected from the DOM.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"signality-core-elements-on-disconnect.mjs","sources":["../../../projects/core/elements/on-disconnect/index.ts","../../../projects/core/elements/on-disconnect/signality-core-elements-on-disconnect.ts"],"sourcesContent":["import { afterEveryRender, afterRenderEffect, DestroyRef, ElementRef, inject } from '@angular/core';\nimport { isQuerySignal, NOOP_EFFECT_REF, setupContext
|
|
1
|
+
{"version":3,"file":"signality-core-elements-on-disconnect.mjs","sources":["../../../projects/core/elements/on-disconnect/index.ts","../../../projects/core/elements/on-disconnect/signality-core-elements-on-disconnect.ts"],"sourcesContent":["import { afterEveryRender, afterRenderEffect, DestroyRef, ElementRef, inject } from '@angular/core';\nimport { isQuerySignal, NOOP_EFFECT_REF, setupContext } from '@signality/core/internal';\nimport { toElement } from '@signality/core/utilities';\nimport type { MaybeElementSignal, WithInjector } from '@signality/core/types';\n\nexport type OnDisconnectOptions = WithInjector;\n\nexport interface OnDisconnectRef {\n readonly destroy: () => void;\n}\n\n/**\n * Executes a callback when an element is disconnected from the DOM.\n *\n * @param target - The element to watch for disconnection\n * @param callback - Callback to execute when the element is disconnected\n * @param options - Optional configuration including injector\n * @returns OnDisconnectRef with a destroy method to stop watching for disconnection\n *\n * @example\n * ```typescript\n * @Component({\n * template: `\n * <div #box>Content</div>\n * <button (click)=\"remove()\">Remove</button>\n * `\n * })\n * export class OnDisconnectDemo {\n * readonly box = viewChild<ElementRef>('box');\n *\n * constructor() {\n * onDisconnect(this.box, el => {\n * console.log('Element disconnected: ', el.tagName);\n * // perform cleanup without storing the reference\n * });\n * }\n * }\n * ```\n *\n * @example\n * ```typescript\n * // Manual cleanup\n * const disconnectRef = onDisconnect(element, () => {\n * console.log('Disconnected');\n * });\n *\n * // Stop watching before disconnection\n * disconnectRef.destroy();\n * ```\n */\nexport function onDisconnect<T extends Element>(\n target: MaybeElementSignal<T>,\n callback: (element: T) => void,\n options?: OnDisconnectOptions\n): OnDisconnectRef {\n const { runInContext } = setupContext(options?.injector, onDisconnect);\n\n return runInContext(({ isServer }) => {\n if (isServer) {\n return NOOP_EFFECT_REF;\n }\n\n // (1) Host element check\n // if we are inside a directive and the target element is its host,\n // then we hook into the directive's lifecycle via its DestroyRef\n const hostElRef = inject(ElementRef, { optional: true, self: true });\n if (hostElRef) {\n const targetEl = toElement(target);\n if (targetEl && hostElRef.nativeElement === targetEl) {\n return {\n destroy: inject(DestroyRef).onDestroy(() => callback(targetEl)),\n };\n }\n }\n\n // (2) Query signal check (viewChild/contentChild)\n // if target is a query signal, we rely on its automatic state transition\n // managed by Angular's change detection, calling callback at render completion timing\n if (isQuerySignal(target)) {\n const effectRef = afterRenderEffect({\n read: onCleanup => {\n const targetEl = toElement(target);\n\n if (targetEl) {\n onCleanup(() => {\n if (!targetEl.isConnected) callback(targetEl);\n });\n }\n },\n });\n\n return { destroy: () => effectRef.destroy() };\n }\n\n // (3) Fallback\n // for any DOM target (reactive or non-reactive), we assume the value was\n // manually read from the DOM. Therefore, we perform isConnected check after\n // every render cycle to detect disconnection\n // @TODO: document the behavior of state transitions when the target is reactive\n const afterRenderRef = afterEveryRender({\n read: () => {\n const targetEl = toElement(target);\n if (targetEl && !targetEl.isConnected) callback(targetEl);\n },\n });\n\n return { destroy: () => afterRenderRef.destroy() };\n });\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":";;;;AAWA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAsCG;SACa,YAAY,CAC1B,MAA6B,EAC7B,QAA8B,EAC9B,OAA6B,EAAA;AAE7B,IAAA,MAAM,EAAE,YAAY,EAAE,GAAG,YAAY,CAAC,OAAO,EAAE,QAAQ,EAAE,YAAY,CAAC;AAEtE,IAAA,OAAO,YAAY,CAAC,CAAC,EAAE,QAAQ,EAAE,KAAI;QACnC,IAAI,QAAQ,EAAE;AACZ,YAAA,OAAO,eAAe;QACxB;;;;AAKA,QAAA,MAAM,SAAS,GAAG,MAAM,CAAC,UAAU,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;QACpE,IAAI,SAAS,EAAE;AACb,YAAA,MAAM,QAAQ,GAAG,SAAS,CAAC,MAAM,CAAC;YAClC,IAAI,QAAQ,IAAI,SAAS,CAAC,aAAa,KAAK,QAAQ,EAAE;gBACpD,OAAO;AACL,oBAAA,OAAO,EAAE,MAAM,CAAC,UAAU,CAAC,CAAC,SAAS,CAAC,MAAM,QAAQ,CAAC,QAAQ,CAAC,CAAC;iBAChE;YACH;QACF;;;;AAKA,QAAA,IAAI,aAAa,CAAC,MAAM,CAAC,EAAE;YACzB,MAAM,SAAS,GAAG,iBAAiB,CAAC;gBAClC,IAAI,EAAE,SAAS,IAAG;AAChB,oBAAA,MAAM,QAAQ,GAAG,SAAS,CAAC,MAAM,CAAC;oBAElC,IAAI,QAAQ,EAAE;wBACZ,SAAS,CAAC,MAAK;4BACb,IAAI,CAAC,QAAQ,CAAC,WAAW;gCAAE,QAAQ,CAAC,QAAQ,CAAC;AAC/C,wBAAA,CAAC,CAAC;oBACJ;gBACF,CAAC;AACF,aAAA,CAAC;YAEF,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC,OAAO,EAAE,EAAE;QAC/C;;;;;;QAOA,MAAM,cAAc,GAAG,gBAAgB,CAAC;YACtC,IAAI,EAAE,MAAK;AACT,gBAAA,MAAM,QAAQ,GAAG,SAAS,CAAC,MAAM,CAAC;AAClC,gBAAA,IAAI,QAAQ,IAAI,CAAC,QAAQ,CAAC,WAAW;oBAAE,QAAQ,CAAC,QAAQ,CAAC;YAC3D,CAAC;AACF,SAAA,CAAC;QAEF,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC,OAAO,EAAE,EAAE;AACpD,IAAA,CAAC,CAAC;AACJ;;AC5GA;;AAEG;;;;"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { setupContext, NOOP_EFFECT_REF
|
|
1
|
+
import { setupContext, NOOP_EFFECT_REF } from '@signality/core/internal';
|
|
2
|
+
import { toValue } from '@signality/core/utilities';
|
|
2
3
|
import { listener } from '@signality/core/browser/listener';
|
|
3
4
|
|
|
4
5
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"signality-core-elements-on-long-press.mjs","sources":["../../../projects/core/elements/on-long-press/index.ts","../../../projects/core/elements/on-long-press/signality-core-elements-on-long-press.ts"],"sourcesContent":["import { NOOP_EFFECT_REF, setupContext, type Timer
|
|
1
|
+
{"version":3,"file":"signality-core-elements-on-long-press.mjs","sources":["../../../projects/core/elements/on-long-press/index.ts","../../../projects/core/elements/on-long-press/signality-core-elements-on-long-press.ts"],"sourcesContent":["import { NOOP_EFFECT_REF, setupContext, type Timer } from '@signality/core/internal';\nimport { toValue } from '@signality/core/utilities';\nimport type { MaybeElementSignal, MaybeSignal, WithInjector } from '@signality/core/types';\nimport { listener } from '@signality/core/browser/listener';\n\nexport interface OnLongPressOptions extends WithInjector {\n /**\n * Time in ms before the callback is triggered.\n * @default 500\n */\n readonly delay?: MaybeSignal<number>;\n\n /**\n * Maximum distance (in pixels) the pointer can move before cancelling.\n * Set to `false` to disable distance checking.\n * @default 10\n */\n readonly distanceThreshold?: number | false;\n}\n\nexport interface OnLongPressRef {\n readonly destroy: () => void;\n}\n\n/**\n * Detect long press gestures on an element.\n * Calls a callback after a configurable delay if the pointer stays down\n * without moving beyond the distance threshold.\n *\n * @param target - The element to detect long presses on\n * @param handler - Callback invoked when a long press is detected\n * @param options - Optional configuration including delay, distance threshold, and injector\n * @returns A OnLongPressRef with a destroy method to stop detection\n *\n * @example\n * ```typescript\n * @Component({\n * template: `<button #btn>Hold me</button>`\n * })\n * export class OnLongPressDemo {\n * readonly btn = viewChild<ElementRef>('btn');\n *\n * constructor() {\n * onLongPress(this.btn, () => {\n * console.log('Long press detected!');\n * });\n * }\n * }\n * ```\n */\nexport function onLongPress(\n target: MaybeElementSignal<HTMLElement>,\n handler: (event: PointerEvent) => void,\n options?: OnLongPressOptions\n): OnLongPressRef {\n const { runInContext } = setupContext(options?.injector, onLongPress);\n\n return runInContext(({ isServer, onCleanup }) => {\n if (isServer) {\n return NOOP_EFFECT_REF;\n }\n\n const distanceThreshold = options?.distanceThreshold;\n\n let startX = 0;\n let startY = 0;\n let longPressTimeout: Timer;\n\n function abortPendingPress(): void {\n clearTimeout(longPressTimeout);\n longPressTimeout = undefined;\n }\n\n const downListener = listener(target, 'pointerdown', (e: PointerEvent) => {\n startX = e.clientX;\n startY = e.clientY;\n\n const delay = toValue(options?.delay) ?? 500;\n\n longPressTimeout = setTimeout(() => {\n handler(e);\n longPressTimeout = undefined;\n }, delay);\n });\n\n const moveListener = listener(target, 'pointermove', (e: PointerEvent) => {\n if (!longPressTimeout || distanceThreshold === false) {\n return;\n }\n\n const threshold = distanceThreshold ?? 10;\n const dx = e.clientX - startX;\n const dy = e.clientY - startY;\n\n if (Math.sqrt(dx * dx + dy * dy) > threshold) {\n abortPendingPress();\n }\n });\n\n const upListener = listener(target, 'pointerup', abortPendingPress);\n const leaveListener = listener(target, 'pointerleave', abortPendingPress);\n\n onCleanup(abortPendingPress);\n\n return {\n destroy: () => {\n abortPendingPress();\n upListener.destroy();\n downListener.destroy();\n moveListener.destroy();\n leaveListener.destroy();\n },\n };\n });\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":";;;;AAwBA;;;;;;;;;;;;;;;;;;;;;;;;;AAyBG;SACa,WAAW,CACzB,MAAuC,EACvC,OAAsC,EACtC,OAA4B,EAAA;AAE5B,IAAA,MAAM,EAAE,YAAY,EAAE,GAAG,YAAY,CAAC,OAAO,EAAE,QAAQ,EAAE,WAAW,CAAC;IAErE,OAAO,YAAY,CAAC,CAAC,EAAE,QAAQ,EAAE,SAAS,EAAE,KAAI;QAC9C,IAAI,QAAQ,EAAE;AACZ,YAAA,OAAO,eAAe;QACxB;AAEA,QAAA,MAAM,iBAAiB,GAAG,OAAO,EAAE,iBAAiB;QAEpD,IAAI,MAAM,GAAG,CAAC;QACd,IAAI,MAAM,GAAG,CAAC;AACd,QAAA,IAAI,gBAAuB;AAE3B,QAAA,SAAS,iBAAiB,GAAA;YACxB,YAAY,CAAC,gBAAgB,CAAC;YAC9B,gBAAgB,GAAG,SAAS;QAC9B;QAEA,MAAM,YAAY,GAAG,QAAQ,CAAC,MAAM,EAAE,aAAa,EAAE,CAAC,CAAe,KAAI;AACvE,YAAA,MAAM,GAAG,CAAC,CAAC,OAAO;AAClB,YAAA,MAAM,GAAG,CAAC,CAAC,OAAO;YAElB,MAAM,KAAK,GAAG,OAAO,CAAC,OAAO,EAAE,KAAK,CAAC,IAAI,GAAG;AAE5C,YAAA,gBAAgB,GAAG,UAAU,CAAC,MAAK;gBACjC,OAAO,CAAC,CAAC,CAAC;gBACV,gBAAgB,GAAG,SAAS;YAC9B,CAAC,EAAE,KAAK,CAAC;AACX,QAAA,CAAC,CAAC;QAEF,MAAM,YAAY,GAAG,QAAQ,CAAC,MAAM,EAAE,aAAa,EAAE,CAAC,CAAe,KAAI;AACvE,YAAA,IAAI,CAAC,gBAAgB,IAAI,iBAAiB,KAAK,KAAK,EAAE;gBACpD;YACF;AAEA,YAAA,MAAM,SAAS,GAAG,iBAAiB,IAAI,EAAE;AACzC,YAAA,MAAM,EAAE,GAAG,CAAC,CAAC,OAAO,GAAG,MAAM;AAC7B,YAAA,MAAM,EAAE,GAAG,CAAC,CAAC,OAAO,GAAG,MAAM;AAE7B,YAAA,IAAI,IAAI,CAAC,IAAI,CAAC,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC,GAAG,SAAS,EAAE;AAC5C,gBAAA,iBAAiB,EAAE;YACrB;AACF,QAAA,CAAC,CAAC;QAEF,MAAM,UAAU,GAAG,QAAQ,CAAC,MAAM,EAAE,WAAW,EAAE,iBAAiB,CAAC;QACnE,MAAM,aAAa,GAAG,QAAQ,CAAC,MAAM,EAAE,cAAc,EAAE,iBAAiB,CAAC;QAEzE,SAAS,CAAC,iBAAiB,CAAC;QAE5B,OAAO;YACL,OAAO,EAAE,MAAK;AACZ,gBAAA,iBAAiB,EAAE;gBACnB,UAAU,CAAC,OAAO,EAAE;gBACpB,YAAY,CAAC,OAAO,EAAE;gBACtB,YAAY,CAAC,OAAO,EAAE;gBACtB,aAAa,CAAC,OAAO,EAAE;YACzB,CAAC;SACF;AACH,IAAA,CAAC,CAAC;AACJ;;AClHA;;AAEG;;;;"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { signal } from '@angular/core';
|
|
2
|
-
import { setupContext, constSignal, isWindow
|
|
2
|
+
import { setupContext, constSignal, isWindow } from '@signality/core/internal';
|
|
3
|
+
import { toElement } from '@signality/core/utilities';
|
|
3
4
|
import { throttleCallback } from '@signality/core/scheduling/throttle-callback';
|
|
4
5
|
import { listener } from '@signality/core/browser/listener';
|
|
5
6
|
import { onDisconnect } from '@signality/core/elements/on-disconnect';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"signality-core-elements-scroll-position.mjs","sources":["../../../projects/core/elements/scroll-position/index.ts","../../../projects/core/elements/scroll-position/signality-core-elements-scroll-position.ts"],"sourcesContent":["import { type Signal, signal } from '@angular/core';\nimport {\n constSignal,\n isWindow,\n setupContext,\n type Timer,\n toElement,\n} from '@signality/core/internal';\nimport type { MaybeElementSignal, WithInjector } from '@signality/core/types';\nimport { throttleCallback } from '@signality/core/scheduling/throttle-callback';\nimport { listener } from '@signality/core/browser/listener';\nimport { onDisconnect } from '@signality/core/elements/on-disconnect';\n\n/**\n * State indicating which edges have been reached.\n */\nexport interface ArrivedState {\n readonly top: boolean;\n readonly bottom: boolean;\n readonly left: boolean;\n readonly right: boolean;\n}\n\n/**\n * Current scroll directions.\n */\nexport interface ScrollDirections {\n readonly top: boolean;\n readonly bottom: boolean;\n readonly left: boolean;\n readonly right: boolean;\n}\n\nexport interface ScrollPositionOptions extends WithInjector {\n /**\n * Element or window to track scroll on.\n * @default window\n */\n readonly target?: MaybeElementSignal<Element> | Window;\n\n /**\n * Throttle scroll events in milliseconds.\n * @default 0\n */\n readonly throttle?: number;\n\n /**\n * Offset for arrived detection.\n */\n readonly offset?: {\n readonly top?: number;\n readonly bottom?: number;\n readonly left?: number;\n readonly right?: number;\n };\n}\n\nexport interface ScrollPositionRef {\n /** Horizontal scroll position */\n readonly x: Signal<number>;\n\n /** Vertical scroll position */\n readonly y: Signal<number>;\n\n /** Whether currently scrolling */\n readonly isScrolling: Signal<boolean>;\n\n /** Which edges have been reached */\n readonly arrivedState: Signal<ArrivedState>;\n\n /** Current scroll direction */\n readonly directions: Signal<ScrollDirections>;\n}\n\n/**\n * Reactive tracking of scroll position.\n * Track scroll offset of window or any scrollable element.\n *\n * @param options - Optional configuration\n * @returns An object with x, y, isScrolling, arrivedState, and directions signals\n *\n * @example\n * ```typescript\n * @Component({\n * template: `\n * <p>Scroll Y: {{ scrollPos.y() }}px</p>\n * @if (scrollPos.isScrolling()) {\n * <p>Scrolling...</p>\n * }\n * @if (scrollPos.arrivedState().bottom) {\n * <p>Reached bottom!</p>\n * }\n * `\n * })\n * export class ScrollTracker {\n * readonly scrollPos = scrollPosition();\n * }\n * ```\n *\n * @example\n * ```typescript\n * // Track scroll on a specific element\n * @Component({\n * template: `\n * <div #scrollable style=\"overflow: auto; height: 200px;\">\n * <div style=\"height: 1000px;\">Long content</div>\n * </div>\n * <p>Scroll position: {{ pos.y() }}</p>\n * `\n * })\n * export class ScrollableComponent {\n * readonly scrollableEl = viewChild<ElementRef>('scrollable');\n * readonly pos = scrollPosition({ target: this.scrollableEl });\n * }\n * ```\n */\nexport function scrollPosition(options?: ScrollPositionOptions): ScrollPositionRef {\n const { runInContext } = setupContext(options?.injector, scrollPosition);\n\n return runInContext(({ isServer, onCleanup }) => {\n if (isServer) {\n return {\n x: constSignal(0),\n y: constSignal(0),\n isScrolling: constSignal(false),\n arrivedState: constSignal(DEFAULT_ARRIVED),\n directions: constSignal(DEFAULT_DIRECTIONS),\n };\n }\n\n const target = options?.target ?? window;\n const targetIsWindow = isWindow(target);\n const offset = options?.offset ?? {};\n const throttleMs = options?.throttle ?? 0;\n\n const x = signal(0);\n const y = signal(0);\n const isScrolling = signal(false);\n const arrivedState = signal(DEFAULT_ARRIVED);\n const directions = signal(DEFAULT_DIRECTIONS);\n\n let lastX = 0;\n let lastY = 0;\n let scrollingTimeout: Timer;\n\n const getScrollPosition = (): { scrollX: number; scrollY: number } => {\n if (targetIsWindow) {\n return { scrollX: target.scrollX, scrollY: target.scrollY };\n }\n\n const el = toElement(target);\n return {\n scrollX: el?.scrollLeft || 0,\n scrollY: el?.scrollTop || 0,\n };\n };\n\n const getScrollSize = (): {\n scrollWidth: number;\n scrollHeight: number;\n clientWidth: number;\n clientHeight: number;\n } => {\n if (targetIsWindow) {\n return {\n scrollWidth: document.documentElement.scrollWidth,\n scrollHeight: document.documentElement.scrollHeight,\n clientWidth: target.innerWidth,\n clientHeight: target.innerHeight,\n };\n }\n\n const el = toElement(target);\n return {\n scrollWidth: el?.scrollWidth || 0,\n scrollHeight: el?.scrollHeight || 0,\n clientWidth: el?.clientWidth || 0,\n clientHeight: el?.clientHeight || 0,\n };\n };\n\n const update = () => {\n const { scrollX, scrollY } = getScrollPosition();\n const { scrollWidth, scrollHeight, clientWidth, clientHeight } = getScrollSize();\n\n directions.set({\n top: scrollY < lastY,\n bottom: scrollY > lastY,\n left: scrollX < lastX,\n right: scrollX > lastX,\n });\n\n lastX = scrollX;\n lastY = scrollY;\n\n x.set(scrollX);\n y.set(scrollY);\n\n const topOffset = offset.top ?? 0;\n const bottomOffset = offset.bottom ?? 0;\n const leftOffset = offset.left ?? 0;\n const rightOffset = offset.right ?? 0;\n\n arrivedState.set({\n top: scrollY <= topOffset,\n bottom: scrollY + clientHeight >= scrollHeight - bottomOffset,\n left: scrollX <= leftOffset,\n right: scrollX + clientWidth >= scrollWidth - rightOffset,\n });\n\n isScrolling.set(true);\n\n if (scrollingTimeout) {\n clearTimeout(scrollingTimeout);\n }\n\n scrollingTimeout = setTimeout(() => {\n isScrolling.set(false);\n }, SCROLL_IDLE_DELAY);\n };\n\n listener(target, 'scroll', throttleMs > 0 ? throttleCallback(update, throttleMs) : update);\n\n if (!targetIsWindow) {\n onDisconnect(target, () => {\n x.set(0);\n y.set(0);\n isScrolling.set(false);\n arrivedState.set(DEFAULT_ARRIVED);\n directions.set(DEFAULT_DIRECTIONS);\n });\n }\n\n onCleanup(() => {\n if (scrollingTimeout) {\n clearTimeout(scrollingTimeout);\n }\n });\n\n update();\n\n return {\n x: x.asReadonly(),\n y: y.asReadonly(),\n isScrolling: isScrolling.asReadonly(),\n arrivedState: arrivedState.asReadonly(),\n directions: directions.asReadonly(),\n };\n });\n}\n\nconst DEFAULT_ARRIVED: ArrivedState = {\n top: true,\n bottom: false,\n left: true,\n right: false,\n};\n\nconst DEFAULT_DIRECTIONS: ScrollDirections = {\n top: false,\n bottom: false,\n left: false,\n right: false,\n};\n\nconst SCROLL_IDLE_DELAY = 150;\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":";;;;;;AA0EA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAyCG;AACG,SAAU,cAAc,CAAC,OAA+B,EAAA;AAC5D,IAAA,MAAM,EAAE,YAAY,EAAE,GAAG,YAAY,CAAC,OAAO,EAAE,QAAQ,EAAE,cAAc,CAAC;IAExE,OAAO,YAAY,CAAC,CAAC,EAAE,QAAQ,EAAE,SAAS,EAAE,KAAI;QAC9C,IAAI,QAAQ,EAAE;YACZ,OAAO;AACL,gBAAA,CAAC,EAAE,WAAW,CAAC,CAAC,CAAC;AACjB,gBAAA,CAAC,EAAE,WAAW,CAAC,CAAC,CAAC;AACjB,gBAAA,WAAW,EAAE,WAAW,CAAC,KAAK,CAAC;AAC/B,gBAAA,YAAY,EAAE,WAAW,CAAC,eAAe,CAAC;AAC1C,gBAAA,UAAU,EAAE,WAAW,CAAC,kBAAkB,CAAC;aAC5C;QACH;AAEA,QAAA,MAAM,MAAM,GAAG,OAAO,EAAE,MAAM,IAAI,MAAM;AACxC,QAAA,MAAM,cAAc,GAAG,QAAQ,CAAC,MAAM,CAAC;AACvC,QAAA,MAAM,MAAM,GAAG,OAAO,EAAE,MAAM,IAAI,EAAE;AACpC,QAAA,MAAM,UAAU,GAAG,OAAO,EAAE,QAAQ,IAAI,CAAC;AAEzC,QAAA,MAAM,CAAC,GAAG,MAAM,CAAC,CAAC,6CAAC;AACnB,QAAA,MAAM,CAAC,GAAG,MAAM,CAAC,CAAC,6CAAC;AACnB,QAAA,MAAM,WAAW,GAAG,MAAM,CAAC,KAAK,uDAAC;AACjC,QAAA,MAAM,YAAY,GAAG,MAAM,CAAC,eAAe,wDAAC;AAC5C,QAAA,MAAM,UAAU,GAAG,MAAM,CAAC,kBAAkB,sDAAC;QAE7C,IAAI,KAAK,GAAG,CAAC;QACb,IAAI,KAAK,GAAG,CAAC;AACb,QAAA,IAAI,gBAAuB;QAE3B,MAAM,iBAAiB,GAAG,MAA2C;YACnE,IAAI,cAAc,EAAE;AAClB,gBAAA,OAAO,EAAE,OAAO,EAAE,MAAM,CAAC,OAAO,EAAE,OAAO,EAAE,MAAM,CAAC,OAAO,EAAE;YAC7D;AAEA,YAAA,MAAM,EAAE,GAAG,SAAS,CAAC,MAAM,CAAC;YAC5B,OAAO;AACL,gBAAA,OAAO,EAAE,EAAE,EAAE,UAAU,IAAI,CAAC;AAC5B,gBAAA,OAAO,EAAE,EAAE,EAAE,SAAS,IAAI,CAAC;aAC5B;AACH,QAAA,CAAC;QAED,MAAM,aAAa,GAAG,MAKlB;YACF,IAAI,cAAc,EAAE;gBAClB,OAAO;AACL,oBAAA,WAAW,EAAE,QAAQ,CAAC,eAAe,CAAC,WAAW;AACjD,oBAAA,YAAY,EAAE,QAAQ,CAAC,eAAe,CAAC,YAAY;oBACnD,WAAW,EAAE,MAAM,CAAC,UAAU;oBAC9B,YAAY,EAAE,MAAM,CAAC,WAAW;iBACjC;YACH;AAEA,YAAA,MAAM,EAAE,GAAG,SAAS,CAAC,MAAM,CAAC;YAC5B,OAAO;AACL,gBAAA,WAAW,EAAE,EAAE,EAAE,WAAW,IAAI,CAAC;AACjC,gBAAA,YAAY,EAAE,EAAE,EAAE,YAAY,IAAI,CAAC;AACnC,gBAAA,WAAW,EAAE,EAAE,EAAE,WAAW,IAAI,CAAC;AACjC,gBAAA,YAAY,EAAE,EAAE,EAAE,YAAY,IAAI,CAAC;aACpC;AACH,QAAA,CAAC;QAED,MAAM,MAAM,GAAG,MAAK;YAClB,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,GAAG,iBAAiB,EAAE;AAChD,YAAA,MAAM,EAAE,WAAW,EAAE,YAAY,EAAE,WAAW,EAAE,YAAY,EAAE,GAAG,aAAa,EAAE;YAEhF,UAAU,CAAC,GAAG,CAAC;gBACb,GAAG,EAAE,OAAO,GAAG,KAAK;gBACpB,MAAM,EAAE,OAAO,GAAG,KAAK;gBACvB,IAAI,EAAE,OAAO,GAAG,KAAK;gBACrB,KAAK,EAAE,OAAO,GAAG,KAAK;AACvB,aAAA,CAAC;YAEF,KAAK,GAAG,OAAO;YACf,KAAK,GAAG,OAAO;AAEf,YAAA,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC;AACd,YAAA,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC;AAEd,YAAA,MAAM,SAAS,GAAG,MAAM,CAAC,GAAG,IAAI,CAAC;AACjC,YAAA,MAAM,YAAY,GAAG,MAAM,CAAC,MAAM,IAAI,CAAC;AACvC,YAAA,MAAM,UAAU,GAAG,MAAM,CAAC,IAAI,IAAI,CAAC;AACnC,YAAA,MAAM,WAAW,GAAG,MAAM,CAAC,KAAK,IAAI,CAAC;YAErC,YAAY,CAAC,GAAG,CAAC;gBACf,GAAG,EAAE,OAAO,IAAI,SAAS;AACzB,gBAAA,MAAM,EAAE,OAAO,GAAG,YAAY,IAAI,YAAY,GAAG,YAAY;gBAC7D,IAAI,EAAE,OAAO,IAAI,UAAU;AAC3B,gBAAA,KAAK,EAAE,OAAO,GAAG,WAAW,IAAI,WAAW,GAAG,WAAW;AAC1D,aAAA,CAAC;AAEF,YAAA,WAAW,CAAC,GAAG,CAAC,IAAI,CAAC;YAErB,IAAI,gBAAgB,EAAE;gBACpB,YAAY,CAAC,gBAAgB,CAAC;YAChC;AAEA,YAAA,gBAAgB,GAAG,UAAU,CAAC,MAAK;AACjC,gBAAA,WAAW,CAAC,GAAG,CAAC,KAAK,CAAC;YACxB,CAAC,EAAE,iBAAiB,CAAC;AACvB,QAAA,CAAC;QAED,QAAQ,CAAC,MAAM,EAAE,QAAQ,EAAE,UAAU,GAAG,CAAC,GAAG,gBAAgB,CAAC,MAAM,EAAE,UAAU,CAAC,GAAG,MAAM,CAAC;QAE1F,IAAI,CAAC,cAAc,EAAE;AACnB,YAAA,YAAY,CAAC,MAAM,EAAE,MAAK;AACxB,gBAAA,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;AACR,gBAAA,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;AACR,gBAAA,WAAW,CAAC,GAAG,CAAC,KAAK,CAAC;AACtB,gBAAA,YAAY,CAAC,GAAG,CAAC,eAAe,CAAC;AACjC,gBAAA,UAAU,CAAC,GAAG,CAAC,kBAAkB,CAAC;AACpC,YAAA,CAAC,CAAC;QACJ;QAEA,SAAS,CAAC,MAAK;YACb,IAAI,gBAAgB,EAAE;gBACpB,YAAY,CAAC,gBAAgB,CAAC;YAChC;AACF,QAAA,CAAC,CAAC;AAEF,QAAA,MAAM,EAAE;QAER,OAAO;AACL,YAAA,CAAC,EAAE,CAAC,CAAC,UAAU,EAAE;AACjB,YAAA,CAAC,EAAE,CAAC,CAAC,UAAU,EAAE;AACjB,YAAA,WAAW,EAAE,WAAW,CAAC,UAAU,EAAE;AACrC,YAAA,YAAY,EAAE,YAAY,CAAC,UAAU,EAAE;AACvC,YAAA,UAAU,EAAE,UAAU,CAAC,UAAU,EAAE;SACpC;AACH,IAAA,CAAC,CAAC;AACJ;AAEA,MAAM,eAAe,GAAiB;AACpC,IAAA,GAAG,EAAE,IAAI;AACT,IAAA,MAAM,EAAE,KAAK;AACb,IAAA,IAAI,EAAE,IAAI;AACV,IAAA,KAAK,EAAE,KAAK;CACb;AAED,MAAM,kBAAkB,GAAqB;AAC3C,IAAA,GAAG,EAAE,KAAK;AACV,IAAA,MAAM,EAAE,KAAK;AACb,IAAA,IAAI,EAAE,KAAK;AACX,IAAA,KAAK,EAAE,KAAK;CACb;AAED,MAAM,iBAAiB,GAAG,GAAG;;ACzQ7B;;AAEG;;;;"}
|
|
1
|
+
{"version":3,"file":"signality-core-elements-scroll-position.mjs","sources":["../../../projects/core/elements/scroll-position/index.ts","../../../projects/core/elements/scroll-position/signality-core-elements-scroll-position.ts"],"sourcesContent":["import { type Signal, signal } from '@angular/core';\nimport { constSignal, isWindow, setupContext, type Timer } from '@signality/core/internal';\nimport { toElement } from '@signality/core/utilities';\nimport type { MaybeElementSignal, WithInjector } from '@signality/core/types';\nimport { throttleCallback } from '@signality/core/scheduling/throttle-callback';\nimport { listener } from '@signality/core/browser/listener';\nimport { onDisconnect } from '@signality/core/elements/on-disconnect';\n\n/**\n * State indicating which edges have been reached.\n */\nexport interface ArrivedState {\n readonly top: boolean;\n readonly bottom: boolean;\n readonly left: boolean;\n readonly right: boolean;\n}\n\n/**\n * Current scroll directions.\n */\nexport interface ScrollDirections {\n readonly top: boolean;\n readonly bottom: boolean;\n readonly left: boolean;\n readonly right: boolean;\n}\n\nexport interface ScrollPositionOptions extends WithInjector {\n /**\n * Element or window to track scroll on.\n * @default window\n */\n readonly target?: MaybeElementSignal<Element> | Window;\n\n /**\n * Throttle scroll events in milliseconds.\n * @default 0\n */\n readonly throttle?: number;\n\n /**\n * Offset for arrived detection.\n */\n readonly offset?: {\n readonly top?: number;\n readonly bottom?: number;\n readonly left?: number;\n readonly right?: number;\n };\n}\n\nexport interface ScrollPositionRef {\n /** Horizontal scroll position */\n readonly x: Signal<number>;\n\n /** Vertical scroll position */\n readonly y: Signal<number>;\n\n /** Whether currently scrolling */\n readonly isScrolling: Signal<boolean>;\n\n /** Which edges have been reached */\n readonly arrivedState: Signal<ArrivedState>;\n\n /** Current scroll direction */\n readonly directions: Signal<ScrollDirections>;\n}\n\n/**\n * Reactive tracking of scroll position.\n * Track scroll offset of window or any scrollable element.\n *\n * @param options - Optional configuration\n * @returns An object with x, y, isScrolling, arrivedState, and directions signals\n *\n * @example\n * ```typescript\n * @Component({\n * template: `\n * <p>Scroll Y: {{ scrollPos.y() }}px</p>\n * @if (scrollPos.isScrolling()) {\n * <p>Scrolling...</p>\n * }\n * @if (scrollPos.arrivedState().bottom) {\n * <p>Reached bottom!</p>\n * }\n * `\n * })\n * export class ScrollTracker {\n * readonly scrollPos = scrollPosition();\n * }\n * ```\n *\n * @example\n * ```typescript\n * // Track scroll on a specific element\n * @Component({\n * template: `\n * <div #scrollable style=\"overflow: auto; height: 200px;\">\n * <div style=\"height: 1000px;\">Long content</div>\n * </div>\n * <p>Scroll position: {{ pos.y() }}</p>\n * `\n * })\n * export class ScrollableComponent {\n * readonly scrollableEl = viewChild<ElementRef>('scrollable');\n * readonly pos = scrollPosition({ target: this.scrollableEl });\n * }\n * ```\n */\nexport function scrollPosition(options?: ScrollPositionOptions): ScrollPositionRef {\n const { runInContext } = setupContext(options?.injector, scrollPosition);\n\n return runInContext(({ isServer, onCleanup }) => {\n if (isServer) {\n return {\n x: constSignal(0),\n y: constSignal(0),\n isScrolling: constSignal(false),\n arrivedState: constSignal(DEFAULT_ARRIVED),\n directions: constSignal(DEFAULT_DIRECTIONS),\n };\n }\n\n const target = options?.target ?? window;\n const targetIsWindow = isWindow(target);\n const offset = options?.offset ?? {};\n const throttleMs = options?.throttle ?? 0;\n\n const x = signal(0);\n const y = signal(0);\n const isScrolling = signal(false);\n const arrivedState = signal(DEFAULT_ARRIVED);\n const directions = signal(DEFAULT_DIRECTIONS);\n\n let lastX = 0;\n let lastY = 0;\n let scrollingTimeout: Timer;\n\n const getScrollPosition = (): { scrollX: number; scrollY: number } => {\n if (targetIsWindow) {\n return { scrollX: target.scrollX, scrollY: target.scrollY };\n }\n\n const el = toElement(target);\n return {\n scrollX: el?.scrollLeft || 0,\n scrollY: el?.scrollTop || 0,\n };\n };\n\n const getScrollSize = (): {\n scrollWidth: number;\n scrollHeight: number;\n clientWidth: number;\n clientHeight: number;\n } => {\n if (targetIsWindow) {\n return {\n scrollWidth: document.documentElement.scrollWidth,\n scrollHeight: document.documentElement.scrollHeight,\n clientWidth: target.innerWidth,\n clientHeight: target.innerHeight,\n };\n }\n\n const el = toElement(target);\n return {\n scrollWidth: el?.scrollWidth || 0,\n scrollHeight: el?.scrollHeight || 0,\n clientWidth: el?.clientWidth || 0,\n clientHeight: el?.clientHeight || 0,\n };\n };\n\n const update = () => {\n const { scrollX, scrollY } = getScrollPosition();\n const { scrollWidth, scrollHeight, clientWidth, clientHeight } = getScrollSize();\n\n directions.set({\n top: scrollY < lastY,\n bottom: scrollY > lastY,\n left: scrollX < lastX,\n right: scrollX > lastX,\n });\n\n lastX = scrollX;\n lastY = scrollY;\n\n x.set(scrollX);\n y.set(scrollY);\n\n const topOffset = offset.top ?? 0;\n const bottomOffset = offset.bottom ?? 0;\n const leftOffset = offset.left ?? 0;\n const rightOffset = offset.right ?? 0;\n\n arrivedState.set({\n top: scrollY <= topOffset,\n bottom: scrollY + clientHeight >= scrollHeight - bottomOffset,\n left: scrollX <= leftOffset,\n right: scrollX + clientWidth >= scrollWidth - rightOffset,\n });\n\n isScrolling.set(true);\n\n if (scrollingTimeout) {\n clearTimeout(scrollingTimeout);\n }\n\n scrollingTimeout = setTimeout(() => {\n isScrolling.set(false);\n }, SCROLL_IDLE_DELAY);\n };\n\n listener(target, 'scroll', throttleMs > 0 ? throttleCallback(update, throttleMs) : update);\n\n if (!targetIsWindow) {\n onDisconnect(target, () => {\n x.set(0);\n y.set(0);\n isScrolling.set(false);\n arrivedState.set(DEFAULT_ARRIVED);\n directions.set(DEFAULT_DIRECTIONS);\n });\n }\n\n onCleanup(() => {\n if (scrollingTimeout) {\n clearTimeout(scrollingTimeout);\n }\n });\n\n update();\n\n return {\n x: x.asReadonly(),\n y: y.asReadonly(),\n isScrolling: isScrolling.asReadonly(),\n arrivedState: arrivedState.asReadonly(),\n directions: directions.asReadonly(),\n };\n });\n}\n\nconst DEFAULT_ARRIVED: ArrivedState = {\n top: true,\n bottom: false,\n left: true,\n right: false,\n};\n\nconst DEFAULT_DIRECTIONS: ScrollDirections = {\n top: false,\n bottom: false,\n left: false,\n right: false,\n};\n\nconst SCROLL_IDLE_DELAY = 150;\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}
|
|
@@ -2,7 +2,7 @@ import { inject, signal, afterNextRender } from '@angular/core';
|
|
|
2
2
|
import { NgControl, RequiredValidator, Validators, NgModel } from '@angular/forms';
|
|
3
3
|
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
|
4
4
|
import { timer, switchMap, EMPTY, startWith, map } from 'rxjs';
|
|
5
|
-
import { setupContext, ALWAYS_FALSE_FN } from '@signality/core/internal';
|
|
5
|
+
import { setupContext, ALWAYS_FALSE_FN, waitForValue } from '@signality/core/internal';
|
|
6
6
|
import { watcher } from '@signality/core/reactivity/watcher';
|
|
7
7
|
|
|
8
8
|
/**
|
|
@@ -50,13 +50,14 @@ function cva(options) {
|
|
|
50
50
|
return runInContext(({ injector }) => {
|
|
51
51
|
const ngControl = inject(NgControl, { self: true, optional: true });
|
|
52
52
|
const ngModelRequired = inject(RequiredValidator, { self: true, optional: true });
|
|
53
|
-
const initialValue = options.value();
|
|
54
53
|
const { value,
|
|
55
54
|
// Use ALWAYS_FALSE_FN to ensure touched signal always triggers watcher updates.
|
|
56
55
|
// This is critical for controls with `updateOn: 'blur'` - when blur occurs, the control
|
|
57
56
|
// may update its value, but control.touched remains true. Without forcing signal updates,
|
|
58
57
|
// the watcher won't fire and the control won't properly synchronize its value after blur.
|
|
59
58
|
touched = signal(false, { equal: ALWAYS_FALSE_FN }), disabled = signal(false), required = signal(false), invalid = signal(false), pending = signal(false), dirty = signal(false), errors = signal(null), } = options;
|
|
59
|
+
let initialValue = UNSET_VALUE;
|
|
60
|
+
waitForValue(value).then(val => (initialValue = val));
|
|
60
61
|
const cvaRef = {
|
|
61
62
|
value,
|
|
62
63
|
touched,
|
|
@@ -66,7 +67,15 @@ function cva(options) {
|
|
|
66
67
|
pending: pending.asReadonly(),
|
|
67
68
|
dirty: dirty.asReadonly(),
|
|
68
69
|
errors: errors.asReadonly(),
|
|
69
|
-
reset: () =>
|
|
70
|
+
reset: () => {
|
|
71
|
+
if (initialValue === UNSET_VALUE) {
|
|
72
|
+
throw new Error(ngDevMode
|
|
73
|
+
? '[cva] Cannot reset before the initial value is resolved. ' +
|
|
74
|
+
'Avoid calling `reset()` synchronously during initialization.'
|
|
75
|
+
: '');
|
|
76
|
+
}
|
|
77
|
+
value.set(initialValue);
|
|
78
|
+
},
|
|
70
79
|
};
|
|
71
80
|
if (!ngControl) {
|
|
72
81
|
return cvaRef;
|
|
@@ -131,6 +140,7 @@ function cva(options) {
|
|
|
131
140
|
return cvaRef;
|
|
132
141
|
});
|
|
133
142
|
}
|
|
143
|
+
const UNSET_VALUE = Symbol('Cva#UNSET');
|
|
134
144
|
|
|
135
145
|
/**
|
|
136
146
|
* Generated bundle index. Do not edit.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"signality-core-forms-cva.mjs","sources":["../../../projects/core/forms/cva/index.ts","../../../projects/core/forms/cva/signality-core-forms-cva.ts"],"sourcesContent":["import {\n afterNextRender,\n type AfterRenderRef,\n inject,\n type Signal,\n signal,\n type WritableSignal,\n} from '@angular/core';\nimport {\n NgControl,\n NgModel,\n RequiredValidator,\n type ValidationErrors,\n Validators,\n} from '@angular/forms';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\nimport { EMPTY, map, startWith, switchMap, timer } from 'rxjs';\nimport { ALWAYS_FALSE_FN, setupContext } from '@signality/core/internal';\nimport type { WithInjector } from '@signality/core/types';\nimport { watcher } from '@signality/core/reactivity/watcher';\n\nexport type CvaOptions<T> = Omit<Partial<MakeWritable<CvaRef<T>>>, 'value'> &\n Pick<CvaRef<T>, 'value'> &\n WithInjector;\n\nexport interface CvaRef<T> {\n readonly value: WritableSignal<T>;\n readonly touched: WritableSignal<boolean>;\n readonly disabled: Signal<boolean>;\n readonly required: Signal<boolean>;\n readonly invalid: Signal<boolean>;\n readonly pending: Signal<boolean>;\n readonly dirty: Signal<boolean>;\n readonly errors: Signal<ValidationErrors | null>;\n readonly reset: () => void;\n}\n\n/**\n * Reactive wrapper around the [Angular Forms](https://angular.dev/guide/forms) Control Value Accessor (CVA) pattern.\n * Integrates seamlessly with both template-driven and reactive forms.\n *\n * @param options - Configuration options including the value signal\n * @returns A CvaRef with reactive form control state signals\n *\n * @example\n * ```typescript\n * @Component({\n * selector: 'app-currency-input',\n * template: `\n * <input\n * type=\"text\"\n * [value]=\"displayValue()\"\n * [required]=\"cva.required()\"\n * (input)=\"handleInput($any($event.target).value)\"\n * (blur)=\"cva.touched.set(true)\"\n * />\n * `,\n * })\n * export class CurrencyInput {\n * readonly value = model(0);\n * readonly cva = cva({ value: this.value });\n *\n * readonly displayValue = computed(() => {\n * return this.value()\n * .toFixed(2)\n * .replace(/\\B(?=(\\d{3})+(?!\\d))/g, ','); // Shows \"1,234.56\"\n * });\n *\n * handleInput(input: string) {\n * const num = parseFloat(input.replace(/[^0-9.]/g, ''));\n * if (!isNaN(num)) {\n * this.value.set(num);\n * }\n * }\n * }\n * ```\n */\nexport function cva<T>(options: CvaOptions<T>): CvaRef<T> {\n const { runInContext } = setupContext(options?.injector, cva);\n\n return runInContext(({ injector }) => {\n const ngControl = inject(NgControl, { self: true, optional: true });\n const ngModelRequired = inject(RequiredValidator, { self: true, optional: true });\n\n const initialValue = options.value();\n\n const {\n value,\n // Use ALWAYS_FALSE_FN to ensure touched signal always triggers watcher updates.\n // This is critical for controls with `updateOn: 'blur'` - when blur occurs, the control\n // may update its value, but control.touched remains true. Without forcing signal updates,\n // the watcher won't fire and the control won't properly synchronize its value after blur.\n touched = signal(false, { equal: ALWAYS_FALSE_FN }),\n disabled = signal(false),\n required = signal(false),\n invalid = signal(false),\n pending = signal(false),\n dirty = signal(false),\n errors = signal(null),\n } = options;\n\n const cvaRef: CvaRef<T> = {\n value,\n touched,\n disabled: disabled.asReadonly(),\n required: required.asReadonly(),\n invalid: invalid.asReadonly(),\n pending: pending.asReadonly(),\n dirty: dirty.asReadonly(),\n errors: errors.asReadonly(),\n reset: () => value.set(initialValue),\n };\n\n if (!ngControl) {\n return cvaRef;\n }\n\n let touchedFn: () => void;\n let updateFn: (v: T) => void;\n let scheduledModelUpdate: AfterRenderRef | null;\n\n const runModelUpdate = (fn: () => void) => {\n scheduledModelUpdate?.destroy();\n\n fn();\n\n scheduledModelUpdate = afterNextRender(\n () => {\n scheduledModelUpdate = null;\n },\n { injector }\n );\n };\n\n watcher(touched, isTouched => {\n if (isTouched) {\n touchedFn?.();\n }\n });\n\n watcher(value, v => {\n if (scheduledModelUpdate) {\n scheduledModelUpdate.destroy();\n scheduledModelUpdate = null;\n } else {\n updateFn?.(v);\n }\n });\n\n // the control instance isn't available immediately inside FormControl or FormControlName,\n // because they depend on [inputs]. That's why we schedule the subscription asynchronously.\n timer(0)\n .pipe(\n switchMap(() => {\n const { control } = ngControl;\n\n if (!control) {\n return EMPTY;\n }\n\n return control.events.pipe(\n startWith(null),\n map(() => control)\n );\n }),\n takeUntilDestroyed()\n )\n .subscribe(control => {\n required.set(\n control.hasValidator(Validators.required) ||\n // cannot compare references because `RequiredValidator` wraps `requiredValidator` fn\n // (https://github.com/angular/angular/blob/19.1.0/packages/forms/src/directives/validators.ts#L398)\n !!ngModelRequired?.required\n );\n touched.set(control.touched);\n invalid.set(control.invalid);\n pending.set(control.pending);\n errors.set(control.errors);\n dirty.set(control.dirty);\n });\n\n ngControl.valueAccessor = {\n writeValue: (rawValue: T | null) => {\n runModelUpdate(() => {\n // fix (https://github.com/angular/angular/issues/14988)\n const modelValue = ngControl instanceof NgModel ? ngControl.model : rawValue;\n value.set(modelValue);\n });\n },\n registerOnChange: fn => (updateFn = fn),\n registerOnTouched: fn => (touchedFn = fn),\n setDisabledState: isDisabled => disabled?.set(isDisabled),\n };\n\n return cvaRef;\n });\n}\n\ntype MakeWritable<T extends object> = {\n [K in keyof T]: T[K] extends Signal<infer U> ? WritableSignal<U> : never;\n};\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"signality-core-forms-cva.mjs","sources":["../../../projects/core/forms/cva/index.ts","../../../projects/core/forms/cva/signality-core-forms-cva.ts"],"sourcesContent":["import {\n afterNextRender,\n type AfterRenderRef,\n inject,\n type Signal,\n signal,\n type WritableSignal,\n} from '@angular/core';\nimport {\n NgControl,\n NgModel,\n RequiredValidator,\n type ValidationErrors,\n Validators,\n} from '@angular/forms';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\nimport { EMPTY, map, startWith, switchMap, timer } from 'rxjs';\nimport { ALWAYS_FALSE_FN, setupContext, waitForValue } from '@signality/core/internal';\nimport type { WithInjector } from '@signality/core/types';\nimport { watcher } from '@signality/core/reactivity/watcher';\n\nexport interface CvaOptions<T> extends WithInjector {\n readonly value: WritableSignal<T>;\n readonly touched?: WritableSignal<boolean>;\n readonly disabled?: WritableSignal<boolean>;\n readonly required?: WritableSignal<boolean>;\n readonly invalid?: WritableSignal<boolean>;\n readonly pending?: WritableSignal<boolean>;\n readonly dirty?: WritableSignal<boolean>;\n readonly errors?: WritableSignal<ValidationErrors | null>;\n}\n\nexport interface CvaRef<T> {\n readonly value: WritableSignal<T>;\n readonly touched: WritableSignal<boolean>;\n readonly disabled: Signal<boolean>;\n readonly required: Signal<boolean>;\n readonly invalid: Signal<boolean>;\n readonly pending: Signal<boolean>;\n readonly dirty: Signal<boolean>;\n readonly errors: Signal<ValidationErrors | null>;\n readonly reset: () => void;\n}\n\n/**\n * Reactive wrapper around the [Angular Forms](https://angular.dev/guide/forms) Control Value Accessor (CVA) pattern.\n * Integrates seamlessly with both template-driven and reactive forms.\n *\n * @param options - Configuration options including the value signal\n * @returns A CvaRef with reactive form control state signals\n *\n * @example\n * ```typescript\n * @Component({\n * selector: 'app-currency-input',\n * template: `\n * <input\n * type=\"text\"\n * [value]=\"displayValue()\"\n * [required]=\"cva.required()\"\n * (input)=\"handleInput($any($event.target).value)\"\n * (blur)=\"cva.touched.set(true)\"\n * />\n * `,\n * })\n * export class CurrencyInput {\n * readonly value = model(0);\n * readonly cva = cva({ value: this.value });\n *\n * readonly displayValue = computed(() => {\n * return this.value()\n * .toFixed(2)\n * .replace(/\\B(?=(\\d{3})+(?!\\d))/g, ','); // Shows \"1,234.56\"\n * });\n *\n * handleInput(input: string) {\n * const num = parseFloat(input.replace(/[^0-9.]/g, ''));\n * if (!isNaN(num)) {\n * this.value.set(num);\n * }\n * }\n * }\n * ```\n */\nexport function cva<T>(options: CvaOptions<T>): CvaRef<T> {\n const { runInContext } = setupContext(options?.injector, cva);\n\n return runInContext(({ injector }) => {\n const ngControl = inject(NgControl, { self: true, optional: true });\n const ngModelRequired = inject(RequiredValidator, { self: true, optional: true });\n\n const {\n value,\n // Use ALWAYS_FALSE_FN to ensure touched signal always triggers watcher updates.\n // This is critical for controls with `updateOn: 'blur'` - when blur occurs, the control\n // may update its value, but control.touched remains true. Without forcing signal updates,\n // the watcher won't fire and the control won't properly synchronize its value after blur.\n touched = signal(false, { equal: ALWAYS_FALSE_FN }),\n disabled = signal(false),\n required = signal(false),\n invalid = signal(false),\n pending = signal(false),\n dirty = signal(false),\n errors = signal(null),\n } = options;\n\n let initialValue: T = UNSET_VALUE as never;\n\n waitForValue(value).then(val => (initialValue = val));\n\n const cvaRef: CvaRef<T> = {\n value,\n touched,\n disabled: disabled.asReadonly(),\n required: required.asReadonly(),\n invalid: invalid.asReadonly(),\n pending: pending.asReadonly(),\n dirty: dirty.asReadonly(),\n errors: errors.asReadonly(),\n reset: () => {\n if (initialValue === UNSET_VALUE) {\n throw new Error(\n ngDevMode\n ? '[cva] Cannot reset before the initial value is resolved. ' +\n 'Avoid calling `reset()` synchronously during initialization.'\n : ''\n );\n }\n value.set(initialValue);\n },\n };\n\n if (!ngControl) {\n return cvaRef;\n }\n\n let touchedFn: () => void;\n let updateFn: (v: T) => void;\n let scheduledModelUpdate: AfterRenderRef | null;\n\n const runModelUpdate = (fn: () => void) => {\n scheduledModelUpdate?.destroy();\n\n fn();\n\n scheduledModelUpdate = afterNextRender(\n () => {\n scheduledModelUpdate = null;\n },\n { injector }\n );\n };\n\n watcher(touched, isTouched => {\n if (isTouched) {\n touchedFn?.();\n }\n });\n\n watcher(value, v => {\n if (scheduledModelUpdate) {\n scheduledModelUpdate.destroy();\n scheduledModelUpdate = null;\n } else {\n updateFn?.(v);\n }\n });\n\n // the control instance isn't available immediately inside FormControl or FormControlName,\n // because they depend on [inputs]. That's why we schedule the subscription asynchronously.\n timer(0)\n .pipe(\n switchMap(() => {\n const { control } = ngControl;\n\n if (!control) {\n return EMPTY;\n }\n\n return control.events.pipe(\n startWith(null),\n map(() => control)\n );\n }),\n takeUntilDestroyed()\n )\n .subscribe(control => {\n required.set(\n control.hasValidator(Validators.required) ||\n // cannot compare references because `RequiredValidator` wraps `requiredValidator` fn\n // (https://github.com/angular/angular/blob/19.1.0/packages/forms/src/directives/validators.ts#L398)\n !!ngModelRequired?.required\n );\n touched.set(control.touched);\n invalid.set(control.invalid);\n pending.set(control.pending);\n errors.set(control.errors);\n dirty.set(control.dirty);\n });\n\n ngControl.valueAccessor = {\n writeValue: (rawValue: T | null) => {\n runModelUpdate(() => {\n // fix (https://github.com/angular/angular/issues/14988)\n const modelValue = ngControl instanceof NgModel ? ngControl.model : rawValue;\n value.set(modelValue);\n });\n },\n registerOnChange: fn => (updateFn = fn),\n registerOnTouched: fn => (touchedFn = fn),\n setDisabledState: isDisabled => disabled?.set(isDisabled),\n };\n\n return cvaRef;\n });\n}\n\nconst UNSET_VALUE: unique symbol = Symbol('Cva#UNSET');\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { InjectionToken, inject, PLATFORM_ID, assertInInjectionContext, INJECTOR, runInInjectionContext, DestroyRef, untracked, isSignal, ElementRef } from '@angular/core';
|
|
1
|
+
import { InjectionToken, inject, PLATFORM_ID, assertInInjectionContext, INJECTOR, runInInjectionContext, DestroyRef, untracked, isSignal, effect, ElementRef } from '@angular/core';
|
|
2
2
|
import { isPlatformBrowser, isPlatformServer } from '@angular/common';
|
|
3
3
|
import { SIGNAL, SIGNAL_NODE } from '@angular/core/primitives/signals';
|
|
4
4
|
|
|
@@ -118,7 +118,7 @@ function assertElement(value, source) {
|
|
|
118
118
|
}
|
|
119
119
|
function assertEventTarget(value, source) {
|
|
120
120
|
if (!isEventTarget(value)) {
|
|
121
|
-
throw new Error(`[${source}] Expected an EventTarget
|
|
121
|
+
throw new Error(`[${source}] Expected an EventTarget, ElementRef but received: ${value.constructor?.name ?? typeof value}. ` +
|
|
122
122
|
`If you are using viewChild/contentChild, specify "{ read: ElementRef }" to avoid implicit directive references.`);
|
|
123
123
|
}
|
|
124
124
|
}
|
|
@@ -184,6 +184,38 @@ function createToken(factory, providedIn = 'root') {
|
|
|
184
184
|
return new InjectionToken(ngDevMode ? factory.name : '', { factory, providedIn });
|
|
185
185
|
}
|
|
186
186
|
|
|
187
|
+
/**
|
|
188
|
+
* Resolves the first available value of a signal as a Promise.
|
|
189
|
+
* @internal
|
|
190
|
+
*/
|
|
191
|
+
function waitForValue(source, injector) {
|
|
192
|
+
const { runInContext } = setupContext(injector, waitForValue);
|
|
193
|
+
return runInContext(() => {
|
|
194
|
+
try {
|
|
195
|
+
// Try to read the signal synchronously
|
|
196
|
+
return Promise.resolve(source());
|
|
197
|
+
}
|
|
198
|
+
catch {
|
|
199
|
+
// Required signals (input, model, queries) throw when read outside a reactive context
|
|
200
|
+
// during initialization, fall back to reading the value inside an effect
|
|
201
|
+
return new Promise((resolve, reject) => {
|
|
202
|
+
const effectRef = effect(() => {
|
|
203
|
+
try {
|
|
204
|
+
const value = source();
|
|
205
|
+
resolve(value);
|
|
206
|
+
}
|
|
207
|
+
catch (e) {
|
|
208
|
+
reject(e);
|
|
209
|
+
}
|
|
210
|
+
finally {
|
|
211
|
+
effectRef.destroy();
|
|
212
|
+
}
|
|
213
|
+
}, ...(ngDevMode ? [{ debugName: "effectRef" }] : []));
|
|
214
|
+
});
|
|
215
|
+
}
|
|
216
|
+
});
|
|
217
|
+
}
|
|
218
|
+
|
|
187
219
|
/**
|
|
188
220
|
* Determines if a signal is a query signal (viewChild, contentChild).
|
|
189
221
|
* Query signals have a special internal structure with a `_dirtyCounter` property that tracks
|
|
@@ -250,34 +282,10 @@ function proxySignal(source, handler) {
|
|
|
250
282
|
return proxy;
|
|
251
283
|
}
|
|
252
284
|
|
|
253
|
-
// @TODO: Consider moving it out of internal
|
|
254
|
-
const toValue = (() => {
|
|
255
|
-
const fn = toValueFn;
|
|
256
|
-
fn.untracked = v => toValueFn(v, true);
|
|
257
|
-
return fn;
|
|
258
|
-
})();
|
|
259
|
-
function toValueFn(maybeSignal, untracked$1 = false) {
|
|
260
|
-
if (isSignal(maybeSignal)) {
|
|
261
|
-
return untracked$1 ? untracked(maybeSignal) : maybeSignal();
|
|
262
|
-
}
|
|
263
|
-
return maybeSignal;
|
|
264
|
-
}
|
|
265
|
-
|
|
266
285
|
function unrefElement(value) {
|
|
267
286
|
return value instanceof ElementRef ? value.nativeElement : value;
|
|
268
287
|
}
|
|
269
288
|
|
|
270
|
-
// @TODO: Consider moving it out of internal
|
|
271
|
-
const toElement = (() => {
|
|
272
|
-
const fn = toElementFn;
|
|
273
|
-
fn.untracked = v => toElementFn(v, true);
|
|
274
|
-
return fn;
|
|
275
|
-
})();
|
|
276
|
-
function toElementFn(maybeSignal, untracked = false) {
|
|
277
|
-
const raw = untracked ? toValue.untracked(maybeSignal) : toValue(maybeSignal);
|
|
278
|
-
return unrefElement(raw);
|
|
279
|
-
}
|
|
280
|
-
|
|
281
289
|
/**
|
|
282
290
|
* Checks whether a file matches the given accept patterns.
|
|
283
291
|
* Follows the native HTML
|
|
@@ -311,5 +319,5 @@ function isAcceptedFile(file, accept) {
|
|
|
311
319
|
* Generated bundle index. Do not edit.
|
|
312
320
|
*/
|
|
313
321
|
|
|
314
|
-
export { ALWAYS_FALSE_FN, IS_BROWSER, IS_MOBILE, IS_SERVER, MOBILE_REGEX, NOOP_ASYNC_FN, NOOP_EFFECT_REF, NOOP_FN, assertElement, assertEventTarget, constSignal, createToken, getActiveElement, getEventTarget, getPipElement, getShadowRoot, isAcceptedFile, isElement, isEventTarget, isNodeWithin, isPlainObject, isQuerySignal, isWindow, proxySignal, setupContext,
|
|
322
|
+
export { ALWAYS_FALSE_FN, IS_BROWSER, IS_MOBILE, IS_SERVER, MOBILE_REGEX, NOOP_ASYNC_FN, NOOP_EFFECT_REF, NOOP_FN, assertElement, assertEventTarget, constSignal, createToken, getActiveElement, getEventTarget, getPipElement, getShadowRoot, isAcceptedFile, isElement, isEventTarget, isNodeWithin, isPlainObject, isQuerySignal, isWindow, proxySignal, setupContext, unrefElement, waitForValue };
|
|
315
323
|
//# sourceMappingURL=signality-core-internal.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"signality-core-internal.mjs","sources":["../../../projects/core/internal/constants/mobile-regex.ts","../../../projects/core/internal/constants/stubs.ts","../../../projects/core/internal/providers/is-browser.ts","../../../projects/core/internal/providers/is-mobile.ts","../../../projects/core/internal/providers/is-server.ts","../../../projects/core/internal/utils/bom/is-window.ts","../../../projects/core/internal/utils/dom/get-active-element.ts","../../../projects/core/internal/utils/dom/get-event-target.ts","../../../projects/core/internal/utils/dom/get-pip-element.ts","../../../projects/core/internal/utils/dom/get-shadow-root.ts","../../../projects/core/internal/utils/dom/is-element.ts","../../../projects/core/internal/utils/dom/is-event-target.ts","../../../projects/core/internal/utils/dom/is-node-within.ts","../../../projects/core/internal/utils/assert.ts","../../../projects/core/internal/utils/context.ts","../../../projects/core/internal/utils/create-token.ts","../../../projects/core/internal/utils/is-query-signal.ts","../../../projects/core/internal/utils/is-plain-object.ts","../../../projects/core/internal/utils/const-signal.ts","../../../projects/core/internal/utils/proxy-signal.ts","../../../projects/core/internal/utils/to-value.ts","../../../projects/core/internal/utils/unref-element.ts","../../../projects/core/internal/utils/to-element.ts","../../../projects/core/internal/utils/files/is-accepted-file.ts","../../../projects/core/internal/signality-core-internal.ts"],"sourcesContent":["export const MOBILE_REGEX = /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i;\n","/**\n * Empty synchronous function stub.\n * Used for SSR compatibility when returning method functions in Ref objects that should do nothing on the server.\n *\n * Example: `close: NOOP_FN` in {@link WebNotificationRef}\n */\nexport const NOOP_FN: (...args: any[]) => void = () => {\n /* empty */\n};\n\n/**\n * Empty asynchronous function stub that returns a resolved Promise.\n * Used for SSR compatibility when returning async method functions in Ref objects that should do nothing on the server.\n *\n * Example: `share: NOOP_ASYNC_FN` in {@link WebShareRef}\n */\nexport const NOOP_ASYNC_FN = () => Promise.resolve();\n\n/**\n * Frozen EffectRef stub with a no-op destroy method.\n * Used for SSR compatibility when returning EffectRef from observer utilities (ResizeObserver, MutationObserver, etc.)\n * that cannot run on the server. Prevents errors when calling destroy() on server-rendered refs.\n *\n * Example: `return NOOP_EFFECT_REF` in {@link resizeObserver}\n */\nexport const NOOP_EFFECT_REF = { destroy: NOOP_FN };\n\n/**\n * Equality function that always returns false, forcing signal updates on every change.\n * Used for signals that hold mutable objects (like Selection, Range) where reference equality is not sufficient\n * and we need to detect changes even when the object structure appears the same.\n *\n * Example: `signal<Selection | null>(null, { equal: ALWAYS_FALSE_FN })` in {@link textSelection}\n */\nexport const ALWAYS_FALSE_FN = () => false;\n","import { inject, InjectionToken, PLATFORM_ID } from '@angular/core';\nimport { isPlatformBrowser } from '@angular/common';\n\nexport const IS_BROWSER = new InjectionToken<boolean>(ngDevMode ? 'IS_BROWSER' : '', {\n providedIn: 'platform',\n factory: () => isPlatformBrowser(inject(PLATFORM_ID)),\n});\n","import { inject, InjectionToken } from '@angular/core';\nimport { MOBILE_REGEX } from '../constants';\nimport { IS_BROWSER } from './is-browser';\n\nexport const IS_MOBILE = new InjectionToken<boolean>(ngDevMode ? 'IS_MOBILE' : '', {\n providedIn: 'platform',\n factory: () => {\n return inject(IS_BROWSER) ? MOBILE_REGEX.test(navigator.userAgent) : false;\n },\n});\n","import { inject, InjectionToken, PLATFORM_ID } from '@angular/core';\nimport { isPlatformServer } from '@angular/common';\n\nexport const IS_SERVER = new InjectionToken<boolean>(ngDevMode ? 'IS_SERVER' : '', {\n providedIn: 'platform',\n factory: () => isPlatformServer(inject(PLATFORM_ID)),\n});\n","export function isWindow(obj: object | null): obj is Window {\n return !!obj && (obj as Window).window === obj;\n}\n","export function getActiveElement(document: Document): Element | null {\n let activeElement = document.activeElement;\n\n while (activeElement && activeElement.shadowRoot) {\n const newActiveElement = activeElement.shadowRoot.activeElement;\n if (newActiveElement === activeElement) {\n break;\n } else {\n activeElement = newActiveElement;\n }\n }\n\n return activeElement;\n}\n","export function getEventTarget<T extends EventTarget>(event: Event): T | null {\n return (event.composedPath ? event.composedPath()[0] : event.target) as T | null;\n}\n","export function getPipElement(document: Document): Element | null {\n let pipElement = document.pictureInPictureElement;\n\n while (pipElement && pipElement.shadowRoot) {\n const newPipElement = pipElement.shadowRoot.pictureInPictureElement;\n if (newPipElement === pipElement) {\n break;\n } else {\n pipElement = newPipElement;\n }\n }\n\n return pipElement;\n}\n","export function getShadowRoot(element: Element | null): ShadowRoot | null {\n const rootNode = element?.getRootNode ? element.getRootNode() : null;\n\n if (rootNode instanceof ShadowRoot) {\n return rootNode;\n }\n\n return null;\n}\n","export function isElement(value: unknown): value is Element {\n return !!value && (value as Element).nodeType === Node.ELEMENT_NODE;\n}\n","export function isEventTarget(value: unknown): value is EventTarget {\n return typeof (value as EventTarget)?.addEventListener === 'function';\n}\n","export function isNodeWithin(node: Node, root: Element): boolean {\n return root === node || root.contains(node) || (root.shadowRoot?.contains(node) ?? false);\n}\n","import { isElement, isEventTarget } from './dom';\n\nexport function assertElement(value: unknown, source: string): asserts value is Element {\n if (!isElement(value)) {\n throw new Error(\n `[${source}] Expected a DOM Element, ElementRef but received: ${\n (value as object).constructor?.name ?? typeof value\n }. ` +\n `If you are using viewChild/contentChild, make sure to specify \"{ read: ElementRef }\" to avoid implicit directive references.`\n );\n }\n}\n\nexport function assertEventTarget(value: unknown, source: string): asserts value is EventTarget {\n if (!isEventTarget(value)) {\n throw new Error(\n `[${source}] Expected an EventTarget (e.g. window, DOM Element, ElementRef), but received: ${\n (value as object).constructor?.name ?? typeof value\n }. ` +\n `If you are using viewChild/contentChild, specify \"{ read: ElementRef }\" to avoid implicit directive references.`\n );\n }\n}\n","import {\n assertInInjectionContext,\n DestroyRef,\n inject,\n type Injector,\n INJECTOR,\n isSignal,\n runInInjectionContext,\n type Signal,\n untracked,\n} from '@angular/core';\nimport { SIGNAL, type SignalNode } from '@angular/core/primitives/signals';\nimport { IS_BROWSER, IS_MOBILE, IS_SERVER } from '../providers';\n\nexport interface ContextRef {\n readonly injector: Injector;\n readonly isServer: boolean;\n readonly isBrowser: boolean;\n readonly isMobile: boolean;\n readonly onCleanup: (cleanupFn: () => void) => void;\n}\n\nexport interface SetupContextRef {\n runInContext<T>(fn: (context: ContextRef) => T): T;\n}\n\n/**\n * @internal\n *\n * @param injector - injector to use for context\n * @param debugFn - context owner function\n */\nexport function setupContext(\n injector?: Injector,\n debugFn?: (...args: any[]) => any\n): SetupContextRef {\n if (typeof ngDevMode !== 'undefined' && ngDevMode && !injector) {\n assertInInjectionContext(debugFn || setupContext);\n }\n\n const ctxInjector = injector || inject(INJECTOR);\n\n return {\n runInContext<T>(fn: (context: ContextRef) => T): T {\n return runInContextImpl(fn, ctxInjector, debugFn || setupContext);\n },\n };\n}\n\nfunction runInContextImpl<T>(\n fn: (context: ContextRef) => T,\n injector: Injector,\n debugFn: (...args: any[]) => any\n): T {\n const result = runInInjectionContext(injector, () => {\n const isBrowser = inject(IS_BROWSER);\n const isServer = inject(IS_SERVER);\n const isMobile = inject(IS_MOBILE);\n const destroyRef = inject(DestroyRef);\n\n const onCleanup = (cleanupFn: () => void) => {\n destroyRef.onDestroy(cleanupFn);\n };\n\n return untracked(() => fn({ injector, isBrowser, isServer, isMobile, onCleanup }));\n });\n\n if (typeof ngDevMode !== 'undefined' && ngDevMode && result != null) {\n setupDebugInfo(result, debugFn);\n }\n\n return result;\n}\n\nfunction setupDebugInfo<T>(value: T, debugFn: (...args: any[]) => any): T {\n if (isSignal(value)) {\n setDebugName(value, debugFn);\n } else if (value && typeof value === 'object') {\n for (const [postfix, maybeSignal] of Object.entries(value)) {\n if (isSignal(maybeSignal)) {\n setDebugName(maybeSignal, debugFn, postfix);\n }\n }\n }\n\n return value;\n}\n\nfunction setDebugName(\n signal: Signal<unknown>,\n debugFn: (...args: any[]) => any,\n postfix?: string\n): void {\n const node = signal[SIGNAL] as SignalNode<unknown>;\n\n if (node.debugName === undefined) {\n node.debugName = debugFn.name + (postfix ? '.' + postfix : '');\n }\n}\n","import { InjectionToken, type ProviderToken } from '@angular/core';\n\n/**\n * Creates an Angular InjectionToken with a factory function.\n * @internal\n */\nexport function createToken<T>(\n factory: () => T,\n providedIn: ProvidedIn = 'root'\n): ProviderToken<T> {\n return new InjectionToken(ngDevMode ? factory.name : '', { factory, providedIn });\n}\n\ntype ProvidedIn = NonNullable<ConstructorParameters<typeof InjectionToken>[1]>['providedIn'];\n","import { isSignal, type Signal } from '@angular/core';\nimport { SIGNAL } from '@angular/core/primitives/signals';\n\n/**\n * Determines if a signal is a query signal (viewChild, contentChild).\n * Query signals have a special internal structure with a `_dirtyCounter` property that tracks\n * when query results change.\n\n * See: https://github.com/angular/angular/blob/main/packages/core/src/render3/queries/query_reactive.ts#L43\n * @internal\n */\nexport function isQuerySignal(val: unknown): val is Signal<unknown> {\n if (!isSignal(val)) {\n return false;\n }\n\n const node = val[SIGNAL] as object;\n return '_dirtyCounter' in node;\n}\n","export function isPlainObject(value: unknown): value is Record<PropertyKey, unknown> {\n if (typeof value !== 'object' || value === null) {\n return false;\n }\n\n const prototype = Object.getPrototypeOf(value);\n return prototype === null || prototype === Object.prototype;\n}\n","import type { Signal } from '@angular/core';\nimport {\n SIGNAL,\n SIGNAL_NODE,\n type SignalGetter,\n type SignalNode,\n} from '@angular/core/primitives/signals';\n\n/***\n * Creates a lightweight, readonly signal.\n * This is primarily used to provide fallback values for states that cannot be\n * computed in the current environment. For example:\n * - During SSR where browser-only APIs are unavailable\n * - In environments that lack support for specific APIs\n * @internal\n */\nexport function constSignal<T>(value: T): Signal<T> {\n const node: SignalNode<T> = Object.create(SIGNAL_NODE);\n node.value = value;\n\n const getter = (() => node.value) as SignalGetter<T>;\n (getter as any)[SIGNAL] = node;\n\n if (typeof ngDevMode !== 'undefined' && ngDevMode) {\n const debugName = node.debugName ? ' (' + node.debugName + ')' : '';\n getter.toString = () => `[Signal${debugName}: ${String(node.value)}]`;\n }\n\n return getter;\n}\n","import { type Signal, untracked, type WritableSignal } from '@angular/core';\nimport { SIGNAL, type SignalNode } from '@angular/core/primitives/signals';\n\n/**\n * @internal\n */\nexport interface SignalProxyHandler<T> {\n get?(source: Signal<T>): T;\n set?(value: T, source: WritableSignal<T>): void;\n}\n\n/**\n * Creates a proxy wrapper around a {@link Signal}\n * @internal\n */\nexport function proxySignal<T>(\n source: Signal<T>,\n handler: Omit<SignalProxyHandler<T>, 'set'>\n): Signal<T>;\n\n/**\n * Creates a proxy wrapper around a {@link WritableSignal}\n * @internal\n */\nexport function proxySignal<T>(\n source: WritableSignal<T>,\n handler: SignalProxyHandler<T>\n): WritableSignal<T>;\n\nexport function proxySignal<T>(\n source: Signal<T> | WritableSignal<T>,\n handler: SignalProxyHandler<T>\n): Signal<T> | WritableSignal<T> {\n const node = source[SIGNAL] as SignalNode<T>;\n const isWritable = 'set' in source && typeof source.set === 'function';\n\n const proxy = (handler.get ? () => handler.get!(source) : () => source()) as Signal<T>;\n\n proxy[SIGNAL] = node;\n\n // @TODO: consider (original toString internally reads from the original getter, bypassing the proxy)\n proxy.toString = source.toString;\n\n if (isWritable) {\n const set = handler.set\n ? (value: T) => untracked(() => handler.set!(value, source))\n : (value: T) => source.set(value);\n\n const update = (updater: (current: T) => T) => set(updater(node.value));\n\n (proxy as WritableSignal<T>).set = set;\n (proxy as WritableSignal<T>).update = update;\n (proxy as WritableSignal<T>).asReadonly = () => {\n const getter = source.asReadonly();\n return proxySignal(getter, { get: handler.get?.bind(handler) });\n };\n }\n\n return proxy;\n}\n","import { isSignal, untracked as _untracked } from '@angular/core';\nimport type { MaybeSignal } from '@signality/core/types';\n\nexport interface ToValueFn {\n <T>(maybeSignal: MaybeSignal<T>): T;\n untracked: <T>(maybeSignal: MaybeSignal<T>) => T;\n}\n\n// @TODO: Consider moving it out of internal\nexport const toValue: ToValueFn = (() => {\n const fn = toValueFn as ToValueFn;\n fn.untracked = v => toValueFn(v, true);\n return fn;\n})();\n\nfunction toValueFn<T>(maybeSignal: MaybeSignal<T>, untracked = false): T {\n if (isSignal(maybeSignal)) {\n return untracked ? _untracked(maybeSignal) : maybeSignal();\n }\n return maybeSignal;\n}\n","import { ElementRef } from '@angular/core';\n\nexport function unrefElement<T>(value: T | ElementRef<T>): T {\n return value instanceof ElementRef ? value.nativeElement : value;\n}\n","import { type ElementRef, type Signal } from '@angular/core';\nimport type { MaybeElementSignal } from '@signality/core/types';\nimport { toValue } from './to-value';\nimport { unrefElement } from './unref-element';\n\nexport interface ToElementFn extends ToElementBase {\n untracked: ToElementBase;\n}\n\nexport interface ToElementBase {\n <T extends Element>(element: T | ElementRef<T>): T;\n <T extends Element>(element: Signal<T | ElementRef<T> | null>): T | null;\n <T extends Element>(element: Signal<T | ElementRef<T> | undefined>): T | undefined;\n <T extends Element>(element: Signal<T | ElementRef<T> | null | undefined>): T | null | undefined;\n <T extends Element>(element: T | ElementRef<T> | Signal<T | ElementRef<T> | null | undefined>):\n | T\n | null\n | undefined;\n}\n\n// @TODO: Consider moving it out of internal\nexport const toElement: ToElementFn = (() => {\n const fn = toElementFn as ToElementFn;\n fn.untracked = v => toElementFn(v, true);\n return fn;\n})();\n\nfunction toElementFn<T extends Element>(\n maybeSignal: MaybeElementSignal<T>,\n untracked = false\n): T | null | undefined {\n const raw = untracked ? toValue.untracked(maybeSignal) : toValue(maybeSignal);\n return unrefElement(raw);\n}\n","/**\n * Checks whether a file matches the given accept patterns.\n * Follows the native HTML\n * [`accept`](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Attributes/accept) attribute format:\n * MIME types (`'image/png'`), wildcards (`'image/*'`), and file extensions (`'.pdf'`).\n *\n * @param file - File to check\n * @param accept - Comma-separated string of accepted patterns (e.g. `'image/*, .pdf'`)\n * @internal\n */\nexport function isAcceptedFile(file: File, accept: string): boolean {\n if (accept === '*') {\n return true;\n }\n\n const patterns = accept.split(',').map(s => s.trim());\n\n if (patterns.length === 0) {\n return true;\n }\n\n return patterns.some(pattern => {\n if (pattern.startsWith('.')) {\n return file.name.toLowerCase().endsWith(pattern.toLowerCase());\n }\n\n if (pattern.endsWith('/*')) {\n return file.type.startsWith(pattern.slice(0, -1));\n }\n\n return file.type === pattern;\n });\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":["untracked","_untracked"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"signality-core-internal.mjs","sources":["../../../projects/core/internal/constants/mobile-regex.ts","../../../projects/core/internal/constants/stubs.ts","../../../projects/core/internal/providers/is-browser.ts","../../../projects/core/internal/providers/is-mobile.ts","../../../projects/core/internal/providers/is-server.ts","../../../projects/core/internal/utils/bom/is-window.ts","../../../projects/core/internal/utils/dom/get-active-element.ts","../../../projects/core/internal/utils/dom/get-event-target.ts","../../../projects/core/internal/utils/dom/get-pip-element.ts","../../../projects/core/internal/utils/dom/get-shadow-root.ts","../../../projects/core/internal/utils/dom/is-element.ts","../../../projects/core/internal/utils/dom/is-event-target.ts","../../../projects/core/internal/utils/dom/is-node-within.ts","../../../projects/core/internal/utils/assert.ts","../../../projects/core/internal/utils/context.ts","../../../projects/core/internal/utils/create-token.ts","../../../projects/core/internal/utils/wait-for-value.ts","../../../projects/core/internal/utils/is-query-signal.ts","../../../projects/core/internal/utils/is-plain-object.ts","../../../projects/core/internal/utils/const-signal.ts","../../../projects/core/internal/utils/proxy-signal.ts","../../../projects/core/internal/utils/unref-element.ts","../../../projects/core/internal/utils/files/is-accepted-file.ts","../../../projects/core/internal/signality-core-internal.ts"],"sourcesContent":["export const MOBILE_REGEX = /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i;\n","/**\n * Empty synchronous function stub.\n * Used for SSR compatibility when returning method functions in Ref objects that should do nothing on the server.\n *\n * Example: `close: NOOP_FN` in {@link WebNotificationRef}\n */\nexport const NOOP_FN: (...args: any[]) => void = () => {\n /* empty */\n};\n\n/**\n * Empty asynchronous function stub that returns a resolved Promise.\n * Used for SSR compatibility when returning async method functions in Ref objects that should do nothing on the server.\n *\n * Example: `share: NOOP_ASYNC_FN` in {@link WebShareRef}\n */\nexport const NOOP_ASYNC_FN = () => Promise.resolve();\n\n/**\n * Frozen EffectRef stub with a no-op destroy method.\n * Used for SSR compatibility when returning EffectRef from observer utilities (ResizeObserver, MutationObserver, etc.)\n * that cannot run on the server. Prevents errors when calling destroy() on server-rendered refs.\n *\n * Example: `return NOOP_EFFECT_REF` in {@link resizeObserver}\n */\nexport const NOOP_EFFECT_REF = { destroy: NOOP_FN };\n\n/**\n * Equality function that always returns false, forcing signal updates on every change.\n * Used for signals that hold mutable objects (like Selection, Range) where reference equality is not sufficient\n * and we need to detect changes even when the object structure appears the same.\n *\n * Example: `signal<Selection | null>(null, { equal: ALWAYS_FALSE_FN })` in {@link textSelection}\n */\nexport const ALWAYS_FALSE_FN = () => false;\n","import { inject, InjectionToken, PLATFORM_ID } from '@angular/core';\nimport { isPlatformBrowser } from '@angular/common';\n\nexport const IS_BROWSER = new InjectionToken<boolean>(ngDevMode ? 'IS_BROWSER' : '', {\n providedIn: 'platform',\n factory: () => isPlatformBrowser(inject(PLATFORM_ID)),\n});\n","import { inject, InjectionToken } from '@angular/core';\nimport { MOBILE_REGEX } from '../constants';\nimport { IS_BROWSER } from './is-browser';\n\nexport const IS_MOBILE = new InjectionToken<boolean>(ngDevMode ? 'IS_MOBILE' : '', {\n providedIn: 'platform',\n factory: () => {\n return inject(IS_BROWSER) ? MOBILE_REGEX.test(navigator.userAgent) : false;\n },\n});\n","import { inject, InjectionToken, PLATFORM_ID } from '@angular/core';\nimport { isPlatformServer } from '@angular/common';\n\nexport const IS_SERVER = new InjectionToken<boolean>(ngDevMode ? 'IS_SERVER' : '', {\n providedIn: 'platform',\n factory: () => isPlatformServer(inject(PLATFORM_ID)),\n});\n","export function isWindow(obj: object | null): obj is Window {\n return !!obj && (obj as Window).window === obj;\n}\n","export function getActiveElement(document: Document): Element | null {\n let activeElement = document.activeElement;\n\n while (activeElement && activeElement.shadowRoot) {\n const newActiveElement = activeElement.shadowRoot.activeElement;\n if (newActiveElement === activeElement) {\n break;\n } else {\n activeElement = newActiveElement;\n }\n }\n\n return activeElement;\n}\n","export function getEventTarget<T extends EventTarget>(event: Event): T | null {\n return (event.composedPath ? event.composedPath()[0] : event.target) as T | null;\n}\n","export function getPipElement(document: Document): Element | null {\n let pipElement = document.pictureInPictureElement;\n\n while (pipElement && pipElement.shadowRoot) {\n const newPipElement = pipElement.shadowRoot.pictureInPictureElement;\n if (newPipElement === pipElement) {\n break;\n } else {\n pipElement = newPipElement;\n }\n }\n\n return pipElement;\n}\n","export function getShadowRoot(element: Element | null): ShadowRoot | null {\n const rootNode = element?.getRootNode ? element.getRootNode() : null;\n\n if (rootNode instanceof ShadowRoot) {\n return rootNode;\n }\n\n return null;\n}\n","export function isElement(value: unknown): value is Element {\n return !!value && (value as Element).nodeType === Node.ELEMENT_NODE;\n}\n","export function isEventTarget(value: unknown): value is EventTarget {\n return typeof (value as EventTarget)?.addEventListener === 'function';\n}\n","export function isNodeWithin(node: Node, root: Element): boolean {\n return root === node || root.contains(node) || (root.shadowRoot?.contains(node) ?? false);\n}\n","import { isElement, isEventTarget } from './dom';\n\nexport function assertElement(value: unknown, source: string): asserts value is Element {\n if (!isElement(value)) {\n throw new Error(\n `[${source}] Expected a DOM Element, ElementRef but received: ${\n (value as object).constructor?.name ?? typeof value\n }. ` +\n `If you are using viewChild/contentChild, make sure to specify \"{ read: ElementRef }\" to avoid implicit directive references.`\n );\n }\n}\n\nexport function assertEventTarget(value: unknown, source: string): asserts value is EventTarget {\n if (!isEventTarget(value)) {\n throw new Error(\n `[${source}] Expected an EventTarget, ElementRef but received: ${\n (value as object).constructor?.name ?? typeof value\n }. ` +\n `If you are using viewChild/contentChild, specify \"{ read: ElementRef }\" to avoid implicit directive references.`\n );\n }\n}\n","import {\n assertInInjectionContext,\n DestroyRef,\n inject,\n type Injector,\n INJECTOR,\n isSignal,\n runInInjectionContext,\n type Signal,\n untracked,\n} from '@angular/core';\nimport { SIGNAL, type SignalNode } from '@angular/core/primitives/signals';\nimport { IS_BROWSER, IS_MOBILE, IS_SERVER } from '../providers';\n\nexport interface ContextRef {\n readonly injector: Injector;\n readonly isServer: boolean;\n readonly isBrowser: boolean;\n readonly isMobile: boolean;\n readonly onCleanup: (cleanupFn: () => void) => void;\n}\n\nexport interface SetupContextRef {\n runInContext<T>(fn: (context: ContextRef) => T): T;\n}\n\n/**\n * @internal\n *\n * @param injector - injector to use for context\n * @param debugFn - context owner function\n */\nexport function setupContext(\n injector?: Injector,\n debugFn?: (...args: any[]) => any\n): SetupContextRef {\n if (typeof ngDevMode !== 'undefined' && ngDevMode && !injector) {\n assertInInjectionContext(debugFn || setupContext);\n }\n\n const ctxInjector = injector || inject(INJECTOR);\n\n return {\n runInContext<T>(fn: (context: ContextRef) => T): T {\n return runInContextImpl(fn, ctxInjector, debugFn || setupContext);\n },\n };\n}\n\nfunction runInContextImpl<T>(\n fn: (context: ContextRef) => T,\n injector: Injector,\n debugFn: (...args: any[]) => any\n): T {\n const result = runInInjectionContext(injector, () => {\n const isBrowser = inject(IS_BROWSER);\n const isServer = inject(IS_SERVER);\n const isMobile = inject(IS_MOBILE);\n const destroyRef = inject(DestroyRef);\n\n const onCleanup = (cleanupFn: () => void) => {\n destroyRef.onDestroy(cleanupFn);\n };\n\n return untracked(() => fn({ injector, isBrowser, isServer, isMobile, onCleanup }));\n });\n\n if (typeof ngDevMode !== 'undefined' && ngDevMode && result != null) {\n setupDebugInfo(result, debugFn);\n }\n\n return result;\n}\n\nfunction setupDebugInfo<T>(value: T, debugFn: (...args: any[]) => any): T {\n if (isSignal(value)) {\n setDebugName(value, debugFn);\n } else if (value && typeof value === 'object') {\n for (const [postfix, maybeSignal] of Object.entries(value)) {\n if (isSignal(maybeSignal)) {\n setDebugName(maybeSignal, debugFn, postfix);\n }\n }\n }\n\n return value;\n}\n\nfunction setDebugName(\n signal: Signal<unknown>,\n debugFn: (...args: any[]) => any,\n postfix?: string\n): void {\n const node = signal[SIGNAL] as SignalNode<unknown>;\n\n if (node.debugName === undefined) {\n node.debugName = debugFn.name + (postfix ? '.' + postfix : '');\n }\n}\n","import { InjectionToken, type ProviderToken } from '@angular/core';\n\n/**\n * Creates an Angular InjectionToken with a factory function.\n * @internal\n */\nexport function createToken<T>(\n factory: () => T,\n providedIn: ProvidedIn = 'root'\n): ProviderToken<T> {\n return new InjectionToken(ngDevMode ? factory.name : '', { factory, providedIn });\n}\n\ntype ProvidedIn = NonNullable<ConstructorParameters<typeof InjectionToken>[1]>['providedIn'];\n","import { effect, type Injector, type Signal } from '@angular/core';\nimport { setupContext } from './context';\n\n/**\n * Resolves the first available value of a signal as a Promise.\n * @internal\n */\nexport function waitForValue<T>(source: Signal<T>, injector?: Injector): Promise<T> {\n const { runInContext } = setupContext(injector, waitForValue);\n\n return runInContext(() => {\n try {\n // Try to read the signal synchronously\n return Promise.resolve(source());\n } catch {\n // Required signals (input, model, queries) throw when read outside a reactive context\n // during initialization, fall back to reading the value inside an effect\n return new Promise<T>((resolve, reject) => {\n const effectRef = effect(() => {\n try {\n const value = source();\n resolve(value);\n } catch (e) {\n reject(e);\n } finally {\n effectRef.destroy();\n }\n });\n });\n }\n });\n}\n","import { isSignal, type Signal } from '@angular/core';\nimport { SIGNAL } from '@angular/core/primitives/signals';\n\n/**\n * Determines if a signal is a query signal (viewChild, contentChild).\n * Query signals have a special internal structure with a `_dirtyCounter` property that tracks\n * when query results change.\n\n * See: https://github.com/angular/angular/blob/main/packages/core/src/render3/queries/query_reactive.ts#L43\n * @internal\n */\nexport function isQuerySignal(val: unknown): val is Signal<unknown> {\n if (!isSignal(val)) {\n return false;\n }\n\n const node = val[SIGNAL] as object;\n return '_dirtyCounter' in node;\n}\n","export function isPlainObject(value: unknown): value is Record<PropertyKey, unknown> {\n if (typeof value !== 'object' || value === null) {\n return false;\n }\n\n const prototype = Object.getPrototypeOf(value);\n return prototype === null || prototype === Object.prototype;\n}\n","import type { Signal } from '@angular/core';\nimport {\n SIGNAL,\n SIGNAL_NODE,\n type SignalGetter,\n type SignalNode,\n} from '@angular/core/primitives/signals';\n\n/***\n * Creates a lightweight, readonly signal.\n * This is primarily used to provide fallback values for states that cannot be\n * computed in the current environment. For example:\n * - During SSR where browser-only APIs are unavailable\n * - In environments that lack support for specific APIs\n * @internal\n */\nexport function constSignal<T>(value: T): Signal<T> {\n const node: SignalNode<T> = Object.create(SIGNAL_NODE);\n node.value = value;\n\n const getter = (() => node.value) as SignalGetter<T>;\n (getter as any)[SIGNAL] = node;\n\n if (typeof ngDevMode !== 'undefined' && ngDevMode) {\n const debugName = node.debugName ? ' (' + node.debugName + ')' : '';\n getter.toString = () => `[Signal${debugName}: ${String(node.value)}]`;\n }\n\n return getter;\n}\n","import { type Signal, untracked, type WritableSignal } from '@angular/core';\nimport { SIGNAL, type SignalNode } from '@angular/core/primitives/signals';\n\n/**\n * @internal\n */\nexport interface SignalProxyHandler<T> {\n get?(source: Signal<T>): T;\n set?(value: T, source: WritableSignal<T>): void;\n}\n\n/**\n * Creates a proxy wrapper around a {@link Signal}\n * @internal\n */\nexport function proxySignal<T>(\n source: Signal<T>,\n handler: Omit<SignalProxyHandler<T>, 'set'>\n): Signal<T>;\n\n/**\n * Creates a proxy wrapper around a {@link WritableSignal}\n * @internal\n */\nexport function proxySignal<T>(\n source: WritableSignal<T>,\n handler: SignalProxyHandler<T>\n): WritableSignal<T>;\n\nexport function proxySignal<T>(\n source: Signal<T> | WritableSignal<T>,\n handler: SignalProxyHandler<T>\n): Signal<T> | WritableSignal<T> {\n const node = source[SIGNAL] as SignalNode<T>;\n const isWritable = 'set' in source && typeof source.set === 'function';\n\n const proxy = (handler.get ? () => handler.get!(source) : () => source()) as Signal<T>;\n\n proxy[SIGNAL] = node;\n\n // @TODO: consider (original toString internally reads from the original getter, bypassing the proxy)\n proxy.toString = source.toString;\n\n if (isWritable) {\n const set = handler.set\n ? (value: T) => untracked(() => handler.set!(value, source))\n : (value: T) => source.set(value);\n\n const update = (updater: (current: T) => T) => set(updater(node.value));\n\n (proxy as WritableSignal<T>).set = set;\n (proxy as WritableSignal<T>).update = update;\n (proxy as WritableSignal<T>).asReadonly = () => {\n const getter = source.asReadonly();\n return proxySignal(getter, { get: handler.get?.bind(handler) });\n };\n }\n\n return proxy;\n}\n","import { ElementRef } from '@angular/core';\n\nexport function unrefElement<T>(value: T | ElementRef<T>): T {\n return value instanceof ElementRef ? value.nativeElement : value;\n}\n","/**\n * Checks whether a file matches the given accept patterns.\n * Follows the native HTML\n * [`accept`](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Attributes/accept) attribute format:\n * MIME types (`'image/png'`), wildcards (`'image/*'`), and file extensions (`'.pdf'`).\n *\n * @param file - File to check\n * @param accept - Comma-separated string of accepted patterns (e.g. `'image/*, .pdf'`)\n * @internal\n */\nexport function isAcceptedFile(file: File, accept: string): boolean {\n if (accept === '*') {\n return true;\n }\n\n const patterns = accept.split(',').map(s => s.trim());\n\n if (patterns.length === 0) {\n return true;\n }\n\n return patterns.some(pattern => {\n if (pattern.startsWith('.')) {\n return file.name.toLowerCase().endsWith(pattern.toLowerCase());\n }\n\n if (pattern.endsWith('/*')) {\n return file.type.startsWith(pattern.slice(0, -1));\n }\n\n return file.type === pattern;\n });\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { afterRenderEffect } from '@angular/core';
|
|
2
|
-
import { setupContext, NOOP_EFFECT_REF,
|
|
2
|
+
import { setupContext, NOOP_EFFECT_REF, assertElement } from '@signality/core/internal';
|
|
3
|
+
import { toElement, toValue } from '@signality/core/utilities';
|
|
3
4
|
|
|
4
5
|
/**
|
|
5
6
|
* Low-level utility for observing element intersection with viewport using the [Intersection Observer API](https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API).
|