@ng-native/fabric 0.15.0 → 0.17.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.
@@ -38,11 +38,11 @@ export class EngineIntersectionObserver {
38
38
  if (this.watched.has(target))
39
39
  return;
40
40
  const check = () => this.check(target);
41
- const stops = [target.host.setEventListener(target, 'topLayout', check)];
41
+ const stops = [target.engine.setEventListener(target, 'topLayout', check)];
42
42
  for (let at = target.parent; at; at = at.parent) {
43
43
  if (!SCROLLERS.has(viewNameOf(at)))
44
44
  continue;
45
- stops.push(at.host.setEventListener(at, 'topScroll', check));
45
+ stops.push(at.engine.setEventListener(at, 'topScroll', check));
46
46
  }
47
47
  this.watched.set(target, { stops });
48
48
  // A node laid out before it was observed sends no layout event of its own. Measured now,
@@ -84,7 +84,7 @@ const box = (frame) => ({
84
84
  });
85
85
  function measured(node) {
86
86
  let found = null;
87
- node.host.measure(node, (frame) => (found = box(frame)));
87
+ node.engine.measure(node, (frame) => (found = box(frame)));
88
88
  return found;
89
89
  }
90
90
  function clip(into, by) {
@@ -109,7 +109,7 @@ function visibleShare(target) {
109
109
  if (scroller)
110
110
  clip(visible, scroller);
111
111
  }
112
- const window = target.host.viewport;
112
+ const window = target.engine.viewport;
113
113
  if (window && window.width > 0 && window.height > 0) {
114
114
  clip(visible, { left: 0, top: 0, right: window.width, bottom: window.height });
115
115
  }
@@ -1 +1 @@
1
- {"version":3,"file":"defer-triggers.js","sourceRoot":"","sources":["../src/defer-triggers.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * What Angular's `@defer (on interaction | hover | viewport)` asks of a trigger element, for the\n * engine's nodes.\n *\n * Angular registers those three triggers on the element itself rather than through `Renderer2`:\n * it asserts in development that the element is an `Element`, listens with `addEventListener`,\n * and watches for visibility with a global `IntersectionObserver`. An engine node was none of\n * those, so the placeholder stayed forever and every render logged an assertion. The listeners\n * are on the node (`addEventListener` in `engine.ts`); this is the other two.\n *\n * `installDeferTriggers` runs once, from `mount()`, before anything renders.\n */\nimport { isEngineNode, viewNameOf, type EngineNode, type WindowFrame } from './engine.ts';\nimport { letEngineNodesPass, type Constructor } from './node-global.ts';\n\n/** The views a node scrolls inside of, and whose scrolling can bring it into view. */\nconst SCROLLERS = new Set(['ScrollView', 'AndroidHorizontalScrollView']);\n\ninterface Entry {\n readonly target: EngineNode;\n readonly isIntersecting: boolean;\n readonly intersectionRatio: number;\n}\n\ntype Callback = (entries: Entry[], observer: EngineIntersectionObserver) => void;\n\ninterface Options {\n readonly threshold?: number | readonly number[];\n}\n\ninterface Watched {\n readonly stops: (() => void)[];\n}\n\n/**\n * Visibility for engine nodes, from the layout and scroll events native already sends.\n *\n * A node is checked when it is observed, when it is laid out, and whenever a scroll view it sits\n * in scrolls. The check measures the node in window coordinates, clips it by each scroll view\n * around it and by the window, and reports it intersecting once the visible share reaches the\n * threshold: any of it by default, as the web does, and a node of no size counts once its position\n * is inside. `root` and `rootMargin` are not applied; the root is always the window.\n */\nexport class EngineIntersectionObserver {\n private readonly callback: Callback;\n private readonly threshold: number;\n private readonly watched = new Map<EngineNode, Watched>();\n\n constructor(callback: Callback, options?: Options) {\n this.callback = callback;\n const threshold = options?.threshold;\n this.threshold = Array.isArray(threshold)\n ? Math.min(...(threshold as number[]))\n : ((threshold as number | undefined) ?? 0);\n }\n\n observe(target: EngineNode): void {\n if (this.watched.has(target)) return;\n const check = () => this.check(target);\n const stops = [target.host!.setEventListener(target, 'topLayout', check)];\n for (let at = target.parent; at; at = at.parent) {\n if (!SCROLLERS.has(viewNameOf(at))) continue;\n stops.push(at.host!.setEventListener(at, 'topScroll', check));\n }\n this.watched.set(target, { stops });\n // A node laid out before it was observed sends no layout event of its own. Measured now,\n // after the commit that mounted it, and in a microtask, as an observer never calls back from\n // inside `observe`.\n queueMicrotask(check);\n }\n\n unobserve(target: EngineNode): void {\n const watched = this.watched.get(target);\n if (!watched) return;\n for (const stop of watched.stops) stop();\n this.watched.delete(target);\n }\n\n disconnect(): void {\n for (const target of [...this.watched.keys()]) this.unobserve(target);\n }\n\n takeRecords(): Entry[] {\n return [];\n }\n\n private check(target: EngineNode): void {\n if (!this.watched.has(target)) return;\n const ratio = visibleShare(target);\n if (ratio === null) return;\n const isIntersecting = this.threshold > 0 ? ratio >= this.threshold : ratio >= 0;\n if (isIntersecting) this.callback([{ target, isIntersecting, intersectionRatio: ratio }], this);\n }\n}\n\n/** A frame as its four edges. */\ninterface Box {\n left: number;\n top: number;\n right: number;\n bottom: number;\n}\n\nconst box = (frame: WindowFrame): Box => ({\n left: frame.x,\n top: frame.y,\n right: frame.x + frame.width,\n bottom: frame.y + frame.height,\n});\n\nfunction measured(node: EngineNode): Box | null {\n let found: Box | null = null;\n node.host!.measure(node, (frame) => (found = box(frame)));\n return found;\n}\n\nfunction clip(into: Box, by: Box): void {\n into.left = Math.max(into.left, by.left);\n into.top = Math.max(into.top, by.top);\n into.right = Math.min(into.right, by.right);\n into.bottom = Math.min(into.bottom, by.bottom);\n}\n\n/**\n * How much of the node is on screen, from 0 to 1; below 0 when none of it is, and null when it\n * has not been measured. Measuring is synchronous on the new architecture.\n */\nfunction visibleShare(target: EngineNode): number | null {\n const frame = measured(target);\n if (!frame) return null;\n const visible = { ...frame };\n for (let at = target.parent; at; at = at.parent) {\n if (!SCROLLERS.has(viewNameOf(at))) continue;\n const scroller = measured(at);\n if (scroller) clip(visible, scroller);\n }\n const window = (target.host as { viewport?: { width: number; height: number } }).viewport;\n if (window && window.width > 0 && window.height > 0) {\n clip(visible, { left: 0, top: 0, right: window.width, bottom: window.height });\n }\n const width = visible.right - visible.left;\n const height = visible.bottom - visible.top;\n if (width < 0 || height < 0) return -1;\n const area = (frame.right - frame.left) * (frame.bottom - frame.top);\n return area > 0 ? (width * height) / area : 1;\n}\n\n/** React Native's own `IntersectionObserver`, when its feature flag has installed one. */\ninterface NativeObserver {\n observe(target: unknown): void;\n unobserve(target: unknown): void;\n disconnect(): void;\n}\ntype NativeObserverClass = new (callback: unknown, options?: unknown) => NativeObserver;\n\n// Never reset: the globals it patches stay patched for the life of the process.\nlet installed = false;\n\n/**\n * Let an engine node pass Angular's development check that a trigger is an `Element`, and give\n * `@defer (on viewport)` an `IntersectionObserver` that can watch one.\n *\n * React Native defines a global `Element` for its own DOM-like nodes, so an engine node is made to\n * answer `instanceof Element` as well, and nothing else about that class changes. Node has none,\n * and gets one that only engine nodes are instances of. An `IntersectionObserver` React Native\n * already has is kept for its own nodes; engine nodes are watched by the one above.\n */\nexport function installDeferTriggers(): void {\n if (installed) return;\n installed = true;\n const scope = globalThis as unknown as Record<string, unknown>;\n\n const existing = scope['Element'] as Constructor | undefined;\n if (existing) {\n letEngineNodesPass(existing);\n } else {\n scope['Element'] = class Element {\n static [Symbol.hasInstance](value: unknown): boolean {\n return isEngineNode(value);\n }\n };\n }\n\n const native = scope['IntersectionObserver'] as NativeObserverClass | undefined;\n if (!native) {\n scope['IntersectionObserver'] = EngineIntersectionObserver;\n return;\n }\n scope['IntersectionObserver'] = class extends EngineIntersectionObserver {\n private readonly args: [unknown, unknown];\n private other: NativeObserver | null = null;\n\n constructor(callback: Callback, options?: Options) {\n super(callback, options);\n this.args = [callback, options];\n }\n\n override observe(target: EngineNode): void {\n if (isEngineNode(target)) super.observe(target);\n else (this.other ??= new native(...this.args)).observe(target);\n }\n\n override unobserve(target: EngineNode): void {\n if (isEngineNode(target)) super.unobserve(target);\n else this.other?.unobserve(target);\n }\n\n override disconnect(): void {\n super.disconnect();\n this.other?.disconnect();\n }\n };\n}\n"]}
1
+ {"version":3,"file":"defer-triggers.js","sourceRoot":"","sources":["../src/defer-triggers.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * What Angular's `@defer (on interaction | hover | viewport)` asks of a trigger element, for the\n * engine's nodes.\n *\n * Angular registers those three triggers on the element itself rather than through `Renderer2`:\n * it asserts in development that the element is an `Element`, listens with `addEventListener`,\n * and watches for visibility with a global `IntersectionObserver`. An engine node was none of\n * those, so the placeholder stayed forever and every render logged an assertion. The listeners\n * are on the node (`addEventListener` in `engine.ts`); this is the other two.\n *\n * `installDeferTriggers` runs once, from `mount()`, before anything renders.\n */\nimport { isEngineNode, viewNameOf, type EngineNode, type WindowFrame } from './engine.ts';\nimport { letEngineNodesPass, type Constructor } from './node-global.ts';\n\n/** The views a node scrolls inside of, and whose scrolling can bring it into view. */\nconst SCROLLERS = new Set(['ScrollView', 'AndroidHorizontalScrollView']);\n\ninterface Entry {\n readonly target: EngineNode;\n readonly isIntersecting: boolean;\n readonly intersectionRatio: number;\n}\n\ntype Callback = (entries: Entry[], observer: EngineIntersectionObserver) => void;\n\ninterface Options {\n readonly threshold?: number | readonly number[];\n}\n\ninterface Watched {\n readonly stops: (() => void)[];\n}\n\n/**\n * Visibility for engine nodes, from the layout and scroll events native already sends.\n *\n * A node is checked when it is observed, when it is laid out, and whenever a scroll view it sits\n * in scrolls. The check measures the node in window coordinates, clips it by each scroll view\n * around it and by the window, and reports it intersecting once the visible share reaches the\n * threshold: any of it by default, as the web does, and a node of no size counts once its position\n * is inside. `root` and `rootMargin` are not applied; the root is always the window.\n */\nexport class EngineIntersectionObserver {\n private readonly callback: Callback;\n private readonly threshold: number;\n private readonly watched = new Map<EngineNode, Watched>();\n\n constructor(callback: Callback, options?: Options) {\n this.callback = callback;\n const threshold = options?.threshold;\n this.threshold = Array.isArray(threshold)\n ? Math.min(...(threshold as number[]))\n : ((threshold as number | undefined) ?? 0);\n }\n\n observe(target: EngineNode): void {\n if (this.watched.has(target)) return;\n const check = () => this.check(target);\n const stops = [target.engine!.setEventListener(target, 'topLayout', check)];\n for (let at = target.parent; at; at = at.parent) {\n if (!SCROLLERS.has(viewNameOf(at))) continue;\n stops.push(at.engine!.setEventListener(at, 'topScroll', check));\n }\n this.watched.set(target, { stops });\n // A node laid out before it was observed sends no layout event of its own. Measured now,\n // after the commit that mounted it, and in a microtask, as an observer never calls back from\n // inside `observe`.\n queueMicrotask(check);\n }\n\n unobserve(target: EngineNode): void {\n const watched = this.watched.get(target);\n if (!watched) return;\n for (const stop of watched.stops) stop();\n this.watched.delete(target);\n }\n\n disconnect(): void {\n for (const target of [...this.watched.keys()]) this.unobserve(target);\n }\n\n takeRecords(): Entry[] {\n return [];\n }\n\n private check(target: EngineNode): void {\n if (!this.watched.has(target)) return;\n const ratio = visibleShare(target);\n if (ratio === null) return;\n const isIntersecting = this.threshold > 0 ? ratio >= this.threshold : ratio >= 0;\n if (isIntersecting) this.callback([{ target, isIntersecting, intersectionRatio: ratio }], this);\n }\n}\n\n/** A frame as its four edges. */\ninterface Box {\n left: number;\n top: number;\n right: number;\n bottom: number;\n}\n\nconst box = (frame: WindowFrame): Box => ({\n left: frame.x,\n top: frame.y,\n right: frame.x + frame.width,\n bottom: frame.y + frame.height,\n});\n\nfunction measured(node: EngineNode): Box | null {\n let found: Box | null = null;\n node.engine!.measure(node, (frame) => (found = box(frame)));\n return found;\n}\n\nfunction clip(into: Box, by: Box): void {\n into.left = Math.max(into.left, by.left);\n into.top = Math.max(into.top, by.top);\n into.right = Math.min(into.right, by.right);\n into.bottom = Math.min(into.bottom, by.bottom);\n}\n\n/**\n * How much of the node is on screen, from 0 to 1; below 0 when none of it is, and null when it\n * has not been measured. Measuring is synchronous on the new architecture.\n */\nfunction visibleShare(target: EngineNode): number | null {\n const frame = measured(target);\n if (!frame) return null;\n const visible = { ...frame };\n for (let at = target.parent; at; at = at.parent) {\n if (!SCROLLERS.has(viewNameOf(at))) continue;\n const scroller = measured(at);\n if (scroller) clip(visible, scroller);\n }\n const window = (target.engine as { viewport?: { width: number; height: number } }).viewport;\n if (window && window.width > 0 && window.height > 0) {\n clip(visible, { left: 0, top: 0, right: window.width, bottom: window.height });\n }\n const width = visible.right - visible.left;\n const height = visible.bottom - visible.top;\n if (width < 0 || height < 0) return -1;\n const area = (frame.right - frame.left) * (frame.bottom - frame.top);\n return area > 0 ? (width * height) / area : 1;\n}\n\n/** React Native's own `IntersectionObserver`, when its feature flag has installed one. */\ninterface NativeObserver {\n observe(target: unknown): void;\n unobserve(target: unknown): void;\n disconnect(): void;\n}\ntype NativeObserverClass = new (callback: unknown, options?: unknown) => NativeObserver;\n\n// Never reset: the globals it patches stay patched for the life of the process.\nlet installed = false;\n\n/**\n * Let an engine node pass Angular's development check that a trigger is an `Element`, and give\n * `@defer (on viewport)` an `IntersectionObserver` that can watch one.\n *\n * React Native defines a global `Element` for its own DOM-like nodes, so an engine node is made to\n * answer `instanceof Element` as well, and nothing else about that class changes. Node has none,\n * and gets one that only engine nodes are instances of. An `IntersectionObserver` React Native\n * already has is kept for its own nodes; engine nodes are watched by the one above.\n */\nexport function installDeferTriggers(): void {\n if (installed) return;\n installed = true;\n const scope = globalThis as unknown as Record<string, unknown>;\n\n const existing = scope['Element'] as Constructor | undefined;\n if (existing) {\n letEngineNodesPass(existing);\n } else {\n scope['Element'] = class Element {\n static [Symbol.hasInstance](value: unknown): boolean {\n return isEngineNode(value);\n }\n };\n }\n\n const native = scope['IntersectionObserver'] as NativeObserverClass | undefined;\n if (!native) {\n scope['IntersectionObserver'] = EngineIntersectionObserver;\n return;\n }\n scope['IntersectionObserver'] = class extends EngineIntersectionObserver {\n private readonly args: [unknown, unknown];\n private other: NativeObserver | null = null;\n\n constructor(callback: Callback, options?: Options) {\n super(callback, options);\n this.args = [callback, options];\n }\n\n override observe(target: EngineNode): void {\n if (isEngineNode(target)) super.observe(target);\n else (this.other ??= new native(...this.args)).observe(target);\n }\n\n override unobserve(target: EngineNode): void {\n if (isEngineNode(target)) super.unobserve(target);\n else this.other?.unobserve(target);\n }\n\n override disconnect(): void {\n super.disconnect();\n this.other?.disconnect();\n }\n };\n}\n"]}