@ng-native/fabric 0.16.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.
@@ -147,7 +147,8 @@ export class NativeScrollDriver {
147
147
  * `afterCommit` until both views exist.
148
148
  */
149
149
  drive(view, source, feed, property, range, statics, tagOf, shift = null) {
150
- const drive = { viewTag: null, range, shift, nodes: null, stopped: false };
150
+ const after = statics.flatMap((entry) => Object.entries(entry).map(([property, value]) => ({ property, value })));
151
+ const drive = { viewTag: null, range, shift, after, nodes: null, stopped: false };
151
152
  const key = feedKey(feed);
152
153
  const connect = () => {
153
154
  if (drive.stopped)
@@ -158,26 +159,35 @@ export class NativeScrollDriver {
158
159
  return false;
159
160
  drive.viewTag = viewTag;
160
161
  const offset = this.offset(source, sourceTag, feed, key);
161
- drive.nodes = this.build(offset.value, viewTag, property, drive, statics);
162
+ drive.nodes = this.build(offset.value, viewTag, property, drive);
162
163
  this.hold(view, viewTag, drive.nodes.props, ['transform']);
163
164
  this.flush();
164
165
  return true;
165
166
  };
166
167
  if (!connect())
167
168
  this.pending.add(connect);
169
+ const rebuild = () => {
170
+ if (!drive.nodes || drive.viewTag === null)
171
+ return;
172
+ this.tearDown(drive.nodes, drive.viewTag);
173
+ this.letGo(view, drive.nodes.props);
174
+ const offset = this.offsets.get(source).get(key);
175
+ drive.nodes = this.build(offset.value, drive.viewTag, property, drive);
176
+ this.hold(view, drive.viewTag, drive.nodes.props, ['transform']);
177
+ this.flush();
178
+ };
168
179
  return {
169
180
  update: (next) => {
170
181
  if (drive.stopped || sameRange(drive.range, next))
171
182
  return;
172
183
  drive.range = next;
173
- if (!drive.nodes || drive.viewTag === null)
184
+ rebuild();
185
+ },
186
+ follow: (entries) => {
187
+ if (drive.stopped || sameFollowing(drive.after, entries))
174
188
  return;
175
- this.tearDown(drive.nodes, drive.viewTag);
176
- this.letGo(view, drive.nodes.props);
177
- const offset = this.offsets.get(source).get(key);
178
- drive.nodes = this.build(offset.value, drive.viewTag, property, drive, statics);
179
- this.hold(view, drive.viewTag, drive.nodes.props, ['transform']);
180
- this.flush();
189
+ drive.after = entries;
190
+ rebuild();
181
191
  },
182
192
  shift: (amount) => {
183
193
  if (drive.stopped || drive.shift === null || drive.shift === amount)
@@ -262,8 +272,12 @@ export class NativeScrollDriver {
262
272
  * of the last iteration; `stop` lets the view go, and stops an animation still playing.
263
273
  *
264
274
  * Null where the native module cannot start an animation, and the caller plays it itself.
275
+ *
276
+ * With `lend`, the transform is not set on the view: its entries are handed to `lend` once
277
+ * built, for a graph that sets the view's transform already to apply, and `lend` is told null
278
+ * before they go.
265
279
  */
266
- play(view, channels, timing, tagOf, ended) {
280
+ play(view, channels, timing, tagOf, ended, lend) {
267
281
  const { API } = this.native;
268
282
  const start = API.startAnimatingNode;
269
283
  if (!start || !API.stopAnimation || !this.native.generateNewAnimationId)
@@ -284,7 +298,7 @@ export class NativeScrollDriver {
284
298
  state.viewTag = viewTag;
285
299
  state.value = this.native.generateNewNodeTag();
286
300
  API.createAnimatedNode(state.value, { type: 'value', value: 0, offset: 0 });
287
- state.nodes = this.buildChannels(view, state.value, viewTag, channels);
301
+ state.nodes = this.buildPlayed(view, state.value, viewTag, channels, lend);
288
302
  state.id = this.native.generateNewAnimationId();
289
303
  const config = { type: 'frames', frames: [...timing.frames], toValue: timing.toValue };
290
304
  start(state.id, state.value, { ...config, iterations: timing.iterations }, (result) => {
@@ -314,29 +328,53 @@ export class NativeScrollDriver {
314
328
  return;
315
329
  if (state.id)
316
330
  API.stopAnimation(state.id);
331
+ if (lend && channels.transform.length)
332
+ lend(null);
317
333
  this.dropChannels(view, state.nodes, state.viewTag);
318
334
  API.dropAnimatedNode(state.value);
319
335
  this.flush();
320
336
  },
321
337
  };
322
338
  }
339
+ /**
340
+ * The nodes for what `play` plays: a transform handed to `lend` is set by another graph, and
341
+ * with nothing else to set the view has no props node.
342
+ */
343
+ buildPlayed(view, value, viewTag, channels, lend) {
344
+ if (!lend || !channels.transform.length) {
345
+ return this.buildChannels(view, value, viewTag, channels);
346
+ }
347
+ const lent = [];
348
+ lend(channels.transform.map((channel) => 'range' in channel
349
+ ? { property: channel.property, node: this.interpolation(value, channel.range, lent) }
350
+ : channel));
351
+ const rest = { ...channels, transform: [] };
352
+ if (!rest.opacity && !Object.keys(rest.colors ?? {}).length) {
353
+ return { props: null, nodes: lent.reverse() };
354
+ }
355
+ const built = this.buildChannels(view, value, viewTag, rest);
356
+ return { props: built.props, nodes: [...built.nodes, ...lent.reverse()] };
357
+ }
358
+ /** An interpolation from `value`, clamped at both ends, noted in `made`. */
359
+ interpolation(value, range, made) {
360
+ const { API } = this.native;
361
+ const tag = this.native.generateNewNodeTag();
362
+ API.createAnimatedNode(tag, {
363
+ type: 'interpolation',
364
+ inputRange: [...range.input],
365
+ outputRange: [...range.output],
366
+ extrapolateLeft: 'clamp',
367
+ extrapolateRight: 'clamp',
368
+ });
369
+ API.connectAnimatedNodes(value, tag);
370
+ made.push(tag);
371
+ return tag;
372
+ }
323
373
  /** The nodes for a set of channels, connected to the view; the props node first. */
324
374
  buildChannels(view, value, viewTag, channels) {
325
375
  const { API } = this.native;
326
376
  const made = [];
327
- const interpolation = (range) => {
328
- const tag = this.native.generateNewNodeTag();
329
- API.createAnimatedNode(tag, {
330
- type: 'interpolation',
331
- inputRange: [...range.input],
332
- outputRange: [...range.output],
333
- extrapolateLeft: 'clamp',
334
- extrapolateRight: 'clamp',
335
- });
336
- API.connectAnimatedNodes(value, tag);
337
- made.push(tag);
338
- return tag;
339
- };
377
+ const interpolation = (range) => this.interpolation(value, range, made);
340
378
  const style = {};
341
379
  if (channels.opacity)
342
380
  style['opacity'] = interpolation(channels.opacity);
@@ -371,13 +409,15 @@ export class NativeScrollDriver {
371
409
  API.connectAnimatedNodes(styleTag, props);
372
410
  API.connectAnimatedNodeToView(props, viewTag);
373
411
  this.hold(view, viewTag, props, channelKeys(channels));
374
- return [props, styleTag, ...made.reverse()];
412
+ return { props, nodes: [props, styleTag, ...made.reverse()] };
375
413
  }
376
- dropChannels(view, nodes, viewTag) {
414
+ dropChannels(view, built, viewTag) {
377
415
  const { API } = this.native;
378
- this.letGo(view, nodes[0]);
379
- API.disconnectAnimatedNodeFromView(nodes[0], viewTag);
380
- for (const tag of nodes)
416
+ if (built.props !== null) {
417
+ this.letGo(view, built.props);
418
+ API.disconnectAnimatedNodeFromView(built.props, viewTag);
419
+ }
420
+ for (const tag of built.nodes)
381
421
  API.dropAnimatedNode(tag);
382
422
  }
383
423
  /** Connects every drive still waiting for its views, now that a commit may have made them. */
@@ -420,7 +460,7 @@ export class NativeScrollDriver {
420
460
  }
421
461
  this.native.API.dropAnimatedNode(offset.value);
422
462
  }
423
- build(value, viewTag, property, drive, statics) {
463
+ build(value, viewTag, property, drive) {
424
464
  const { API } = this.native;
425
465
  const range = drive.range;
426
466
  const interpolation = this.native.generateNewNodeTag();
@@ -448,13 +488,12 @@ export class NativeScrollDriver {
448
488
  property,
449
489
  nodeTag: sum ?? interpolation,
450
490
  },
451
- ...statics.flatMap((entry) => Object.entries(entry).map(([property, amount]) => ({
452
- type: 'static',
453
- property,
454
- value: amount,
455
- }))),
491
+ ...drive.after.map((entry) => 'node' in entry
492
+ ? { type: 'animated', property: entry.property, nodeTag: entry.node }
493
+ : { type: 'static', property: entry.property, value: entry.value }),
456
494
  ],
457
495
  });
496
+ const followed = drive.after.flatMap((entry) => ('node' in entry ? [entry.node] : []));
458
497
  // A style node between, as `Animated` builds it: RN's props node on iOS reads its values from
459
498
  // a style node and ignores a transform node connected to it directly.
460
499
  const style = this.native.generateNewNodeTag();
@@ -470,16 +509,21 @@ export class NativeScrollDriver {
470
509
  else {
471
510
  API.connectAnimatedNodes(interpolation, transform);
472
511
  }
512
+ for (const node of followed)
513
+ API.connectAnimatedNodes(node, transform);
473
514
  API.connectAnimatedNodes(transform, style);
474
515
  API.connectAnimatedNodes(style, props);
475
516
  API.connectAnimatedNodeToView(props, viewTag);
476
- return { interpolation, shift, sum, transform, style, props };
517
+ return { interpolation, shift, sum, transform, style, props, followed };
477
518
  }
478
519
  tearDown(nodes, viewTag) {
479
520
  const { API } = this.native;
480
521
  API.disconnectAnimatedNodeFromView(nodes.props, viewTag);
481
522
  API.dropAnimatedNode(nodes.props);
482
523
  API.dropAnimatedNode(nodes.style);
524
+ // Another graph's nodes outlast this one: none of them is left feeding a node that is gone.
525
+ for (const node of nodes.followed)
526
+ API.disconnectAnimatedNodes(node, nodes.transform);
483
527
  API.dropAnimatedNode(nodes.transform);
484
528
  if (nodes.sum !== null)
485
529
  API.dropAnimatedNode(nodes.sum);
@@ -498,6 +542,17 @@ function feedKey(feed) {
498
542
  export function scrollFeed(axis) {
499
543
  return { events: ['onScroll'], path: ['contentOffset', axis] };
500
544
  }
545
+ function sameFollowing(a, b) {
546
+ return (a.length === b.length &&
547
+ a.every((entry, i) => {
548
+ const other = b[i];
549
+ if (entry.property !== other.property)
550
+ return false;
551
+ return 'node' in entry
552
+ ? 'node' in other && entry.node === other.node
553
+ : 'value' in other && entry.value === other.value;
554
+ }));
555
+ }
501
556
  function sameRange(a, b) {
502
557
  return (a.input.length === b.input.length &&
503
558
  a.input.every((value, i) => value === b.input[i]) &&
@@ -1 +1 @@
1
- {"version":3,"file":"native-drive.js","sourceRoot":"","sources":["../src/native-drive.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * A view moved by a scroll view's offset on the native side, with no JavaScript in between.\n *\n * A sticky header moved by a transform set from each scroll event lags the scroll: the event\n * reaches JavaScript, the transform is committed, and by the time Fabric mounts it the content has\n * moved on, so on a fast fling the header shudders and comes away from the edge it is pinned to.\n * React Native's own sticky headers do not, because `ScrollViewStickyHeader` maps the offset onto\n * an animated value on the native side and interpolates the header's translate from it there.\n * This is that mapping, for the engine's nodes: the scroll view's offset along one axis feeds a\n * value, the value an interpolation, the interpolation a translate, and native applies it on every\n * frame the scroll view moves.\n *\n * It goes through React Native's own `NativeAnimatedHelper`, whose node tags every other animated\n * value in the app also comes from, so none of them can collide.\n */\n\n/** The part of React Native's `NativeAnimatedHelper` default export this uses. */\nexport interface NativeAnimated {\n generateNewNodeTag(): number;\n generateNewAnimationId?(): number;\n readonly API: {\n /** Run a value through `config` on the native side, and say when it has ended. */\n startAnimatingNode?(\n animationId: number,\n nodeTag: number,\n config: object,\n end: (result: { finished: boolean }) => void,\n ): void;\n stopAnimation?(animationId: number): void;\n createAnimatedNode(tag: number, config: object): void;\n connectAnimatedNodes(parentTag: number, childTag: number): void;\n disconnectAnimatedNodes(parentTag: number, childTag: number): void;\n connectAnimatedNodeToView(nodeTag: number, viewTag: number): void;\n disconnectAnimatedNodeFromView(nodeTag: number, viewTag: number): void;\n dropAnimatedNode(tag: number): void;\n addAnimatedEventToView(\n viewTag: number,\n eventName: string,\n mapping: { nativeEventPath: string[]; animatedValueTag: number },\n ): void;\n removeAnimatedEventFromView(viewTag: number, eventName: string, nodeTag: number): void;\n setAnimatedNodeValue(nodeTag: number, value: number): void;\n flushQueue?(): void;\n };\n}\n\nimport type { DrivenChannels } from './scroll-animation.ts';\n\nexport type ScrollAxis = 'x' | 'y';\n\n/** A native event that feeds a value: the events carrying it, and the path to it in each. */\nexport interface EventFeed {\n readonly events: readonly string[];\n readonly path: readonly string[];\n}\n\n/** What a driven view moves along. */\nexport type DrivenProperty = 'translateX' | 'translateY';\n\n/** Where a driven view sits for each scroll offset, as an interpolation clamped at both ends. */\nexport interface ScrollRange {\n readonly input: readonly number[];\n readonly output: readonly number[];\n}\n\n/** A transform native keeps beside the driven translate, such as an inverted list's flip. */\nexport type StaticTransform = Readonly<Record<string, number>>;\n\n/**\n * A view moved by a scroll. `update` moves it by a new range; `shift` adds an amount to where the\n * range puts it, for a drive made with one; `stop` lets it go.\n */\nexport interface ScrollDrive {\n update(range: ScrollRange): void;\n shift(amount: number): void;\n stop(): void;\n}\n\ninterface Offset {\n readonly value: number;\n readonly viewTag: number;\n readonly feed: EventFeed;\n users: number;\n}\n\ninterface Nodes {\n interpolation: number;\n /** The shift JavaScript sets, and the sum of it and the interpolation, for a shifted drive. */\n shift: number | null;\n sum: number | null;\n transform: number;\n style: number;\n props: number;\n}\n\ninterface Drive {\n viewTag: number | null;\n range: ScrollRange;\n /** The amount added to the range's translate, or null for a drive without one. */\n shift: number | null;\n nodes: Nodes | null;\n stopped: boolean;\n}\n\n/**\n * Told of each view a graph is connected to, with the props it sets there. Once a graph has set\n * a view's `transform` or `opacity`, React Native lets no commit change it again: iOS skips both\n * for good (`propKeysManagedByAnimated`), and Android puts the last value set back over each\n * commit's (`overrideBySynchronousMountPropsAtMountingAndroid`), until the view is made again.\n */\nexport type Touched = (view: object, viewTag: number, keys: readonly string[]) => void;\n\n/**\n * What a view is set to on native with no animation, where a graph has set it before: see\n * `NativeScrollDriver.set`. A transform is each entry's amount: points, a factor, or an angle in\n * radians.\n */\nexport interface SetValues {\n opacity?: number;\n transform?: readonly { readonly property: string; readonly value: number }[];\n}\n\n/** The graph that sets a view's values: a value node for each number, by its path. */\ninterface Setter {\n readonly tag: number;\n readonly shape: string;\n readonly props: number;\n /** Every node made, the props node first, for dropping them. */\n readonly nodes: readonly number[];\n readonly leaves: ReadonlyMap<string, number>;\n}\n\n/** The style keys a graph's channels set. */\nfunction channelKeys(channels: DrivenChannels): string[] {\n const keys = Object.keys(channels.colors ?? {});\n if (channels.opacity) keys.push('opacity');\n if (channels.transform.length) keys.push('transform');\n return keys;\n}\n\n/** Every number a set of values holds, by its path in the graph. */\nfunction leavesOf(values: SetValues): Map<string, number> {\n const leaves = new Map<string, number>();\n if (values.opacity !== undefined) leaves.set('opacity', values.opacity);\n values.transform?.forEach((entry, at) => leaves.set(`transform.${at}`, entry.value));\n return leaves;\n}\n\n/** What makes two sets of values the same graph: which keys, and the transform's properties. */\nfunction shapeOf(values: SetValues): string {\n const transform = values.transform?.map((entry) => entry.property).join(',');\n return `${values.opacity === undefined ? '' : 'o'}|${transform ?? '-'}`;\n}\n\nconst NONE_HELD: ReadonlySet<string> = new Set();\n\nexport class NativeScrollDriver {\n private readonly native: NativeAnimated;\n private readonly touched: Touched | undefined;\n /** One value per source view and feed, by the feed's key. */\n private readonly offsets = new Map<object, Map<string, Offset>>();\n private readonly pending = new Set<() => boolean>();\n /** The keys each graph connected to a view sets, by its props node, while it is connected. */\n private readonly live = new WeakMap<object, Map<number, readonly string[]>>();\n /** The graph setting each view's values, where one does: see `set`. */\n private readonly setters = new WeakMap<object, Setter>();\n\n constructor(native: NativeAnimated, touched?: Touched) {\n this.native = native;\n this.touched = touched;\n }\n\n /** The style keys a graph of this driver's playing or driving a view sets on it now. */\n held(view: object): ReadonlySet<string> {\n const graphs = this.live.get(view);\n return graphs ? new Set([...graphs.values()].flat()) : NONE_HELD;\n }\n\n /**\n * Set a view's values on native, where a graph that has let it go set them before and no commit\n * can now (see `Touched`). One graph per view, connected until the view is let go or a graph\n * that plays it is connected: a value node for each number, set where it changed.\n */\n set(view: object, viewTag: number, values: SetValues): void {\n const { API } = this.native;\n const shape = shapeOf(values);\n let setter = this.setters.get(view);\n const fresh = setter?.tag !== viewTag || setter.shape !== shape;\n if (fresh) {\n this.forget(view);\n setter = this.buildSetter(viewTag, shape, values);\n this.setters.set(view, setter);\n this.touched?.(view, viewTag, Object.keys(values));\n }\n for (const [path, value] of leavesOf(values)) {\n API.setAnimatedNodeValue(setter!.leaves.get(path)!, value);\n }\n this.flush();\n }\n\n /** Let go of a view `set` set values on: it is made again, or gone. */\n forget(view: object): void {\n const setter = this.setters.get(view);\n if (!setter) return;\n this.setters.delete(view);\n const { API } = this.native;\n API.disconnectAnimatedNodeFromView(setter.props, setter.tag);\n for (const node of setter.nodes) API.dropAnimatedNode(node);\n this.flush();\n }\n\n private buildSetter(viewTag: number, shape: string, values: SetValues): Setter {\n const { API } = this.native;\n const nodes: number[] = [];\n const leaves = new Map<string, number>();\n const made = (config: object): number => {\n const node = this.native.generateNewNodeTag();\n API.createAnimatedNode(node, config);\n nodes.push(node);\n return node;\n };\n const leaf = (path: string, value: number): number => {\n const node = made({ type: 'value', value, offset: 0 });\n leaves.set(path, node);\n return node;\n };\n const style: Record<string, number> = {};\n if (values.opacity !== undefined) style['opacity'] = leaf('opacity', values.opacity);\n if (values.transform) {\n const transforms = values.transform.map((entry, at) => ({\n type: 'animated',\n property: entry.property,\n nodeTag: leaf(`transform.${at}`, entry.value),\n }));\n const transform = made({ type: 'transform', transforms });\n for (const entry of transforms) API.connectAnimatedNodes(entry.nodeTag, transform);\n style['transform'] = transform;\n }\n // A style node between, as `Animated` builds it: see `build`.\n const styleNode = made({ type: 'style', style });\n for (const node of Object.values(style)) API.connectAnimatedNodes(node, styleNode);\n const props = made({ type: 'props', props: { style: styleNode } });\n API.connectAnimatedNodes(styleNode, props);\n API.connectAnimatedNodeToView(props, viewTag);\n return { tag: viewTag, shape, props, nodes: nodes.reverse(), leaves };\n }\n\n /**\n * Note a graph connected to a view, for `held`, and tell whoever asked of it. The graph that\n * set the view's values lets go: the one that plays it sets them from here.\n */\n private hold(view: object, viewTag: number, props: number, keys: readonly string[]): void {\n this.forget(view);\n const graphs = this.live.get(view) ?? new Map<number, readonly string[]>();\n this.live.set(view, graphs.set(props, keys));\n this.touched?.(view, viewTag, keys);\n }\n\n private letGo(view: object, props: number): void {\n const graphs = this.live.get(view);\n if (graphs?.delete(props) && !graphs.size) this.live.delete(view);\n }\n\n /**\n * Move a view by a scroll. `tagOf` answers a node's view tag once it has been committed, and\n * null before, which is why the connection may wait for a commit: `connect` is tried again by\n * `afterCommit` until both views exist.\n */\n drive(\n view: object,\n source: object,\n feed: EventFeed,\n property: DrivenProperty,\n range: ScrollRange,\n statics: readonly StaticTransform[],\n tagOf: (node: object) => number | null,\n shift: number | null = null,\n ): ScrollDrive {\n const drive: Drive = { viewTag: null, range, shift, nodes: null, stopped: false };\n const key = feedKey(feed);\n const connect = (): boolean => {\n if (drive.stopped) return true;\n const viewTag = tagOf(view);\n const sourceTag = tagOf(source);\n if (viewTag === null || sourceTag === null) return false;\n drive.viewTag = viewTag;\n const offset = this.offset(source, sourceTag, feed, key);\n drive.nodes = this.build(offset.value, viewTag, property, drive, statics);\n this.hold(view, viewTag, drive.nodes.props, ['transform']);\n this.flush();\n return true;\n };\n if (!connect()) this.pending.add(connect);\n return {\n update: (next) => {\n if (drive.stopped || sameRange(drive.range, next)) return;\n drive.range = next;\n if (!drive.nodes || drive.viewTag === null) return;\n this.tearDown(drive.nodes, drive.viewTag);\n this.letGo(view, drive.nodes.props);\n const offset = this.offsets.get(source)!.get(key)!;\n drive.nodes = this.build(offset.value, drive.viewTag, property, drive, statics);\n this.hold(view, drive.viewTag, drive.nodes.props, ['transform']);\n this.flush();\n },\n shift: (amount) => {\n if (drive.stopped || drive.shift === null || drive.shift === amount) return;\n drive.shift = amount;\n if (drive.nodes?.shift == null) return;\n this.native.API.setAnimatedNodeValue(drive.nodes.shift, amount);\n this.flush();\n },\n stop: () => {\n if (drive.stopped) return;\n drive.stopped = true;\n this.pending.delete(connect);\n if (!drive.nodes || drive.viewTag === null) return;\n this.tearDown(drive.nodes, drive.viewTag);\n this.letGo(view, drive.nodes.props);\n this.release(source, key);\n this.flush();\n },\n };\n }\n\n /**\n * Play a view's opacity and transform by a scroll: each channel an interpolation from the\n * offset, as `scroll-animation.ts` lays a `@keyframes` animation along it. `update` rebuilds\n * the channels, when the scroll view says how far it scrolls; `stop` lets the view go.\n */\n animate(\n view: object,\n source: object,\n feed: EventFeed,\n channels: DrivenChannels,\n tagOf: (node: object) => number | null,\n ): { update(channels: DrivenChannels): void; stop(): void } {\n const state = {\n channels,\n viewTag: null as number | null,\n nodes: null as number[] | null,\n stopped: false,\n };\n const key = feedKey(feed);\n const connect = (): boolean => {\n if (state.stopped) return true;\n const viewTag = tagOf(view);\n const sourceTag = tagOf(source);\n if (viewTag === null || sourceTag === null) return false;\n state.viewTag = viewTag;\n const offset = this.offset(source, sourceTag, feed, key);\n state.nodes = this.buildChannels(view, offset.value, viewTag, state.channels);\n this.flush();\n return true;\n };\n if (!connect()) this.pending.add(connect);\n return {\n update: (next) => {\n if (state.stopped) return;\n state.channels = next;\n if (!state.nodes || state.viewTag === null) return;\n this.dropChannels(view, state.nodes, state.viewTag);\n const offset = this.offsets.get(source)!.get(key)!;\n state.nodes = this.buildChannels(view, offset.value, state.viewTag, next);\n this.flush();\n },\n stop: () => {\n if (state.stopped) return;\n state.stopped = true;\n this.pending.delete(connect);\n if (!state.nodes || state.viewTag === null) return;\n this.dropChannels(view, state.nodes, state.viewTag);\n this.release(source, key);\n this.flush();\n },\n };\n }\n\n /**\n * Play a view's opacity and transform by the clock: each channel an interpolation from a value\n * native runs from nothing to `timing.toValue`, over the frames it is given, as many times as\n * asked. Nothing runs in JavaScript while it plays. `ended` is told when native reaches the end\n * of the last iteration; `stop` lets the view go, and stops an animation still playing.\n *\n * Null where the native module cannot start an animation, and the caller plays it itself.\n */\n play(\n view: object,\n channels: DrivenChannels,\n timing: { frames: readonly number[]; toValue: number; iterations: number },\n tagOf: (node: object) => number | null,\n ended: () => void,\n ): { stop(): void } | null {\n const { API } = this.native;\n const start = API.startAnimatingNode;\n if (!start || !API.stopAnimation || !this.native.generateNewAnimationId) return null;\n const state = {\n viewTag: null as number | null,\n nodes: null as number[] | null,\n value: 0,\n id: 0,\n over: false,\n };\n const connect = (): boolean => {\n if (state.over) return true;\n const viewTag = tagOf(view);\n if (viewTag === null) return false;\n state.viewTag = viewTag;\n state.value = this.native.generateNewNodeTag();\n API.createAnimatedNode(state.value, { type: 'value', value: 0, offset: 0 });\n state.nodes = this.buildChannels(view, state.value, viewTag, channels);\n state.id = this.native.generateNewAnimationId!();\n const config = { type: 'frames', frames: [...timing.frames], toValue: timing.toValue };\n start(state.id, state.value, { ...config, iterations: timing.iterations }, (result) => {\n // Stopped rather than finished is the caller's own doing, and it knows.\n if (!result.finished || state.over) return;\n state.id = 0;\n // Written once more, to the view as it is now. A view is mounted when the task that\n // made it is over, and an animation no longer than that task is over before there is a\n // view to move: the view is then mounted at the frame the animation started from.\n API.setAnimatedNodeValue(state.value, timing.toValue);\n this.flush();\n ended();\n });\n this.flush();\n return true;\n };\n if (!connect()) this.pending.add(connect);\n return {\n stop: () => {\n if (state.over) return;\n state.over = true;\n this.pending.delete(connect);\n if (!state.nodes || state.viewTag === null) return;\n if (state.id) API.stopAnimation!(state.id);\n this.dropChannels(view, state.nodes, state.viewTag);\n API.dropAnimatedNode(state.value);\n this.flush();\n },\n };\n }\n\n /** The nodes for a set of channels, connected to the view; the props node first. */\n private buildChannels(\n view: object,\n value: number,\n viewTag: number,\n channels: DrivenChannels,\n ): number[] {\n const { API } = this.native;\n const made: number[] = [];\n const interpolation = (range: ScrollRange): number => {\n const tag = this.native.generateNewNodeTag();\n API.createAnimatedNode(tag, {\n type: 'interpolation',\n inputRange: [...range.input],\n outputRange: [...range.output],\n extrapolateLeft: 'clamp',\n extrapolateRight: 'clamp',\n });\n API.connectAnimatedNodes(value, tag);\n made.push(tag);\n return tag;\n };\n const style: Record<string, number> = {};\n if (channels.opacity) style['opacity'] = interpolation(channels.opacity);\n for (const [property, parts] of Object.entries(channels.colors ?? {})) {\n const [r, g, b, a] = parts.map(interpolation);\n const colour = this.native.generateNewNodeTag();\n API.createAnimatedNode(colour, { type: 'color', r, g, b, a });\n for (const part of [r, g, b, a]) API.connectAnimatedNodes(part!, colour);\n style[property] = colour;\n made.push(colour);\n }\n if (channels.transform.length) {\n const transforms = channels.transform.map((channel) =>\n 'range' in channel\n ? { type: 'animated', property: channel.property, nodeTag: interpolation(channel.range) }\n : { type: 'static', property: channel.property, value: channel.value },\n );\n const transform = this.native.generateNewNodeTag();\n API.createAnimatedNode(transform, { type: 'transform', transforms });\n for (const entry of transforms) {\n if (entry.type === 'animated') API.connectAnimatedNodes(entry.nodeTag!, transform);\n }\n style['transform'] = transform;\n made.push(transform);\n }\n const styleTag = this.native.generateNewNodeTag();\n API.createAnimatedNode(styleTag, { type: 'style', style });\n for (const tag of Object.values(style)) API.connectAnimatedNodes(tag, styleTag);\n const props = this.native.generateNewNodeTag();\n API.createAnimatedNode(props, { type: 'props', props: { style: styleTag } });\n API.connectAnimatedNodes(styleTag, props);\n API.connectAnimatedNodeToView(props, viewTag);\n this.hold(view, viewTag, props, channelKeys(channels));\n return [props, styleTag, ...made.reverse()];\n }\n\n private dropChannels(view: object, nodes: readonly number[], viewTag: number): void {\n const { API } = this.native;\n this.letGo(view, nodes[0]!);\n API.disconnectAnimatedNodeFromView(nodes[0]!, viewTag);\n for (const tag of nodes) API.dropAnimatedNode(tag);\n }\n\n /** Connects every drive still waiting for its views, now that a commit may have made them. */\n afterCommit(): void {\n for (const connect of [...this.pending]) if (connect()) this.pending.delete(connect);\n }\n\n /** One value per source view and feed, fed by its events, shared by every view it drives. */\n private offset(source: object, viewTag: number, feed: EventFeed, key: string): Offset {\n let feeds = this.offsets.get(source);\n if (!feeds) this.offsets.set(source, (feeds = new Map()));\n let offset = feeds.get(key);\n if (!offset) {\n const value = this.native.generateNewNodeTag();\n this.native.API.createAnimatedNode(value, { type: 'value', value: 0, offset: 0 });\n for (const event of feed.events) {\n this.native.API.addAnimatedEventToView(viewTag, event, {\n nativeEventPath: [...feed.path],\n animatedValueTag: value,\n });\n }\n offset = { value, viewTag, feed, users: 0 };\n feeds.set(key, offset);\n }\n offset.users++;\n return offset;\n }\n\n private release(source: object, key: string): void {\n const feeds = this.offsets.get(source);\n const offset = feeds?.get(key);\n if (!feeds || !offset || --offset.users > 0) return;\n feeds.delete(key);\n if (feeds.size === 0) this.offsets.delete(source);\n for (const event of offset.feed.events) {\n this.native.API.removeAnimatedEventFromView(offset.viewTag, event, offset.value);\n }\n this.native.API.dropAnimatedNode(offset.value);\n }\n\n private build(\n value: number,\n viewTag: number,\n property: DrivenProperty,\n drive: Drive,\n statics: readonly StaticTransform[],\n ): Nodes {\n const { API } = this.native;\n const range = drive.range;\n const interpolation = this.native.generateNewNodeTag();\n API.createAnimatedNode(interpolation, {\n type: 'interpolation',\n inputRange: [...range.input],\n outputRange: [...range.output],\n extrapolateLeft: 'clamp',\n extrapolateRight: 'clamp',\n });\n let shift: number | null = null;\n let sum: number | null = null;\n if (drive.shift !== null) {\n shift = this.native.generateNewNodeTag();\n API.createAnimatedNode(shift, { type: 'value', value: drive.shift, offset: 0 });\n sum = this.native.generateNewNodeTag();\n API.createAnimatedNode(sum, { type: 'addition', input: [interpolation, shift] });\n }\n const transform = this.native.generateNewNodeTag();\n API.createAnimatedNode(transform, {\n type: 'transform',\n transforms: [\n {\n type: 'animated',\n property,\n nodeTag: sum ?? interpolation,\n },\n ...statics.flatMap((entry) =>\n Object.entries(entry).map(([property, amount]) => ({\n type: 'static',\n property,\n value: amount,\n })),\n ),\n ],\n });\n // A style node between, as `Animated` builds it: RN's props node on iOS reads its values from\n // a style node and ignores a transform node connected to it directly.\n const style = this.native.generateNewNodeTag();\n API.createAnimatedNode(style, { type: 'style', style: { transform } });\n const props = this.native.generateNewNodeTag();\n API.createAnimatedNode(props, { type: 'props', props: { style } });\n API.connectAnimatedNodes(value, interpolation);\n if (shift !== null && sum !== null) {\n API.connectAnimatedNodes(interpolation, sum);\n API.connectAnimatedNodes(shift, sum);\n API.connectAnimatedNodes(sum, transform);\n } else {\n API.connectAnimatedNodes(interpolation, transform);\n }\n API.connectAnimatedNodes(transform, style);\n API.connectAnimatedNodes(style, props);\n API.connectAnimatedNodeToView(props, viewTag);\n return { interpolation, shift, sum, transform, style, props };\n }\n\n private tearDown(nodes: Nodes, viewTag: number): void {\n const { API } = this.native;\n API.disconnectAnimatedNodeFromView(nodes.props, viewTag);\n API.dropAnimatedNode(nodes.props);\n API.dropAnimatedNode(nodes.style);\n API.dropAnimatedNode(nodes.transform);\n if (nodes.sum !== null) API.dropAnimatedNode(nodes.sum);\n if (nodes.shift !== null) API.dropAnimatedNode(nodes.shift);\n API.dropAnimatedNode(nodes.interpolation);\n }\n\n private flush(): void {\n this.native.API.flushQueue?.();\n }\n}\n\nfunction feedKey(feed: EventFeed): string {\n return `${feed.events.join(',')}:${feed.path.join('.')}`;\n}\n\n/** A scroll view's offset along an axis, as `onScroll` carries it. */\nexport function scrollFeed(axis: ScrollAxis): EventFeed {\n return { events: ['onScroll'], path: ['contentOffset', axis] };\n}\n\nfunction sameRange(a: ScrollRange, b: ScrollRange): boolean {\n return (\n a.input.length === b.input.length &&\n a.input.every((value, i) => value === b.input[i]) &&\n a.output.every((value, i) => value === b.output[i])\n );\n}\n\n/**\n * The translate a pinned view needs at each scroll offset: none until the offset reaches where\n * the view starts, then the offset past that, until `until`, where the next pinned view pushes it\n * off and it stays. `start` and `until` are in the scroll view's own coordinates.\n */\nexport function pinnedRange(start: number, until = Infinity): ScrollRange {\n if (!Number.isFinite(until) || until <= start) {\n // A large finite end, since native interpolation takes numbers and extends nothing here.\n return { input: [start, start + 1e7], output: [0, 1e7] };\n }\n return { input: [start, until], output: [0, until - start] };\n}\n"]}
1
+ {"version":3,"file":"native-drive.js","sourceRoot":"","sources":["../src/native-drive.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * A view moved by a scroll view's offset on the native side, with no JavaScript in between.\n *\n * A sticky header moved by a transform set from each scroll event lags the scroll: the event\n * reaches JavaScript, the transform is committed, and by the time Fabric mounts it the content has\n * moved on, so on a fast fling the header shudders and comes away from the edge it is pinned to.\n * React Native's own sticky headers do not, because `ScrollViewStickyHeader` maps the offset onto\n * an animated value on the native side and interpolates the header's translate from it there.\n * This is that mapping, for the engine's nodes: the scroll view's offset along one axis feeds a\n * value, the value an interpolation, the interpolation a translate, and native applies it on every\n * frame the scroll view moves.\n *\n * It goes through React Native's own `NativeAnimatedHelper`, whose node tags every other animated\n * value in the app also comes from, so none of them can collide.\n */\n\n/** The part of React Native's `NativeAnimatedHelper` default export this uses. */\nexport interface NativeAnimated {\n generateNewNodeTag(): number;\n generateNewAnimationId?(): number;\n readonly API: {\n /** Run a value through `config` on the native side, and say when it has ended. */\n startAnimatingNode?(\n animationId: number,\n nodeTag: number,\n config: object,\n end: (result: { finished: boolean }) => void,\n ): void;\n stopAnimation?(animationId: number): void;\n createAnimatedNode(tag: number, config: object): void;\n connectAnimatedNodes(parentTag: number, childTag: number): void;\n disconnectAnimatedNodes(parentTag: number, childTag: number): void;\n connectAnimatedNodeToView(nodeTag: number, viewTag: number): void;\n disconnectAnimatedNodeFromView(nodeTag: number, viewTag: number): void;\n dropAnimatedNode(tag: number): void;\n addAnimatedEventToView(\n viewTag: number,\n eventName: string,\n mapping: { nativeEventPath: string[]; animatedValueTag: number },\n ): void;\n removeAnimatedEventFromView(viewTag: number, eventName: string, nodeTag: number): void;\n setAnimatedNodeValue(nodeTag: number, value: number): void;\n flushQueue?(): void;\n };\n}\n\nimport type { DrivenChannels } from './scroll-animation.ts';\n\nexport type ScrollAxis = 'x' | 'y';\n\n/** A native event that feeds a value: the events carrying it, and the path to it in each. */\nexport interface EventFeed {\n readonly events: readonly string[];\n readonly path: readonly string[];\n}\n\n/** What a driven view moves along. */\nexport type DrivenProperty = 'translateX' | 'translateY';\n\n/** Where a driven view sits for each scroll offset, as an interpolation clamped at both ends. */\nexport interface ScrollRange {\n readonly input: readonly number[];\n readonly output: readonly number[];\n}\n\n/** A transform native keeps beside the driven translate, such as an inverted list's flip. */\nexport type StaticTransform = Readonly<Record<string, number>>;\n\n/**\n * A view moved by a scroll. `update` moves it by a new range; `shift` adds an amount to where the\n * range puts it, for a drive made with one; `stop` lets it go.\n */\nexport interface ScrollDrive {\n update(range: ScrollRange): void;\n shift(amount: number): void;\n stop(): void;\n}\n\n/**\n * A transform entry native applies after a drive's translate: an amount, or a node of another\n * graph's that native moves, such as a transition's along its clock.\n */\nexport type FollowingTransform =\n | { readonly property: string; readonly value: number }\n | { readonly property: string; readonly node: number };\n\n/** A drive whose transform after its translate can change. */\nexport interface ComposedDrive extends ScrollDrive {\n /** Have native apply these after the translate, in place of what it applied after it before. */\n follow(entries: readonly FollowingTransform[]): void;\n}\n\ninterface Offset {\n readonly value: number;\n readonly viewTag: number;\n readonly feed: EventFeed;\n users: number;\n}\n\ninterface Nodes {\n interpolation: number;\n /** The shift JavaScript sets, and the sum of it and the interpolation, for a shifted drive. */\n shift: number | null;\n sum: number | null;\n transform: number;\n style: number;\n props: number;\n /** The nodes of other graphs' the transform applies after the translate. */\n followed: readonly number[];\n}\n\ninterface Drive {\n viewTag: number | null;\n range: ScrollRange;\n /** The amount added to the range's translate, or null for a drive without one. */\n shift: number | null;\n /** What native applies after the translate. */\n after: readonly FollowingTransform[];\n nodes: Nodes | null;\n stopped: boolean;\n}\n\n/**\n * Told of each view a graph is connected to, with the props it sets there. Once a graph has set\n * a view's `transform` or `opacity`, React Native lets no commit change it again: iOS skips both\n * for good (`propKeysManagedByAnimated`), and Android puts the last value set back over each\n * commit's (`overrideBySynchronousMountPropsAtMountingAndroid`), until the view is made again.\n */\nexport type Touched = (view: object, viewTag: number, keys: readonly string[]) => void;\n\n/**\n * What a view is set to on native with no animation, where a graph has set it before: see\n * `NativeScrollDriver.set`. A transform is each entry's amount: points, a factor, or an angle in\n * radians.\n */\nexport interface SetValues {\n opacity?: number;\n transform?: readonly { readonly property: string; readonly value: number }[];\n}\n\n/** The graph that sets a view's values: a value node for each number, by its path. */\ninterface Setter {\n readonly tag: number;\n readonly shape: string;\n readonly props: number;\n /** Every node made, the props node first, for dropping them. */\n readonly nodes: readonly number[];\n readonly leaves: ReadonlyMap<string, number>;\n}\n\n/** The style keys a graph's channels set. */\nfunction channelKeys(channels: DrivenChannels): string[] {\n const keys = Object.keys(channels.colors ?? {});\n if (channels.opacity) keys.push('opacity');\n if (channels.transform.length) keys.push('transform');\n return keys;\n}\n\n/** Every number a set of values holds, by its path in the graph. */\nfunction leavesOf(values: SetValues): Map<string, number> {\n const leaves = new Map<string, number>();\n if (values.opacity !== undefined) leaves.set('opacity', values.opacity);\n values.transform?.forEach((entry, at) => leaves.set(`transform.${at}`, entry.value));\n return leaves;\n}\n\n/** What makes two sets of values the same graph: which keys, and the transform's properties. */\nfunction shapeOf(values: SetValues): string {\n const transform = values.transform?.map((entry) => entry.property).join(',');\n return `${values.opacity === undefined ? '' : 'o'}|${transform ?? '-'}`;\n}\n\nconst NONE_HELD: ReadonlySet<string> = new Set();\n\n/** The nodes a set of channels was built of: the props node, where there is one, first. */\ninterface Built {\n readonly props: number | null;\n readonly nodes: readonly number[];\n}\n\nexport class NativeScrollDriver {\n private readonly native: NativeAnimated;\n private readonly touched: Touched | undefined;\n /** One value per source view and feed, by the feed's key. */\n private readonly offsets = new Map<object, Map<string, Offset>>();\n private readonly pending = new Set<() => boolean>();\n /** The keys each graph connected to a view sets, by its props node, while it is connected. */\n private readonly live = new WeakMap<object, Map<number, readonly string[]>>();\n /** The graph setting each view's values, where one does: see `set`. */\n private readonly setters = new WeakMap<object, Setter>();\n\n constructor(native: NativeAnimated, touched?: Touched) {\n this.native = native;\n this.touched = touched;\n }\n\n /** The style keys a graph of this driver's playing or driving a view sets on it now. */\n held(view: object): ReadonlySet<string> {\n const graphs = this.live.get(view);\n return graphs ? new Set([...graphs.values()].flat()) : NONE_HELD;\n }\n\n /**\n * Set a view's values on native, where a graph that has let it go set them before and no commit\n * can now (see `Touched`). One graph per view, connected until the view is let go or a graph\n * that plays it is connected: a value node for each number, set where it changed.\n */\n set(view: object, viewTag: number, values: SetValues): void {\n const { API } = this.native;\n const shape = shapeOf(values);\n let setter = this.setters.get(view);\n const fresh = setter?.tag !== viewTag || setter.shape !== shape;\n if (fresh) {\n this.forget(view);\n setter = this.buildSetter(viewTag, shape, values);\n this.setters.set(view, setter);\n this.touched?.(view, viewTag, Object.keys(values));\n }\n for (const [path, value] of leavesOf(values)) {\n API.setAnimatedNodeValue(setter!.leaves.get(path)!, value);\n }\n this.flush();\n }\n\n /** Let go of a view `set` set values on: it is made again, or gone. */\n forget(view: object): void {\n const setter = this.setters.get(view);\n if (!setter) return;\n this.setters.delete(view);\n const { API } = this.native;\n API.disconnectAnimatedNodeFromView(setter.props, setter.tag);\n for (const node of setter.nodes) API.dropAnimatedNode(node);\n this.flush();\n }\n\n private buildSetter(viewTag: number, shape: string, values: SetValues): Setter {\n const { API } = this.native;\n const nodes: number[] = [];\n const leaves = new Map<string, number>();\n const made = (config: object): number => {\n const node = this.native.generateNewNodeTag();\n API.createAnimatedNode(node, config);\n nodes.push(node);\n return node;\n };\n const leaf = (path: string, value: number): number => {\n const node = made({ type: 'value', value, offset: 0 });\n leaves.set(path, node);\n return node;\n };\n const style: Record<string, number> = {};\n if (values.opacity !== undefined) style['opacity'] = leaf('opacity', values.opacity);\n if (values.transform) {\n const transforms = values.transform.map((entry, at) => ({\n type: 'animated',\n property: entry.property,\n nodeTag: leaf(`transform.${at}`, entry.value),\n }));\n const transform = made({ type: 'transform', transforms });\n for (const entry of transforms) API.connectAnimatedNodes(entry.nodeTag, transform);\n style['transform'] = transform;\n }\n // A style node between, as `Animated` builds it: see `build`.\n const styleNode = made({ type: 'style', style });\n for (const node of Object.values(style)) API.connectAnimatedNodes(node, styleNode);\n const props = made({ type: 'props', props: { style: styleNode } });\n API.connectAnimatedNodes(styleNode, props);\n API.connectAnimatedNodeToView(props, viewTag);\n return { tag: viewTag, shape, props, nodes: nodes.reverse(), leaves };\n }\n\n /**\n * Note a graph connected to a view, for `held`, and tell whoever asked of it. The graph that\n * set the view's values lets go: the one that plays it sets them from here.\n */\n private hold(view: object, viewTag: number, props: number, keys: readonly string[]): void {\n this.forget(view);\n const graphs = this.live.get(view) ?? new Map<number, readonly string[]>();\n this.live.set(view, graphs.set(props, keys));\n this.touched?.(view, viewTag, keys);\n }\n\n private letGo(view: object, props: number): void {\n const graphs = this.live.get(view);\n if (graphs?.delete(props) && !graphs.size) this.live.delete(view);\n }\n\n /**\n * Move a view by a scroll. `tagOf` answers a node's view tag once it has been committed, and\n * null before, which is why the connection may wait for a commit: `connect` is tried again by\n * `afterCommit` until both views exist.\n */\n drive(\n view: object,\n source: object,\n feed: EventFeed,\n property: DrivenProperty,\n range: ScrollRange,\n statics: readonly StaticTransform[],\n tagOf: (node: object) => number | null,\n shift: number | null = null,\n ): ComposedDrive {\n const after = statics.flatMap((entry) =>\n Object.entries(entry).map(([property, value]) => ({ property, value })),\n );\n const drive: Drive = { viewTag: null, range, shift, after, nodes: null, stopped: false };\n const key = feedKey(feed);\n const connect = (): boolean => {\n if (drive.stopped) return true;\n const viewTag = tagOf(view);\n const sourceTag = tagOf(source);\n if (viewTag === null || sourceTag === null) return false;\n drive.viewTag = viewTag;\n const offset = this.offset(source, sourceTag, feed, key);\n drive.nodes = this.build(offset.value, viewTag, property, drive);\n this.hold(view, viewTag, drive.nodes.props, ['transform']);\n this.flush();\n return true;\n };\n if (!connect()) this.pending.add(connect);\n const rebuild = () => {\n if (!drive.nodes || drive.viewTag === null) return;\n this.tearDown(drive.nodes, drive.viewTag);\n this.letGo(view, drive.nodes.props);\n const offset = this.offsets.get(source)!.get(key)!;\n drive.nodes = this.build(offset.value, drive.viewTag, property, drive);\n this.hold(view, drive.viewTag, drive.nodes.props, ['transform']);\n this.flush();\n };\n return {\n update: (next) => {\n if (drive.stopped || sameRange(drive.range, next)) return;\n drive.range = next;\n rebuild();\n },\n follow: (entries) => {\n if (drive.stopped || sameFollowing(drive.after, entries)) return;\n drive.after = entries;\n rebuild();\n },\n shift: (amount) => {\n if (drive.stopped || drive.shift === null || drive.shift === amount) return;\n drive.shift = amount;\n if (drive.nodes?.shift == null) return;\n this.native.API.setAnimatedNodeValue(drive.nodes.shift, amount);\n this.flush();\n },\n stop: () => {\n if (drive.stopped) return;\n drive.stopped = true;\n this.pending.delete(connect);\n if (!drive.nodes || drive.viewTag === null) return;\n this.tearDown(drive.nodes, drive.viewTag);\n this.letGo(view, drive.nodes.props);\n this.release(source, key);\n this.flush();\n },\n };\n }\n\n /**\n * Play a view's opacity and transform by a scroll: each channel an interpolation from the\n * offset, as `scroll-animation.ts` lays a `@keyframes` animation along it. `update` rebuilds\n * the channels, when the scroll view says how far it scrolls; `stop` lets the view go.\n */\n animate(\n view: object,\n source: object,\n feed: EventFeed,\n channels: DrivenChannels,\n tagOf: (node: object) => number | null,\n ): { update(channels: DrivenChannels): void; stop(): void } {\n const state = {\n channels,\n viewTag: null as number | null,\n nodes: null as Built | null,\n stopped: false,\n };\n const key = feedKey(feed);\n const connect = (): boolean => {\n if (state.stopped) return true;\n const viewTag = tagOf(view);\n const sourceTag = tagOf(source);\n if (viewTag === null || sourceTag === null) return false;\n state.viewTag = viewTag;\n const offset = this.offset(source, sourceTag, feed, key);\n state.nodes = this.buildChannels(view, offset.value, viewTag, state.channels);\n this.flush();\n return true;\n };\n if (!connect()) this.pending.add(connect);\n return {\n update: (next) => {\n if (state.stopped) return;\n state.channels = next;\n if (!state.nodes || state.viewTag === null) return;\n this.dropChannels(view, state.nodes, state.viewTag);\n const offset = this.offsets.get(source)!.get(key)!;\n state.nodes = this.buildChannels(view, offset.value, state.viewTag, next);\n this.flush();\n },\n stop: () => {\n if (state.stopped) return;\n state.stopped = true;\n this.pending.delete(connect);\n if (!state.nodes || state.viewTag === null) return;\n this.dropChannels(view, state.nodes, state.viewTag);\n this.release(source, key);\n this.flush();\n },\n };\n }\n\n /**\n * Play a view's opacity and transform by the clock: each channel an interpolation from a value\n * native runs from nothing to `timing.toValue`, over the frames it is given, as many times as\n * asked. Nothing runs in JavaScript while it plays. `ended` is told when native reaches the end\n * of the last iteration; `stop` lets the view go, and stops an animation still playing.\n *\n * Null where the native module cannot start an animation, and the caller plays it itself.\n *\n * With `lend`, the transform is not set on the view: its entries are handed to `lend` once\n * built, for a graph that sets the view's transform already to apply, and `lend` is told null\n * before they go.\n */\n play(\n view: object,\n channels: DrivenChannels,\n timing: { frames: readonly number[]; toValue: number; iterations: number },\n tagOf: (node: object) => number | null,\n ended: () => void,\n lend?: (entries: readonly FollowingTransform[] | null) => void,\n ): { stop(): void } | null {\n const { API } = this.native;\n const start = API.startAnimatingNode;\n if (!start || !API.stopAnimation || !this.native.generateNewAnimationId) return null;\n const state = {\n viewTag: null as number | null,\n nodes: null as Built | null,\n value: 0,\n id: 0,\n over: false,\n };\n const connect = (): boolean => {\n if (state.over) return true;\n const viewTag = tagOf(view);\n if (viewTag === null) return false;\n state.viewTag = viewTag;\n state.value = this.native.generateNewNodeTag();\n API.createAnimatedNode(state.value, { type: 'value', value: 0, offset: 0 });\n state.nodes = this.buildPlayed(view, state.value, viewTag, channels, lend);\n state.id = this.native.generateNewAnimationId!();\n const config = { type: 'frames', frames: [...timing.frames], toValue: timing.toValue };\n start(state.id, state.value, { ...config, iterations: timing.iterations }, (result) => {\n // Stopped rather than finished is the caller's own doing, and it knows.\n if (!result.finished || state.over) return;\n state.id = 0;\n // Written once more, to the view as it is now. A view is mounted when the task that\n // made it is over, and an animation no longer than that task is over before there is a\n // view to move: the view is then mounted at the frame the animation started from.\n API.setAnimatedNodeValue(state.value, timing.toValue);\n this.flush();\n ended();\n });\n this.flush();\n return true;\n };\n if (!connect()) this.pending.add(connect);\n return {\n stop: () => {\n if (state.over) return;\n state.over = true;\n this.pending.delete(connect);\n if (!state.nodes || state.viewTag === null) return;\n if (state.id) API.stopAnimation!(state.id);\n if (lend && channels.transform.length) lend(null);\n this.dropChannels(view, state.nodes, state.viewTag);\n API.dropAnimatedNode(state.value);\n this.flush();\n },\n };\n }\n\n /**\n * The nodes for what `play` plays: a transform handed to `lend` is set by another graph, and\n * with nothing else to set the view has no props node.\n */\n private buildPlayed(\n view: object,\n value: number,\n viewTag: number,\n channels: DrivenChannels,\n lend: ((entries: readonly FollowingTransform[] | null) => void) | undefined,\n ): Built {\n if (!lend || !channels.transform.length) {\n return this.buildChannels(view, value, viewTag, channels);\n }\n const lent: number[] = [];\n lend(\n channels.transform.map((channel) =>\n 'range' in channel\n ? { property: channel.property, node: this.interpolation(value, channel.range, lent) }\n : channel,\n ),\n );\n const rest = { ...channels, transform: [] };\n if (!rest.opacity && !Object.keys(rest.colors ?? {}).length) {\n return { props: null, nodes: lent.reverse() };\n }\n const built = this.buildChannels(view, value, viewTag, rest);\n return { props: built.props, nodes: [...built.nodes, ...lent.reverse()] };\n }\n\n /** An interpolation from `value`, clamped at both ends, noted in `made`. */\n private interpolation(value: number, range: ScrollRange, made: number[]): number {\n const { API } = this.native;\n const tag = this.native.generateNewNodeTag();\n API.createAnimatedNode(tag, {\n type: 'interpolation',\n inputRange: [...range.input],\n outputRange: [...range.output],\n extrapolateLeft: 'clamp',\n extrapolateRight: 'clamp',\n });\n API.connectAnimatedNodes(value, tag);\n made.push(tag);\n return tag;\n }\n\n /** The nodes for a set of channels, connected to the view; the props node first. */\n private buildChannels(\n view: object,\n value: number,\n viewTag: number,\n channels: DrivenChannels,\n ): Built {\n const { API } = this.native;\n const made: number[] = [];\n const interpolation = (range: ScrollRange) => this.interpolation(value, range, made);\n const style: Record<string, number> = {};\n if (channels.opacity) style['opacity'] = interpolation(channels.opacity);\n for (const [property, parts] of Object.entries(channels.colors ?? {})) {\n const [r, g, b, a] = parts.map(interpolation);\n const colour = this.native.generateNewNodeTag();\n API.createAnimatedNode(colour, { type: 'color', r, g, b, a });\n for (const part of [r, g, b, a]) API.connectAnimatedNodes(part!, colour);\n style[property] = colour;\n made.push(colour);\n }\n if (channels.transform.length) {\n const transforms = channels.transform.map((channel) =>\n 'range' in channel\n ? { type: 'animated', property: channel.property, nodeTag: interpolation(channel.range) }\n : { type: 'static', property: channel.property, value: channel.value },\n );\n const transform = this.native.generateNewNodeTag();\n API.createAnimatedNode(transform, { type: 'transform', transforms });\n for (const entry of transforms) {\n if (entry.type === 'animated') API.connectAnimatedNodes(entry.nodeTag!, transform);\n }\n style['transform'] = transform;\n made.push(transform);\n }\n const styleTag = this.native.generateNewNodeTag();\n API.createAnimatedNode(styleTag, { type: 'style', style });\n for (const tag of Object.values(style)) API.connectAnimatedNodes(tag, styleTag);\n const props = this.native.generateNewNodeTag();\n API.createAnimatedNode(props, { type: 'props', props: { style: styleTag } });\n API.connectAnimatedNodes(styleTag, props);\n API.connectAnimatedNodeToView(props, viewTag);\n this.hold(view, viewTag, props, channelKeys(channels));\n return { props, nodes: [props, styleTag, ...made.reverse()] };\n }\n\n private dropChannels(view: object, built: Built, viewTag: number): void {\n const { API } = this.native;\n if (built.props !== null) {\n this.letGo(view, built.props);\n API.disconnectAnimatedNodeFromView(built.props, viewTag);\n }\n for (const tag of built.nodes) API.dropAnimatedNode(tag);\n }\n\n /** Connects every drive still waiting for its views, now that a commit may have made them. */\n afterCommit(): void {\n for (const connect of [...this.pending]) if (connect()) this.pending.delete(connect);\n }\n\n /** One value per source view and feed, fed by its events, shared by every view it drives. */\n private offset(source: object, viewTag: number, feed: EventFeed, key: string): Offset {\n let feeds = this.offsets.get(source);\n if (!feeds) this.offsets.set(source, (feeds = new Map()));\n let offset = feeds.get(key);\n if (!offset) {\n const value = this.native.generateNewNodeTag();\n this.native.API.createAnimatedNode(value, { type: 'value', value: 0, offset: 0 });\n for (const event of feed.events) {\n this.native.API.addAnimatedEventToView(viewTag, event, {\n nativeEventPath: [...feed.path],\n animatedValueTag: value,\n });\n }\n offset = { value, viewTag, feed, users: 0 };\n feeds.set(key, offset);\n }\n offset.users++;\n return offset;\n }\n\n private release(source: object, key: string): void {\n const feeds = this.offsets.get(source);\n const offset = feeds?.get(key);\n if (!feeds || !offset || --offset.users > 0) return;\n feeds.delete(key);\n if (feeds.size === 0) this.offsets.delete(source);\n for (const event of offset.feed.events) {\n this.native.API.removeAnimatedEventFromView(offset.viewTag, event, offset.value);\n }\n this.native.API.dropAnimatedNode(offset.value);\n }\n\n private build(value: number, viewTag: number, property: DrivenProperty, drive: Drive): Nodes {\n const { API } = this.native;\n const range = drive.range;\n const interpolation = this.native.generateNewNodeTag();\n API.createAnimatedNode(interpolation, {\n type: 'interpolation',\n inputRange: [...range.input],\n outputRange: [...range.output],\n extrapolateLeft: 'clamp',\n extrapolateRight: 'clamp',\n });\n let shift: number | null = null;\n let sum: number | null = null;\n if (drive.shift !== null) {\n shift = this.native.generateNewNodeTag();\n API.createAnimatedNode(shift, { type: 'value', value: drive.shift, offset: 0 });\n sum = this.native.generateNewNodeTag();\n API.createAnimatedNode(sum, { type: 'addition', input: [interpolation, shift] });\n }\n const transform = this.native.generateNewNodeTag();\n API.createAnimatedNode(transform, {\n type: 'transform',\n transforms: [\n {\n type: 'animated',\n property,\n nodeTag: sum ?? interpolation,\n },\n ...drive.after.map((entry) =>\n 'node' in entry\n ? { type: 'animated', property: entry.property, nodeTag: entry.node }\n : { type: 'static', property: entry.property, value: entry.value },\n ),\n ],\n });\n const followed = drive.after.flatMap((entry) => ('node' in entry ? [entry.node] : []));\n // A style node between, as `Animated` builds it: RN's props node on iOS reads its values from\n // a style node and ignores a transform node connected to it directly.\n const style = this.native.generateNewNodeTag();\n API.createAnimatedNode(style, { type: 'style', style: { transform } });\n const props = this.native.generateNewNodeTag();\n API.createAnimatedNode(props, { type: 'props', props: { style } });\n API.connectAnimatedNodes(value, interpolation);\n if (shift !== null && sum !== null) {\n API.connectAnimatedNodes(interpolation, sum);\n API.connectAnimatedNodes(shift, sum);\n API.connectAnimatedNodes(sum, transform);\n } else {\n API.connectAnimatedNodes(interpolation, transform);\n }\n for (const node of followed) API.connectAnimatedNodes(node, transform);\n API.connectAnimatedNodes(transform, style);\n API.connectAnimatedNodes(style, props);\n API.connectAnimatedNodeToView(props, viewTag);\n return { interpolation, shift, sum, transform, style, props, followed };\n }\n\n private tearDown(nodes: Nodes, viewTag: number): void {\n const { API } = this.native;\n API.disconnectAnimatedNodeFromView(nodes.props, viewTag);\n API.dropAnimatedNode(nodes.props);\n API.dropAnimatedNode(nodes.style);\n // Another graph's nodes outlast this one: none of them is left feeding a node that is gone.\n for (const node of nodes.followed) API.disconnectAnimatedNodes(node, nodes.transform);\n API.dropAnimatedNode(nodes.transform);\n if (nodes.sum !== null) API.dropAnimatedNode(nodes.sum);\n if (nodes.shift !== null) API.dropAnimatedNode(nodes.shift);\n API.dropAnimatedNode(nodes.interpolation);\n }\n\n private flush(): void {\n this.native.API.flushQueue?.();\n }\n}\n\nfunction feedKey(feed: EventFeed): string {\n return `${feed.events.join(',')}:${feed.path.join('.')}`;\n}\n\n/** A scroll view's offset along an axis, as `onScroll` carries it. */\nexport function scrollFeed(axis: ScrollAxis): EventFeed {\n return { events: ['onScroll'], path: ['contentOffset', axis] };\n}\n\nfunction sameFollowing(a: readonly FollowingTransform[], b: readonly FollowingTransform[]) {\n return (\n a.length === b.length &&\n a.every((entry, i) => {\n const other = b[i]!;\n if (entry.property !== other.property) return false;\n return 'node' in entry\n ? 'node' in other && entry.node === other.node\n : 'value' in other && entry.value === other.value;\n })\n );\n}\n\nfunction sameRange(a: ScrollRange, b: ScrollRange): boolean {\n return (\n a.input.length === b.input.length &&\n a.input.every((value, i) => value === b.input[i]) &&\n a.output.every((value, i) => value === b.output[i])\n );\n}\n\n/**\n * The translate a pinned view needs at each scroll offset: none until the offset reaches where\n * the view starts, then the offset past that, until `until`, where the next pinned view pushes it\n * off and it stays. `start` and `until` are in the scroll view's own coordinates.\n */\nexport function pinnedRange(start: number, until = Infinity): ScrollRange {\n if (!Number.isFinite(until) || until <= start) {\n // A large finite end, since native interpolation takes numbers and extends nothing here.\n return { input: [start, start + 1e7], output: [0, 1e7] };\n }\n return { input: [start, until], output: [0, until - start] };\n}\n"]}
@@ -0,0 +1,2 @@
1
+ /** One turn of the frame loop, or the macrotask queue where there is no loop to wait on. */
2
+ export declare const nextFrame: () => Promise<void>;
@@ -0,0 +1,10 @@
1
+ /** One turn of the frame loop, or the macrotask queue where there is no loop to wait on. */
2
+ export const nextFrame = () => new Promise((resolve) => {
3
+ const raf = globalThis
4
+ .requestAnimationFrame;
5
+ if (raf)
6
+ raf(() => resolve());
7
+ else
8
+ setTimeout(resolve, 0);
9
+ });
10
+ //# sourceMappingURL=next-frame.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"next-frame.js","sourceRoot":"","sources":["../src/next-frame.ts"],"names":[],"mappings":"AAAA,4FAA4F;AAC5F,MAAM,CAAC,MAAM,SAAS,GAAG,GAAkB,EAAE,CAC3C,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;IACtB,MAAM,GAAG,GAAI,UAAyE;SACnF,qBAAqB,CAAC;IACzB,IAAI,GAAG;QAAE,GAAG,CAAC,GAAG,EAAE,CAAC,OAAO,EAAE,CAAC,CAAC;;QACzB,UAAU,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;AAC9B,CAAC,CAAC,CAAC","sourcesContent":["/** One turn of the frame loop, or the macrotask queue where there is no loop to wait on. */\nexport const nextFrame = (): Promise<void> =>\n new Promise((resolve) => {\n const raf = (globalThis as { requestAnimationFrame?: (callback: () => void) => void })\n .requestAnimationFrame;\n if (raf) raf(() => resolve());\n else setTimeout(resolve, 0);\n });\n"]}
@@ -60,13 +60,14 @@ export declare function clockChannels(tracks: ReadonlyMap<string, Track>, spec:
60
60
  };
61
61
  /**
62
62
  * A transform as native's transform node holds it, entry by entry, each move by a share as the
63
- * points it is of the box `sizeOf` answers. Null for one native cannot take that way: a matrix,
64
- * or a share of a box with no size yet.
63
+ * points it is of the box `sizeOf` answers and a flat matrix as the move, turn, skew and scale it
64
+ * is. Null for one native cannot take that way: a matrix in depth, or a share of a box with no
65
+ * size yet.
65
66
  */
66
67
  export declare function heldTransform(value: unknown, sizeOf: () => {
67
68
  width: number;
68
69
  height: number;
69
- } | undefined): {
70
+ } | undefined, skews: boolean): {
70
71
  property: string;
71
72
  value: number;
72
73
  }[] | null;
@@ -155,14 +155,74 @@ function heldGroup(resting) {
155
155
  }
156
156
  /**
157
157
  * A transform as native's transform node holds it, entry by entry, each move by a share as the
158
- * points it is of the box `sizeOf` answers. Null for one native cannot take that way: a matrix,
159
- * or a share of a box with no size yet.
158
+ * points it is of the box `sizeOf` answers and a flat matrix as the move, turn, skew and scale it
159
+ * is. Null for one native cannot take that way: a matrix in depth, or a share of a box with no
160
+ * size yet.
160
161
  */
161
- export function heldTransform(value, sizeOf) {
162
+ export function heldTransform(value, sizeOf, skews) {
162
163
  const size = sharesIn(value) ? sizeOf() : undefined;
163
- const channels = heldGroup(size ? inPoints(value, size) : value);
164
+ const channels = heldGroup(flatMatrices(size ? inPoints(value, size) : value, skews));
164
165
  return channels;
165
166
  }
167
+ /** Where each number of a flat matrix is in React Native's sixteen, by column. */
168
+ const FLAT = { a: 0, b: 1, c: 4, d: 5, e: 12, f: 13 };
169
+ /** What the rest of a flat matrix's sixteen are. */
170
+ const FLAT_REST = [
171
+ [2, 0],
172
+ [3, 0],
173
+ [6, 0],
174
+ [7, 0],
175
+ [8, 0],
176
+ [9, 0],
177
+ [10, 1],
178
+ [11, 0],
179
+ [14, 0],
180
+ [15, 1],
181
+ ];
182
+ /** A transform list with each flat matrix in it as the entries `flatMatrix` makes of it. */
183
+ function flatMatrices(value, skews) {
184
+ const matrixOf = (entry) => entry?.matrix;
185
+ if (!Array.isArray(value) || !value.some((entry) => matrixOf(entry) !== undefined))
186
+ return value;
187
+ return value.flatMap((entry) => flatMatrix(matrixOf(entry), skews) ?? [entry]);
188
+ }
189
+ /**
190
+ * A matrix in two dimensions as the move, turn, skew and scale it is, in that order, as CSS
191
+ * decomposes one: numbers native's transform node takes. Null for one in three dimensions, one
192
+ * that flattens the view to a line, or one with a skew where the platform draws none, which
193
+ * native cannot be set to.
194
+ *
195
+ * Once a graph has set a view's transform, no commit changes it again (see `Touched`), so a
196
+ * matrix bound after a native animation that native is not set to leaves the view where the
197
+ * animation ended.
198
+ */
199
+ function flatMatrix(raw, skews) {
200
+ if (!Array.isArray(raw) || raw.length !== 16 || !raw.every(Number.isFinite))
201
+ return null;
202
+ const m = raw;
203
+ if (FLAT_REST.some(([index, value]) => m[index] !== value))
204
+ return null;
205
+ const [a, b, c, d] = [m[FLAT.a], m[FLAT.b], m[FLAT.c], m[FLAT.d]];
206
+ const scaleX = Math.hypot(a, b);
207
+ if (scaleX === 0)
208
+ return null;
209
+ const [cos, sin] = [a / scaleX, b / scaleX];
210
+ const shear = cos * c + sin * d;
211
+ const scaleY = cos * (d - sin * shear) - sin * (c - cos * shear);
212
+ if (scaleY === 0)
213
+ return null;
214
+ // Android draws no skew: React Native leaves `skewX` out there, so a sheared matrix is left as it is.
215
+ if (!skews && Math.abs(shear) > 1e-9)
216
+ return null;
217
+ return [
218
+ { translateX: m[FLAT.e] },
219
+ { translateY: m[FLAT.f] },
220
+ { rotate: Math.atan2(sin, cos) },
221
+ { skewX: Math.atan(shear / scaleY) },
222
+ { scaleX },
223
+ { scaleY },
224
+ ];
225
+ }
166
226
  function restingAmount(resting, index, key, identity) {
167
227
  const entry = Array.isArray(resting) ? resting[index] : undefined;
168
228
  return (entry && key in entry ? amount(key, entry[key]) : null) ?? identity;