react-native-gtkx 0.2.0-alpha.2 → 0.3.0-alpha.1
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/README.md +5 -2
- package/dist/aliases/index.d.ts +84 -0
- package/dist/aliases/index.js +208 -0
- package/dist/aliases/index.js.map +1 -0
- package/dist/animated/index.d.ts +2 -0
- package/dist/animated/index.js +5 -0
- package/dist/animated/index.js.map +1 -1
- package/dist/animated/types.d.ts +1 -0
- package/dist/animated/types.js.map +1 -1
- package/dist/animated/value-animation.js +17 -4
- package/dist/animated/value-animation.js.map +1 -1
- package/dist/apis/host.gtkx.js +9 -12
- package/dist/apis/host.gtkx.js.map +1 -1
- package/dist/apis/index.d.ts +4 -2
- package/dist/apis/index.js +2 -0
- package/dist/apis/index.js.map +1 -1
- package/dist/apis/keyboard.d.ts +60 -0
- package/dist/apis/keyboard.js +63 -0
- package/dist/apis/keyboard.js.map +1 -0
- package/dist/apis/log-box.d.ts +15 -0
- package/dist/apis/log-box.js +46 -0
- package/dist/apis/log-box.js.map +1 -0
- package/dist/apis/platform.d.ts +18 -1
- package/dist/apis/platform.js.map +1 -1
- package/dist/common/index.d.ts +0 -1
- package/dist/common/index.js +24 -1
- package/dist/common/index.js.map +1 -1
- package/dist/components/animated.d.ts +70 -6
- package/dist/components/animated.js +559 -46
- package/dist/components/animated.js.map +1 -1
- package/dist/components/driven-size.d.ts +27 -0
- package/dist/components/driven-size.js +85 -0
- package/dist/components/driven-size.js.map +1 -0
- package/dist/components/find-node-handle.d.ts +11 -0
- package/dist/components/find-node-handle.js +53 -0
- package/dist/components/find-node-handle.js.map +1 -0
- package/dist/components/flat-list.d.ts +3 -2
- package/dist/components/flat-list.js.map +1 -1
- package/dist/components/frame-scheduler.d.ts +16 -0
- package/dist/components/frame-scheduler.js +37 -0
- package/dist/components/frame-scheduler.js.map +1 -0
- package/dist/components/image.d.ts +6 -1
- package/dist/components/image.js +15 -4
- package/dist/components/image.js.map +1 -1
- package/dist/components/index.d.ts +7 -5
- package/dist/components/index.js +5 -3
- package/dist/components/index.js.map +1 -1
- package/dist/components/measure.d.ts +51 -1
- package/dist/components/measure.js +101 -2
- package/dist/components/measure.js.map +1 -1
- package/dist/components/pressable.d.ts +61 -1
- package/dist/components/pressable.js +151 -4
- package/dist/components/pressable.js.map +1 -1
- package/dist/components/rect-store.d.ts +58 -0
- package/dist/components/rect-store.js +124 -3
- package/dist/components/rect-store.js.map +1 -1
- package/dist/components/root.js +6 -1
- package/dist/components/root.js.map +1 -1
- package/dist/components/scroll-phase.d.ts +35 -0
- package/dist/components/scroll-phase.js +26 -0
- package/dist/components/scroll-phase.js.map +1 -0
- package/dist/components/scroll-view.d.ts +39 -3
- package/dist/components/scroll-view.js +378 -43
- package/dist/components/scroll-view.js.map +1 -1
- package/dist/components/text-input.js +9 -25
- package/dist/components/text-input.js.map +1 -1
- package/dist/components/text.d.ts +6 -2
- package/dist/components/text.js +43 -8
- package/dist/components/text.js.map +1 -1
- package/dist/components/use-focus.d.ts +27 -0
- package/dist/components/use-focus.js +116 -0
- package/dist/components/use-focus.js.map +1 -0
- package/dist/components/use-layout-child.d.ts +13 -1
- package/dist/components/use-layout-child.js +188 -5
- package/dist/components/use-layout-child.js.map +1 -1
- package/dist/components/view.d.ts +5 -2
- package/dist/components/view.js +18 -13
- package/dist/components/view.js.map +1 -1
- package/dist/components/virtualized-list.d.ts +45 -5
- package/dist/components/virtualized-list.js +90 -24
- package/dist/components/virtualized-list.js.map +1 -1
- package/dist/components/wheel-scroll-session.d.ts +7 -0
- package/dist/components/wheel-scroll-session.js +53 -0
- package/dist/components/wheel-scroll-session.js.map +1 -0
- package/dist/components/widget-retention.d.ts +35 -0
- package/dist/components/widget-retention.js +169 -0
- package/dist/components/widget-retention.js.map +1 -0
- package/dist/contracts.d.ts +4 -0
- package/dist/contracts.js.map +1 -1
- package/dist/dnd/context.d.ts +69 -0
- package/dist/dnd/context.js +149 -0
- package/dist/dnd/context.js.map +1 -0
- package/dist/dnd/draggable.d.ts +59 -0
- package/dist/dnd/draggable.js +149 -0
- package/dist/dnd/draggable.js.map +1 -0
- package/dist/dnd/droppable.d.ts +24 -0
- package/dist/dnd/droppable.js +74 -0
- package/dist/dnd/droppable.js.map +1 -0
- package/dist/dnd/gtk-controllers.d.ts +39 -0
- package/dist/dnd/gtk-controllers.js +110 -0
- package/dist/dnd/gtk-controllers.js.map +1 -0
- package/dist/dnd/index.d.ts +6 -0
- package/dist/dnd/index.js +31 -0
- package/dist/dnd/index.js.map +1 -0
- package/dist/dnd/order.d.ts +7 -0
- package/dist/dnd/order.js +20 -0
- package/dist/dnd/order.js.map +1 -0
- package/dist/dnd/payload.d.ts +14 -0
- package/dist/dnd/payload.js +41 -0
- package/dist/dnd/payload.js.map +1 -0
- package/dist/dnd/sortable.d.ts +49 -0
- package/dist/dnd/sortable.js +307 -0
- package/dist/dnd/sortable.js.map +1 -0
- package/dist/dnd/types.d.ts +290 -0
- package/dist/dnd/types.js +25 -0
- package/dist/dnd/types.js.map +1 -0
- package/dist/gesture-handler-compat/builder.d.ts +251 -0
- package/dist/gesture-handler-compat/builder.js +513 -0
- package/dist/gesture-handler-compat/builder.js.map +1 -0
- package/dist/gesture-handler-compat/composition.d.ts +23 -0
- package/dist/gesture-handler-compat/composition.js +111 -0
- package/dist/gesture-handler-compat/composition.js.map +1 -0
- package/dist/gesture-handler-compat/deciders.d.ts +3 -0
- package/dist/gesture-handler-compat/deciders.js +47 -0
- package/dist/gesture-handler-compat/deciders.js.map +1 -0
- package/dist/gesture-handler-compat/detector-runtime.d.ts +44 -0
- package/dist/gesture-handler-compat/detector-runtime.js +374 -0
- package/dist/gesture-handler-compat/detector-runtime.js.map +1 -0
- package/dist/gesture-handler-compat/detector.d.ts +22 -0
- package/dist/gesture-handler-compat/detector.js +104 -0
- package/dist/gesture-handler-compat/detector.js.map +1 -0
- package/dist/gesture-handler-compat/fling.d.ts +24 -0
- package/dist/gesture-handler-compat/fling.js +123 -0
- package/dist/gesture-handler-compat/fling.js.map +1 -0
- package/dist/gesture-handler-compat/force-touch.d.ts +13 -0
- package/dist/gesture-handler-compat/force-touch.js +40 -0
- package/dist/gesture-handler-compat/force-touch.js.map +1 -0
- package/dist/gesture-handler-compat/hooks.d.ts +157 -0
- package/dist/gesture-handler-compat/hooks.js +268 -0
- package/dist/gesture-handler-compat/hooks.js.map +1 -0
- package/dist/gesture-handler-compat/hover.d.ts +2 -0
- package/dist/gesture-handler-compat/hover.js +22 -0
- package/dist/gesture-handler-compat/hover.js.map +1 -0
- package/dist/gesture-handler-compat/index.d.ts +98 -0
- package/dist/gesture-handler-compat/index.js +255 -0
- package/dist/gesture-handler-compat/index.js.map +1 -0
- package/dist/gesture-handler-compat/long-press.d.ts +6 -0
- package/dist/gesture-handler-compat/long-press.js +21 -0
- package/dist/gesture-handler-compat/long-press.js.map +1 -0
- package/dist/gesture-handler-compat/manual.d.ts +2 -0
- package/dist/gesture-handler-compat/manual.js +18 -0
- package/dist/gesture-handler-compat/manual.js.map +1 -0
- package/dist/gesture-handler-compat/native.d.ts +7 -0
- package/dist/gesture-handler-compat/native.js +34 -0
- package/dist/gesture-handler-compat/native.js.map +1 -0
- package/dist/gesture-handler-compat/orchestrator.d.ts +77 -0
- package/dist/gesture-handler-compat/orchestrator.js +284 -0
- package/dist/gesture-handler-compat/orchestrator.js.map +1 -0
- package/dist/gesture-handler-compat/pan.d.ts +23 -0
- package/dist/gesture-handler-compat/pan.js +116 -0
- package/dist/gesture-handler-compat/pan.js.map +1 -0
- package/dist/gesture-handler-compat/recognizer.d.ts +268 -0
- package/dist/gesture-handler-compat/recognizer.js +1056 -0
- package/dist/gesture-handler-compat/recognizer.js.map +1 -0
- package/dist/gesture-handler-compat/relations.d.ts +43 -0
- package/dist/gesture-handler-compat/relations.js +128 -0
- package/dist/gesture-handler-compat/relations.js.map +1 -0
- package/dist/gesture-handler-compat/tap.d.ts +6 -0
- package/dist/gesture-handler-compat/tap.js +29 -0
- package/dist/gesture-handler-compat/tap.js.map +1 -0
- package/dist/gesture-handler-compat/touchpad.d.ts +41 -0
- package/dist/gesture-handler-compat/touchpad.js +64 -0
- package/dist/gesture-handler-compat/touchpad.js.map +1 -0
- package/dist/gesture-handler-compat/types.d.ts +441 -0
- package/dist/gesture-handler-compat/types.js +167 -0
- package/dist/gesture-handler-compat/types.js.map +1 -0
- package/dist/gtk/controllers.d.ts +39 -0
- package/dist/gtk/controllers.js +92 -0
- package/dist/gtk/controllers.js.map +1 -0
- package/dist/gtk/index.d.ts +2 -1
- package/dist/gtk/index.js +7 -1
- package/dist/gtk/index.js.map +1 -1
- package/dist/gtkx/bridge/geometry.js +6 -4
- package/dist/gtkx/bridge/geometry.js.map +1 -1
- package/dist/gtkx/bridge/index.d.ts +5 -3
- package/dist/gtkx/bridge/index.js +6 -3
- package/dist/gtkx/bridge/index.js.map +1 -1
- package/dist/gtkx/bridge/slot-portal.js.map +1 -1
- package/dist/gtkx/bridge/use-signal.js +1 -1
- package/dist/gtkx/bridge/use-signal.js.map +1 -1
- package/dist/gtkx/bridge/view-box.d.ts +56 -0
- package/dist/gtkx/bridge/view-box.js +394 -9
- package/dist/gtkx/bridge/view-box.js.map +1 -1
- package/dist/gtkx/bridge/widget-css.d.ts +17 -0
- package/dist/gtkx/bridge/widget-css.js +72 -0
- package/dist/gtkx/bridge/widget-css.js.map +1 -0
- package/dist/index.d.ts +3 -3
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/layout/driven-size.d.ts +12 -0
- package/dist/layout/driven-size.js +70 -0
- package/dist/layout/driven-size.js.map +1 -0
- package/dist/layout/engine.d.ts +17 -1
- package/dist/layout/engine.js +3 -20
- package/dist/layout/engine.js.map +1 -1
- package/dist/layout/node.d.ts +13 -0
- package/dist/layout/node.js +14 -0
- package/dist/layout/node.js.map +1 -1
- package/dist/layout/yoga.d.ts +3 -2
- package/dist/layout/yoga.js +5 -2
- package/dist/layout/yoga.js.map +1 -1
- package/dist/mcp/data/generated.d.ts +257 -60
- package/dist/mcp/data/generated.js +306 -62
- package/dist/mcp/data/generated.js.map +1 -1
- package/dist/metro/index.d.ts +10 -0
- package/dist/metro/index.js +21 -12
- package/dist/metro/index.js.map +1 -1
- package/dist/navigation/sidebar.d.ts +16 -0
- package/dist/navigation/sidebar.js +65 -1
- package/dist/navigation/sidebar.js.map +1 -1
- package/dist/reanimated-compat/animated-ref.d.ts +32 -0
- package/dist/reanimated-compat/animated-ref.js +57 -0
- package/dist/reanimated-compat/animated-ref.js.map +1 -0
- package/dist/reanimated-compat/animation.d.ts +177 -0
- package/dist/reanimated-compat/animation.js +540 -0
- package/dist/reanimated-compat/animation.js.map +1 -0
- package/dist/reanimated-compat/color.d.ts +28 -0
- package/dist/reanimated-compat/color.js +249 -0
- package/dist/reanimated-compat/color.js.map +1 -0
- package/dist/reanimated-compat/decay.d.ts +39 -0
- package/dist/reanimated-compat/decay.js +96 -0
- package/dist/reanimated-compat/decay.js.map +1 -0
- package/dist/reanimated-compat/easing.d.ts +30 -0
- package/dist/reanimated-compat/easing.js +76 -0
- package/dist/reanimated-compat/easing.js.map +1 -0
- package/dist/reanimated-compat/hooks.d.ts +14 -0
- package/dist/reanimated-compat/hooks.js +217 -0
- package/dist/reanimated-compat/hooks.js.map +1 -0
- package/dist/reanimated-compat/index.d.ts +258 -0
- package/dist/reanimated-compat/index.js +464 -0
- package/dist/reanimated-compat/index.js.map +1 -0
- package/dist/reanimated-compat/interpolation.d.ts +18 -0
- package/dist/reanimated-compat/interpolation.js +122 -0
- package/dist/reanimated-compat/interpolation.js.map +1 -0
- package/dist/reanimated-compat/layout-animation-config.d.ts +43 -0
- package/dist/reanimated-compat/layout-animation-config.js +78 -0
- package/dist/reanimated-compat/layout-animation-config.js.map +1 -0
- package/dist/reanimated-compat/layout-animation-presets.d.ts +117 -0
- package/dist/reanimated-compat/layout-animation-presets.js +498 -0
- package/dist/reanimated-compat/layout-animation-presets.js.map +1 -0
- package/dist/reanimated-compat/layout-animation-runtime.d.ts +21 -0
- package/dist/reanimated-compat/layout-animation-runtime.js +311 -0
- package/dist/reanimated-compat/layout-animation-runtime.js.map +1 -0
- package/dist/reanimated-compat/layout-animation-view.d.ts +27 -0
- package/dist/reanimated-compat/layout-animation-view.js +266 -0
- package/dist/reanimated-compat/layout-animation-view.js.map +1 -0
- package/dist/reanimated-compat/layout-animation.d.ts +171 -0
- package/dist/reanimated-compat/layout-animation.js +469 -0
- package/dist/reanimated-compat/layout-animation.js.map +1 -0
- package/dist/reanimated-compat/layout-transitions.d.ts +83 -0
- package/dist/reanimated-compat/layout-transitions.js +350 -0
- package/dist/reanimated-compat/layout-transitions.js.map +1 -0
- package/dist/reanimated-compat/mutable.d.ts +29 -0
- package/dist/reanimated-compat/mutable.js +139 -0
- package/dist/reanimated-compat/mutable.js.map +1 -0
- package/dist/reanimated-compat/props.d.ts +18 -0
- package/dist/reanimated-compat/props.js +111 -0
- package/dist/reanimated-compat/props.js.map +1 -0
- package/dist/reanimated-compat/scroll-handler.d.ts +119 -0
- package/dist/reanimated-compat/scroll-handler.js +274 -0
- package/dist/reanimated-compat/scroll-handler.js.map +1 -0
- package/dist/reanimated-compat/scroll-offset.d.ts +12 -0
- package/dist/reanimated-compat/scroll-offset.js +104 -0
- package/dist/reanimated-compat/scroll-offset.js.map +1 -0
- package/dist/reanimated-compat/style.d.ts +90 -0
- package/dist/reanimated-compat/style.js +452 -0
- package/dist/reanimated-compat/style.js.map +1 -0
- package/dist/reanimated-compat/test-timers.d.ts +28 -0
- package/dist/reanimated-compat/test-timers.js +136 -0
- package/dist/reanimated-compat/test-timers.js.map +1 -0
- package/dist/reanimated-compat/threads.d.ts +13 -0
- package/dist/reanimated-compat/threads.js +41 -0
- package/dist/reanimated-compat/threads.js.map +1 -0
- package/dist/reanimated-compat/tracking.d.ts +41 -0
- package/dist/reanimated-compat/tracking.js +106 -0
- package/dist/reanimated-compat/tracking.js.map +1 -0
- package/dist/reanimated-compat/updater-animations.d.ts +36 -0
- package/dist/reanimated-compat/updater-animations.js +273 -0
- package/dist/reanimated-compat/updater-animations.js.map +1 -0
- package/dist/responder/system.d.ts +80 -7
- package/dist/responder/system.js +143 -23
- package/dist/responder/system.js.map +1 -1
- package/dist/responder/use-responder.d.ts +11 -0
- package/dist/responder/use-responder.js +225 -6
- package/dist/responder/use-responder.js.map +1 -1
- package/dist/runner/host-dev.js +1 -1
- package/dist/runner/host-dev.js.map +1 -1
- package/dist/runner/host.js +1 -1
- package/dist/runner/host.js.map +1 -1
- package/dist/runner/index.js +3 -3
- package/dist/runner/index.js.map +1 -1
- package/dist/sea/gtkx-config-module.js +1 -1
- package/dist/sea/gtkx-config-module.js.map +1 -1
- package/dist/style/absolute-insets.d.ts +26 -0
- package/dist/style/absolute-insets.js +113 -0
- package/dist/style/absolute-insets.js.map +1 -0
- package/dist/style/animated-size.d.ts +25 -0
- package/dist/style/animated-size.js +225 -0
- package/dist/style/animated-size.js.map +1 -0
- package/dist/style/colors.d.ts +17 -0
- package/dist/style/colors.js +25 -6
- package/dist/style/colors.js.map +1 -1
- package/dist/style/imperative-css.d.ts +21 -0
- package/dist/style/imperative-css.js +63 -0
- package/dist/style/imperative-css.js.map +1 -0
- package/dist/style/index.d.ts +2 -1
- package/dist/style/index.js +2 -1
- package/dist/style/index.js.map +1 -1
- package/dist/style/split-style.js +5 -0
- package/dist/style/split-style.js.map +1 -1
- package/dist/testing/index.js.map +1 -1
- package/dist/unsupported-export.d.ts +8 -0
- package/dist/unsupported-export.js +66 -0
- package/dist/unsupported-export.js.map +1 -0
- package/dist/vite/index.d.ts +21 -8
- package/dist/vite/index.js +127 -82
- package/dist/vite/index.js.map +1 -1
- package/dist/vitest/index.d.ts +2 -2
- package/dist/vitest/index.js.map +1 -1
- package/dist/worklets-compat/index.d.ts +4 -0
- package/dist/worklets-compat/index.js +28 -0
- package/dist/worklets-compat/index.js.map +1 -0
- package/dist/worklets-compat/surface.d.ts +110 -0
- package/dist/worklets-compat/surface.js +153 -0
- package/dist/worklets-compat/surface.js.map +1 -0
- package/package.json +25 -9
- package/types.d.ts +9 -0
- package/dist/common/list.d.ts +0 -82
- package/dist/common/list.js +0 -166
- package/dist/common/list.js.map +0 -1
|
@@ -0,0 +1,273 @@
|
|
|
1
|
+
import { animationSignature, buildAnimation, isAnimationSpec, targetOf, } from "./animation";
|
|
2
|
+
// How far behind its own animation a property this platform will not drive at
|
|
3
|
+
// frame rate is allowed to fall.
|
|
4
|
+
//
|
|
5
|
+
// The settle alone is not an answer, and `@gorhom/bottom-sheet` MOUNTING is
|
|
6
|
+
// the measurement that says so. Its content mask is bounded by an animated
|
|
7
|
+
// `height` whose target is derived from the sheet's own POSITION, so every
|
|
8
|
+
// frame of the opening spring re-aims it — 37 re-aims over 673 ms, each
|
|
9
|
+
// cancelling the last, so not one of them a settle — and then a further
|
|
10
|
+
// 677 ms for the final spring to converge. Measured on the gallery's
|
|
11
|
+
// `upstream-bottom-sheet` screen: the seed was 95.9 px (gorhom's
|
|
12
|
+
// `animatedContentHeightMax` was still 0 on the mapper run that first
|
|
13
|
+
// produced a `height` at all, and the real 832 px arrived 27 ms later, by
|
|
14
|
+
// which time the key already had an entry and a moving target is an animation
|
|
15
|
+
// rather than a seed), and `height` reached Yoga exactly TWICE in the whole
|
|
16
|
+
// mount: 95.9 px at once, 954.6 px 1378 ms later. For 1.38 s the mask was a
|
|
17
|
+
// tenth of its size, the list inside it had no bounded parent, and it mounted
|
|
18
|
+
// zero of its 18 rows. Correct by the settle rule and plainly wrong to
|
|
19
|
+
// anybody opening the screen.
|
|
20
|
+
//
|
|
21
|
+
// So the value lands on a cadence as well. 100 ms because that is the bound
|
|
22
|
+
// under which a change still reads as immediate, and because it bounds the
|
|
23
|
+
// cost by the CLOCK rather than by the animation: at most ten renders a
|
|
24
|
+
// second per animated key, against sixty frames. The same mount now lands the
|
|
25
|
+
// mask at 266 → 546 → 649 → 731 → 792 → 832 → 896 → 939 → 951 → 954 px before
|
|
26
|
+
// settling at 954.6 — the shape the animation has, at a tenth of its rate —
|
|
27
|
+
// with the first at ~100 ms rather than 1.38 s.
|
|
28
|
+
//
|
|
29
|
+
// What it costs, both halves measured in one `spike/core-exports` run on the
|
|
30
|
+
// same machine: 4 settles and 4 renders against 290 refused-property frames
|
|
31
|
+
// before, 4 settles + 38 landings and 42 renders against 294 after. Still an
|
|
32
|
+
// order of magnitude under the per-frame layout write the refusal exists to
|
|
33
|
+
// avoid, and no longer a promise that may never come due.
|
|
34
|
+
// docs/research/animated-size.md §10.
|
|
35
|
+
const LANDING_INTERVAL_MS = 100;
|
|
36
|
+
// A landing that cannot move a widget is a render for nothing: GTK allocates
|
|
37
|
+
// whole pixels, so a sub-pixel step changes no committed geometry. It is what
|
|
38
|
+
// keeps a long animation over a short distance from spending ten renders a
|
|
39
|
+
// second to travel one pixel — gorhom's `paddingBottom` crosses 26 px over the
|
|
40
|
+
// same 1.38 s and lands 8 times, not 13.
|
|
41
|
+
const LANDING_EPSILON = 1;
|
|
42
|
+
/**
|
|
43
|
+
* @param publish Receives the updater's object with every animated key
|
|
44
|
+
* replaced by a number. Called once per mapper run and once per animation
|
|
45
|
+
* frame.
|
|
46
|
+
* @param onSettled Called when an animation on `key` reaches its target on its
|
|
47
|
+
* own (never when it is cancelled or replaced). The style layer uses it for
|
|
48
|
+
* the properties it refuses to drive at frame rate, whose contract is that
|
|
49
|
+
* the value lands on the next React render — without it, that promise is
|
|
50
|
+
* only kept when something else happens to re-render.
|
|
51
|
+
* @param onLanding Called when `key`'s current value has to reach React
|
|
52
|
+
* without its animation having reached a target. Two occasions: while an
|
|
53
|
+
* animation runs, at most once per `LANDING_INTERVAL_MS` and only when the
|
|
54
|
+
* value has moved far enough to change a committed layout (the cadence); and
|
|
55
|
+
* when a plain number REPLACES a running animation, where upstream cancels
|
|
56
|
+
* and snaps and a refused property cannot snap without a render. The snap is
|
|
57
|
+
* deliberately not rate-limited — it is a state change rather than a step of
|
|
58
|
+
* one, it happens once per mapper run that flips the key rather than once per
|
|
59
|
+
* frame, and upstream pushes exactly the same number of `updateProps` for it.
|
|
60
|
+
* Same job as `onSettled` and the same handling at the call site; it is a
|
|
61
|
+
* separate callback because a settle and a value that has merely got to be
|
|
62
|
+
* published are different claims, and only the first one is a promise kept.
|
|
63
|
+
* Omit it and both cost nothing at all — a caller with no refused properties
|
|
64
|
+
* (`useAnimatedProps`) does.
|
|
65
|
+
*/
|
|
66
|
+
export const createUpdaterAnimations = (engine, publish, onSettled, onLanding) => {
|
|
67
|
+
const entries = new Map();
|
|
68
|
+
// The clock the animations themselves run on, never `Date` — the whole
|
|
69
|
+
// layer is driven by one injected scheduler so a test can take it
|
|
70
|
+
// (components/frame-scheduler.ts). A driver that only has frame stamps and
|
|
71
|
+
// no off-frame `now` cannot have a cadence, and falls back to the settle.
|
|
72
|
+
const hasClock = engine.scheduler.now !== undefined;
|
|
73
|
+
const now = () => engine.scheduler.now?.() ?? 0;
|
|
74
|
+
let lastSource = null;
|
|
75
|
+
// A frame of one key's animation republishes the WHOLE object, which
|
|
76
|
+
// re-enters `resolve`. The guard keeps that from restarting anything: the
|
|
77
|
+
// run in progress publishes the final state itself.
|
|
78
|
+
let resolving = false;
|
|
79
|
+
/**
|
|
80
|
+
* @param replacement The plain value that took the key over, or `undefined`
|
|
81
|
+
* when the key left the updater's result altogether.
|
|
82
|
+
*
|
|
83
|
+
* A number here owes the caller a render, and `landedValue` is what decides
|
|
84
|
+
* it: that field is this module's whole model of what REACT holds for the
|
|
85
|
+
* key, and everything since the last landing or settle went to the widget
|
|
86
|
+
* without passing through React. So a plain number that differs from it has
|
|
87
|
+
* to be published or it never arrives — on a refused property the snap IS
|
|
88
|
+
* a render, and neither the cadence nor a settle is ever going to come for
|
|
89
|
+
* it. Compared without the cadence's one-pixel epsilon and for the same
|
|
90
|
+
* reason a settle ignores it: this is a resting value rather than a step
|
|
91
|
+
* towards one, and there is nothing after it to correct a skipped render.
|
|
92
|
+
*
|
|
93
|
+
* Not asked for otherwise. A key that VANISHED, or one replaced by a
|
|
94
|
+
* percentage or a colour, changes the style's SHAPE, and the caller already
|
|
95
|
+
* pays exactly one render for that (hooks.ts); a value equal to the one
|
|
96
|
+
* React already has is a render for nothing.
|
|
97
|
+
*/
|
|
98
|
+
const drop = (key, replacement) => {
|
|
99
|
+
const entry = entries.get(key);
|
|
100
|
+
if (entry === undefined) {
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
entries.delete(key);
|
|
104
|
+
entry.running?.stop();
|
|
105
|
+
entry.driver.removeListener(entry.listenerId);
|
|
106
|
+
if (typeof replacement === "number" &&
|
|
107
|
+
!Object.is(replacement, entry.landedValue)) {
|
|
108
|
+
onLanding?.(key);
|
|
109
|
+
}
|
|
110
|
+
};
|
|
111
|
+
const republish = () => {
|
|
112
|
+
if (resolving || lastSource === null) {
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
// No previous result on a frame: nothing can START an animation here — the
|
|
116
|
+
// source has not changed — so there is nothing to look a starting point up
|
|
117
|
+
// for.
|
|
118
|
+
publish(resolve(lastSource, null));
|
|
119
|
+
};
|
|
120
|
+
/**
|
|
121
|
+
* Records that `key`'s current value is the one React now holds. Called
|
|
122
|
+
* wherever a render is asked for, so the cadence is measured from the last
|
|
123
|
+
* value React was actually given rather than from the last frame.
|
|
124
|
+
*/
|
|
125
|
+
const markLanded = (entry) => {
|
|
126
|
+
entry.landedValue = entry.driver.__getValue();
|
|
127
|
+
entry.landedAt = now();
|
|
128
|
+
};
|
|
129
|
+
/** The cadence: see LANDING_INTERVAL_MS. */
|
|
130
|
+
const considerLanding = (key, value) => {
|
|
131
|
+
if (onLanding === undefined || !hasClock) {
|
|
132
|
+
return;
|
|
133
|
+
}
|
|
134
|
+
const entry = entries.get(key);
|
|
135
|
+
if (entry === undefined) {
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
138
|
+
if (now() - entry.landedAt < LANDING_INTERVAL_MS) {
|
|
139
|
+
return;
|
|
140
|
+
}
|
|
141
|
+
if (Math.abs(value - entry.landedValue) < LANDING_EPSILON) {
|
|
142
|
+
return;
|
|
143
|
+
}
|
|
144
|
+
markLanded(entry);
|
|
145
|
+
onLanding(key);
|
|
146
|
+
};
|
|
147
|
+
/** Aims `entry`'s driver at `spec`, replacing whatever it was running. */
|
|
148
|
+
const start = (key, entry, spec, signature) => {
|
|
149
|
+
entry.signature = signature;
|
|
150
|
+
entry.running?.stop();
|
|
151
|
+
const animation = buildAnimation(engine, entry.driver, spec);
|
|
152
|
+
entry.running = animation;
|
|
153
|
+
animation.start((result) => {
|
|
154
|
+
if (entry.running === animation) {
|
|
155
|
+
entry.running = null;
|
|
156
|
+
}
|
|
157
|
+
// `finished` only: a restart stops the previous animation, and reporting
|
|
158
|
+
// that as a settle would publish through React on every frame the target
|
|
159
|
+
// moves, which is the cost the refusal exists to avoid. A restart is
|
|
160
|
+
// still covered — the cadence above is what carries a target that keeps
|
|
161
|
+
// moving, and it does not care whose animation the frames belong to.
|
|
162
|
+
if (result.finished) {
|
|
163
|
+
markLanded(entry);
|
|
164
|
+
onSettled?.(key);
|
|
165
|
+
}
|
|
166
|
+
});
|
|
167
|
+
return entry;
|
|
168
|
+
};
|
|
169
|
+
/**
|
|
170
|
+
* Where an animation that is starting has to start FROM, for a key that was
|
|
171
|
+
* not animating a moment ago: the value the PREVIOUS updater result held for
|
|
172
|
+
* it, and only when that is a real number.
|
|
173
|
+
*
|
|
174
|
+
* This is `prepareAnimation(…, oldValues[key])` and nothing more —
|
|
175
|
+
* `oldValues` is `state.last`, upstream's copy of the whole previous updater
|
|
176
|
+
* result — so the second of the header's three rules costs no bookkeeping at
|
|
177
|
+
* all. The previous result is an object this module was already holding for
|
|
178
|
+
* `republish`; reading one key out of it is the entire mechanism, and the
|
|
179
|
+
* entry does not have to carry a value across runs or outlive its animation.
|
|
180
|
+
*
|
|
181
|
+
* Numbers only, and `undefined` for everything else, which lines up with
|
|
182
|
+
* upstream at both ends: a key that was absent has no starting point (its
|
|
183
|
+
* `oldValues[key]` is `undefined`, and the animation's own `current` — the
|
|
184
|
+
* target — stands), and a percentage string or a colour is not something the
|
|
185
|
+
* numeric drivers here can start at.
|
|
186
|
+
*/
|
|
187
|
+
const startingPoint = (previous, key) => {
|
|
188
|
+
const value = previous?.[key];
|
|
189
|
+
return typeof value === "number" && Number.isFinite(value)
|
|
190
|
+
? value
|
|
191
|
+
: undefined;
|
|
192
|
+
};
|
|
193
|
+
const ensure = (key, spec, previous) => {
|
|
194
|
+
const signature = animationSignature(spec);
|
|
195
|
+
const existing = entries.get(key);
|
|
196
|
+
if (existing !== undefined) {
|
|
197
|
+
return existing.signature === signature
|
|
198
|
+
? existing
|
|
199
|
+
: start(key, existing, spec, signature);
|
|
200
|
+
}
|
|
201
|
+
const from = startingPoint(previous, key);
|
|
202
|
+
// The driver is seeded before anything is built on purpose: a spring reads
|
|
203
|
+
// its origin off the value it is given (animation.ts), so this IS where
|
|
204
|
+
// "animate from the old number" happens.
|
|
205
|
+
const driver = new engine.api.Value(from ?? targetOf(spec) ?? 0);
|
|
206
|
+
const entry = {
|
|
207
|
+
driver,
|
|
208
|
+
listenerId: driver.addListener(({ value }) => {
|
|
209
|
+
republish();
|
|
210
|
+
considerLanding(key, value);
|
|
211
|
+
}),
|
|
212
|
+
signature,
|
|
213
|
+
running: null,
|
|
214
|
+
// Whichever branch follows, React's copy of this key is the value the
|
|
215
|
+
// driver starts at: a seed changes the style's SHAPE and the caller
|
|
216
|
+
// already pays one render for that (hooks.ts), and a starting point that
|
|
217
|
+
// came out of the previous result is a number React was already handed.
|
|
218
|
+
// So the cadence starts here either way.
|
|
219
|
+
landedValue: driver.__getValue(),
|
|
220
|
+
landedAt: now(),
|
|
221
|
+
};
|
|
222
|
+
entries.set(key, entry);
|
|
223
|
+
// Nothing to animate from: seeded at the target and not started at all,
|
|
224
|
+
// which is the first of the header's three rules.
|
|
225
|
+
return from === undefined ? entry : start(key, entry, spec, signature);
|
|
226
|
+
};
|
|
227
|
+
const resolve = (source, previous) => {
|
|
228
|
+
resolving = true;
|
|
229
|
+
try {
|
|
230
|
+
let resolved = null;
|
|
231
|
+
for (const key of Object.keys(source)) {
|
|
232
|
+
const value = source[key];
|
|
233
|
+
if (!isAnimationSpec(value)) {
|
|
234
|
+
// A plain value replacing an animation cancels it and snaps, exactly
|
|
235
|
+
// as an assignment to a shared value does and exactly as upstream's
|
|
236
|
+
// `delete animations[key]` + `updateProps` in the same run does. The
|
|
237
|
+
// number itself is published below, by identity.
|
|
238
|
+
drop(key, value);
|
|
239
|
+
continue;
|
|
240
|
+
}
|
|
241
|
+
resolved ??= { ...source };
|
|
242
|
+
resolved[key] = ensure(key, value, previous).driver.__getValue();
|
|
243
|
+
}
|
|
244
|
+
for (const key of [...entries.keys()]) {
|
|
245
|
+
if (!(key in source)) {
|
|
246
|
+
drop(key, undefined);
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
return resolved ?? source;
|
|
250
|
+
}
|
|
251
|
+
finally {
|
|
252
|
+
resolving = false;
|
|
253
|
+
}
|
|
254
|
+
};
|
|
255
|
+
return {
|
|
256
|
+
run(source) {
|
|
257
|
+
// `state.last`, upstream's name for it: the result this run's animations
|
|
258
|
+
// measure themselves against. Held for one run only, and it was already
|
|
259
|
+
// being held.
|
|
260
|
+
const previous = lastSource;
|
|
261
|
+
lastSource = source;
|
|
262
|
+
publish(resolve(source, previous));
|
|
263
|
+
},
|
|
264
|
+
dispose() {
|
|
265
|
+
for (const key of [...entries.keys()]) {
|
|
266
|
+
// Nothing is owed a render: the component is going away.
|
|
267
|
+
drop(key, undefined);
|
|
268
|
+
}
|
|
269
|
+
lastSource = null;
|
|
270
|
+
},
|
|
271
|
+
};
|
|
272
|
+
};
|
|
273
|
+
//# sourceMappingURL=updater-animations.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"updater-animations.js","sourceRoot":"","sources":["../../src/reanimated-compat/updater-animations.ts"],"names":[],"mappings":"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","sourcesContent":["// An animation returned FROM a style or props updater, which is the shape the\n// documentation of `useAnimatedStyle` is written in:\n//\n// const style = useAnimatedStyle(() => ({\n// height: withSpring(open.value ? 320 : 0),\n// }))\n//\n// Assigning an animation to a shared value has always worked here\n// (mutable.ts). Returning one from an updater did not, and it failed the way\n// this repo likes least: silently. `with*` builders return a MARKED DESCRIPTOR\n// outside the initial run (animation.ts), the style layer's leaf test is\n// `typeof value === \"number\"`, and a descriptor is an object — so the property\n// was neither driven nor written nor warned about. It simply sat in the style\n// as `{kind: \"spring\", toValue: 543.4, …}`.\n//\n// Found by `spike/core-exports`, not by reading: `@gorhom/bottom-sheet` bounds\n// its scrollable with `height: animate({point: …})` from `useAnimatedStyle`,\n// and the probe's report that the height \"is not reaching the Yoga node\" was\n// true for a reason one layer earlier than layout — the height was never a\n// number on this platform at all. docs/research/animated-size.md §9.\n//\n// WHAT THIS MODULE IS. One running animation per key, on the platform's own\n// `Animated.Value` and the platform's one frame scheduler — the same\n// `buildAnimation` a shared value uses, so `withTiming`, `withSpring`,\n// `withDelay`, `withSequence`, `withRepeat`, `withDecay` and `withClamp` all\n// arrive here already implemented. The updater's object is republished with\n// each animated key replaced by the number its animation is currently at, and\n// a frame of a running animation costs no React render — it goes down exactly\n// the path a shared value written every frame goes down.\n//\n// THREE RULES, and all three are upstream's — every one of them read out of\n// `hook/useAnimatedStyle.ts`'s `styleUpdater`/`prepareAnimation` rather than\n// inferred from behaviour:\n//\n// - A key APPEARING for the first time is seeded at the animation's target\n// rather than animated to it. There is nothing to animate from, and it is\n// the same collapse `initialUpdaterRun` performs on the updater's first\n// run. Upstream reaches the same place from the other direction: its\n// `prepareAnimation` starts at `oldValues[key]`, which for a key that was\n// not in the last result is `undefined` and leaves the animation's own\n// `current` — its target — standing.\n// - A key whose previous result held a PLAIN NUMBER animates from that\n// number. `oldValues` is `state.last`, the whole previous updater result\n// kept raw, and `prepareAnimation`'s last branch is one line with the\n// comment already on it: `// previously it was a plain value, just set it\n// as starting point`. So `height: open.value ? withTiming(200) : 100` runs\n// 100 → 200, and the idiom people actually write — snap shut, open\n// smoothly — animates. It did not here: the key was dropped when it held a\n// number and re-seeded when it next held an animation, so the seed went\n// straight to 200 and the animation never played at all. Silently, which\n// is the failure this repo ranks worst.\n// - A re-run that produces an EQUIVALENT animation does not restart it. A\n// mapper re-runs whenever anything it read changed, which for a real app is\n// many times a second, and rebuilding the spring each time would leave it\n// crawling. Equivalence is the descriptor's target and shape\n// (`animationSignature`), not object identity — every run builds a fresh\n// object.\n//\n// AND THE REVERSE DIRECTION, animation → plain number, which is upstream's\n// too and is not the mirror image of the second rule: `styleUpdater`'s\n// non-animated branch does `delete animations[key]` and pushes the value\n// through `updateProps` in the SAME run, so the animation is cancelled — no\n// callback, no settle — and the number lands at once. It does not ease back.\n// The only thing this platform has to add is the render a refused property\n// needs to land at all, because \"at once\" through React is still a render (see\n// `onLanding`).\n//\n// WHERE THIS DIFFERS FROM UPSTREAM, said out loud: a restart picks the\n// animation up at the value it is currently at, with the velocity the new\n// descriptor asks for, where upstream also carries the previous animation's\n// VELOCITY across. For a target that moves once that is the same animation;\n// for a target that moves every frame ours is slightly more damped.\n//\n// AND THE CADENCE, the one rule here that is ours rather than upstream's — see\n// LANDING_INTERVAL_MS. It exists because none of the above is enough for a\n// property whose frames this platform refuses to write: for those, the value\n// only exists on screen at whatever the last React render committed, and \"the\n// render at the settle\" turned out to be arbitrarily far away.\nimport type { AnimatedValue, CompositeAnimation } from \"../animated/index\"\nimport {\n animationSignature,\n buildAnimation,\n isAnimationSpec,\n targetOf,\n type AnimationEngine,\n type AnimationSpec,\n} from \"./animation\"\n\n/** What an updater returns: a style object, or a props object. */\nexport type UpdaterObject = Record<string, unknown>\n\n// How far behind its own animation a property this platform will not drive at\n// frame rate is allowed to fall.\n//\n// The settle alone is not an answer, and `@gorhom/bottom-sheet` MOUNTING is\n// the measurement that says so. Its content mask is bounded by an animated\n// `height` whose target is derived from the sheet's own POSITION, so every\n// frame of the opening spring re-aims it — 37 re-aims over 673 ms, each\n// cancelling the last, so not one of them a settle — and then a further\n// 677 ms for the final spring to converge. Measured on the gallery's\n// `upstream-bottom-sheet` screen: the seed was 95.9 px (gorhom's\n// `animatedContentHeightMax` was still 0 on the mapper run that first\n// produced a `height` at all, and the real 832 px arrived 27 ms later, by\n// which time the key already had an entry and a moving target is an animation\n// rather than a seed), and `height` reached Yoga exactly TWICE in the whole\n// mount: 95.9 px at once, 954.6 px 1378 ms later. For 1.38 s the mask was a\n// tenth of its size, the list inside it had no bounded parent, and it mounted\n// zero of its 18 rows. Correct by the settle rule and plainly wrong to\n// anybody opening the screen.\n//\n// So the value lands on a cadence as well. 100 ms because that is the bound\n// under which a change still reads as immediate, and because it bounds the\n// cost by the CLOCK rather than by the animation: at most ten renders a\n// second per animated key, against sixty frames. The same mount now lands the\n// mask at 266 → 546 → 649 → 731 → 792 → 832 → 896 → 939 → 951 → 954 px before\n// settling at 954.6 — the shape the animation has, at a tenth of its rate —\n// with the first at ~100 ms rather than 1.38 s.\n//\n// What it costs, both halves measured in one `spike/core-exports` run on the\n// same machine: 4 settles and 4 renders against 290 refused-property frames\n// before, 4 settles + 38 landings and 42 renders against 294 after. Still an\n// order of magnitude under the per-frame layout write the refusal exists to\n// avoid, and no longer a promise that may never come due.\n// docs/research/animated-size.md §10.\nconst LANDING_INTERVAL_MS = 100\n\n// A landing that cannot move a widget is a render for nothing: GTK allocates\n// whole pixels, so a sub-pixel step changes no committed geometry. It is what\n// keeps a long animation over a short distance from spending ten renders a\n// second to travel one pixel — gorhom's `paddingBottom` crosses 26 px over the\n// same 1.38 s and lands 8 times, not 13.\nconst LANDING_EPSILON = 1\n\ntype Entry = {\n driver: AnimatedValue\n listenerId: string\n signature: string\n running: CompositeAnimation | null\n // The value React was last given for this key, and the moment it was given\n // — the two the cadence is measured against. They survive a restart on\n // purpose: what matters is how stale REACT's copy is, not how far the\n // animation currently in flight has come.\n landedValue: number\n landedAt: number\n}\n\nexport type UpdaterAnimations = {\n /**\n * Resolves `source`'s animations and publishes the result. Called from the\n * mapper, so `source` is a fresh object every time.\n */\n run(source: UpdaterObject): void\n dispose(): void\n}\n\n/**\n * @param publish Receives the updater's object with every animated key\n * replaced by a number. Called once per mapper run and once per animation\n * frame.\n * @param onSettled Called when an animation on `key` reaches its target on its\n * own (never when it is cancelled or replaced). The style layer uses it for\n * the properties it refuses to drive at frame rate, whose contract is that\n * the value lands on the next React render — without it, that promise is\n * only kept when something else happens to re-render.\n * @param onLanding Called when `key`'s current value has to reach React\n * without its animation having reached a target. Two occasions: while an\n * animation runs, at most once per `LANDING_INTERVAL_MS` and only when the\n * value has moved far enough to change a committed layout (the cadence); and\n * when a plain number REPLACES a running animation, where upstream cancels\n * and snaps and a refused property cannot snap without a render. The snap is\n * deliberately not rate-limited — it is a state change rather than a step of\n * one, it happens once per mapper run that flips the key rather than once per\n * frame, and upstream pushes exactly the same number of `updateProps` for it.\n * Same job as `onSettled` and the same handling at the call site; it is a\n * separate callback because a settle and a value that has merely got to be\n * published are different claims, and only the first one is a promise kept.\n * Omit it and both cost nothing at all — a caller with no refused properties\n * (`useAnimatedProps`) does.\n */\nexport const createUpdaterAnimations = (\n engine: AnimationEngine,\n publish: (resolved: UpdaterObject) => void,\n onSettled?: (key: string) => void,\n onLanding?: (key: string) => void,\n): UpdaterAnimations => {\n const entries = new Map<string, Entry>()\n // The clock the animations themselves run on, never `Date` — the whole\n // layer is driven by one injected scheduler so a test can take it\n // (components/frame-scheduler.ts). A driver that only has frame stamps and\n // no off-frame `now` cannot have a cadence, and falls back to the settle.\n const hasClock = engine.scheduler.now !== undefined\n const now = (): number => engine.scheduler.now?.() ?? 0\n let lastSource: UpdaterObject | null = null\n // A frame of one key's animation republishes the WHOLE object, which\n // re-enters `resolve`. The guard keeps that from restarting anything: the\n // run in progress publishes the final state itself.\n let resolving = false\n\n /**\n * @param replacement The plain value that took the key over, or `undefined`\n * when the key left the updater's result altogether.\n *\n * A number here owes the caller a render, and `landedValue` is what decides\n * it: that field is this module's whole model of what REACT holds for the\n * key, and everything since the last landing or settle went to the widget\n * without passing through React. So a plain number that differs from it has\n * to be published or it never arrives — on a refused property the snap IS\n * a render, and neither the cadence nor a settle is ever going to come for\n * it. Compared without the cadence's one-pixel epsilon and for the same\n * reason a settle ignores it: this is a resting value rather than a step\n * towards one, and there is nothing after it to correct a skipped render.\n *\n * Not asked for otherwise. A key that VANISHED, or one replaced by a\n * percentage or a colour, changes the style's SHAPE, and the caller already\n * pays exactly one render for that (hooks.ts); a value equal to the one\n * React already has is a render for nothing.\n */\n const drop = (key: string, replacement: unknown): void => {\n const entry = entries.get(key)\n if (entry === undefined) {\n return\n }\n entries.delete(key)\n entry.running?.stop()\n entry.driver.removeListener(entry.listenerId)\n if (\n typeof replacement === \"number\" &&\n !Object.is(replacement, entry.landedValue)\n ) {\n onLanding?.(key)\n }\n }\n\n const republish = (): void => {\n if (resolving || lastSource === null) {\n return\n }\n // No previous result on a frame: nothing can START an animation here — the\n // source has not changed — so there is nothing to look a starting point up\n // for.\n publish(resolve(lastSource, null))\n }\n\n /**\n * Records that `key`'s current value is the one React now holds. Called\n * wherever a render is asked for, so the cadence is measured from the last\n * value React was actually given rather than from the last frame.\n */\n const markLanded = (entry: Entry): void => {\n entry.landedValue = entry.driver.__getValue()\n entry.landedAt = now()\n }\n\n /** The cadence: see LANDING_INTERVAL_MS. */\n const considerLanding = (key: string, value: number): void => {\n if (onLanding === undefined || !hasClock) {\n return\n }\n const entry = entries.get(key)\n if (entry === undefined) {\n return\n }\n if (now() - entry.landedAt < LANDING_INTERVAL_MS) {\n return\n }\n if (Math.abs(value - entry.landedValue) < LANDING_EPSILON) {\n return\n }\n markLanded(entry)\n onLanding(key)\n }\n\n /** Aims `entry`'s driver at `spec`, replacing whatever it was running. */\n const start = (\n key: string,\n entry: Entry,\n spec: AnimationSpec,\n signature: string,\n ): Entry => {\n entry.signature = signature\n entry.running?.stop()\n const animation = buildAnimation(engine, entry.driver, spec)\n entry.running = animation\n animation.start((result) => {\n if (entry.running === animation) {\n entry.running = null\n }\n // `finished` only: a restart stops the previous animation, and reporting\n // that as a settle would publish through React on every frame the target\n // moves, which is the cost the refusal exists to avoid. A restart is\n // still covered — the cadence above is what carries a target that keeps\n // moving, and it does not care whose animation the frames belong to.\n if (result.finished) {\n markLanded(entry)\n onSettled?.(key)\n }\n })\n return entry\n }\n\n /**\n * Where an animation that is starting has to start FROM, for a key that was\n * not animating a moment ago: the value the PREVIOUS updater result held for\n * it, and only when that is a real number.\n *\n * This is `prepareAnimation(…, oldValues[key])` and nothing more —\n * `oldValues` is `state.last`, upstream's copy of the whole previous updater\n * result — so the second of the header's three rules costs no bookkeeping at\n * all. The previous result is an object this module was already holding for\n * `republish`; reading one key out of it is the entire mechanism, and the\n * entry does not have to carry a value across runs or outlive its animation.\n *\n * Numbers only, and `undefined` for everything else, which lines up with\n * upstream at both ends: a key that was absent has no starting point (its\n * `oldValues[key]` is `undefined`, and the animation's own `current` — the\n * target — stands), and a percentage string or a colour is not something the\n * numeric drivers here can start at.\n */\n const startingPoint = (\n previous: UpdaterObject | null,\n key: string,\n ): number | undefined => {\n const value = previous?.[key]\n return typeof value === \"number\" && Number.isFinite(value)\n ? value\n : undefined\n }\n\n const ensure = (\n key: string,\n spec: AnimationSpec,\n previous: UpdaterObject | null,\n ): Entry => {\n const signature = animationSignature(spec)\n const existing = entries.get(key)\n if (existing !== undefined) {\n return existing.signature === signature\n ? existing\n : start(key, existing, spec, signature)\n }\n const from = startingPoint(previous, key)\n // The driver is seeded before anything is built on purpose: a spring reads\n // its origin off the value it is given (animation.ts), so this IS where\n // \"animate from the old number\" happens.\n const driver = new engine.api.Value(from ?? targetOf(spec) ?? 0)\n const entry: Entry = {\n driver,\n listenerId: driver.addListener(({ value }) => {\n republish()\n considerLanding(key, value)\n }),\n signature,\n running: null,\n // Whichever branch follows, React's copy of this key is the value the\n // driver starts at: a seed changes the style's SHAPE and the caller\n // already pays one render for that (hooks.ts), and a starting point that\n // came out of the previous result is a number React was already handed.\n // So the cadence starts here either way.\n landedValue: driver.__getValue(),\n landedAt: now(),\n }\n entries.set(key, entry)\n // Nothing to animate from: seeded at the target and not started at all,\n // which is the first of the header's three rules.\n return from === undefined ? entry : start(key, entry, spec, signature)\n }\n\n const resolve = (\n source: UpdaterObject,\n previous: UpdaterObject | null,\n ): UpdaterObject => {\n resolving = true\n try {\n let resolved: UpdaterObject | null = null\n for (const key of Object.keys(source)) {\n const value = source[key]\n if (!isAnimationSpec(value)) {\n // A plain value replacing an animation cancels it and snaps, exactly\n // as an assignment to a shared value does and exactly as upstream's\n // `delete animations[key]` + `updateProps` in the same run does. The\n // number itself is published below, by identity.\n drop(key, value)\n continue\n }\n resolved ??= { ...source }\n resolved[key] = ensure(key, value, previous).driver.__getValue()\n }\n for (const key of [...entries.keys()]) {\n if (!(key in source)) {\n drop(key, undefined)\n }\n }\n return resolved ?? source\n } finally {\n resolving = false\n }\n }\n\n return {\n run(source) {\n // `state.last`, upstream's name for it: the result this run's animations\n // measure themselves against. Held for one run only, and it was already\n // being held.\n const previous = lastSource\n lastSource = source\n publish(resolve(source, previous))\n },\n dispose() {\n for (const key of [...entries.keys()]) {\n // Nothing is owed a render: the component is going away.\n drop(key, undefined)\n }\n lastSource = null\n },\n }\n}\n"]}
|
|
@@ -2,18 +2,49 @@ import type { NativeTouch } from "../components/press-event";
|
|
|
2
2
|
import type { ResponderProps } from "./types";
|
|
3
3
|
/** An opaque platform handle. A Gtk.Widget in practice; never treated as one. */
|
|
4
4
|
export type ResponderHost = object;
|
|
5
|
+
/**
|
|
6
|
+
* Why the responder was taken away by something that is not a pointer event.
|
|
7
|
+
*
|
|
8
|
+
* react-native-web's list is longer — cancel-ish events, context menu,
|
|
9
|
+
* window blur, ancestor scroll, selection change — and measuring GTK
|
|
10
|
+
* collapsed most of it. GTK cancels a single-button gesture the instant a
|
|
11
|
+
* second button goes down, and a widget that steals a sequence (a
|
|
12
|
+
* selectable label, a `GtkDragSource` attached through `Controllers`)
|
|
13
|
+
* cancels it too, so "context menu" and "selection change" both arrive as
|
|
14
|
+
* an ordinary `::cancel` on the event source and need no trigger of their
|
|
15
|
+
* own. What is left needs asking for:
|
|
16
|
+
*
|
|
17
|
+
* - `"blur"`: the toplevel stopped being the active window. Not a question,
|
|
18
|
+
* in RN or here — the window is gone either way.
|
|
19
|
+
* - `"scroll"`: an ancestor scroller moved under the gesture. The one
|
|
20
|
+
* termination a holder may refuse, and therefore the only place
|
|
21
|
+
* `onResponderTerminationRequest` is consulted outside a transfer (PRD
|
|
22
|
+
* crux 2: GTK's `CLAIMED` is irrevocable, so anything GTK has already
|
|
23
|
+
* taken cannot be given back no matter what the holder answers).
|
|
24
|
+
*/
|
|
25
|
+
export type TerminationReason = "blur" | "scroll";
|
|
5
26
|
export type ResponderSystemOptions = {
|
|
6
27
|
/** The platform's parent link. Returning null ends the path. */
|
|
7
28
|
parentOf: (host: ResponderHost) => ResponderHost | null;
|
|
8
29
|
/**
|
|
9
|
-
* Fired
|
|
10
|
-
* its GTK `CLAIMED` declaration.
|
|
11
|
-
*
|
|
12
|
-
*
|
|
30
|
+
* Fired at most ONCE per interaction, the first time any node is granted
|
|
31
|
+
* the responder — where the platform makes its GTK `CLAIMED` declaration.
|
|
32
|
+
*
|
|
33
|
+
* Its argument is the node whose event source is carrying the interaction,
|
|
34
|
+
* NOT the node that won the responder. Those differ whenever an ancestor
|
|
35
|
+
* claims (the common `onMoveShouldSetPanResponder` shape), and claiming on
|
|
36
|
+
* the ancestor is actively wrong: GTK denies the sequence on every gesture
|
|
37
|
+
* below the one that claims, which kills the very source the interaction
|
|
38
|
+
* is arriving through. What GTK is being told is "this interaction belongs
|
|
39
|
+
* to React Native, native widgets keep off" — a statement about the
|
|
40
|
+
* island, not about which view inside it currently holds the lock, which
|
|
41
|
+
* is a JS matter GTK has no way to represent.
|
|
42
|
+
*
|
|
43
|
+
* One-way by construction: GTK has no way to hand a claimed sequence back,
|
|
44
|
+
* so this only ever runs once JS has already decided (see
|
|
45
|
+
* docs/research/gestures.md, "no voluntary release").
|
|
13
46
|
*/
|
|
14
|
-
|
|
15
|
-
/** Fired when the responder is released or terminated. */
|
|
16
|
-
onRelease?: (host: ResponderHost) => void;
|
|
47
|
+
onClaim?: (source: ResponderHost) => void;
|
|
17
48
|
};
|
|
18
49
|
export type ResponderSystem = {
|
|
19
50
|
register(host: ResponderHost, getProps: () => ResponderProps): () => void;
|
|
@@ -21,7 +52,49 @@ export type ResponderSystem = {
|
|
|
21
52
|
touchMove(host: ResponderHost, touch: NativeTouch): void;
|
|
22
53
|
touchEnd(host: ResponderHost, touch: NativeTouch): void;
|
|
23
54
|
touchCancel(host: ResponderHost, touch: NativeTouch): void;
|
|
55
|
+
/**
|
|
56
|
+
* Something that is not a pointer event took the interaction. Returns
|
|
57
|
+
* whether the responder was actually given up — `false` means either
|
|
58
|
+
* nothing held it or the holder refused a reason that allows refusal.
|
|
59
|
+
*/
|
|
60
|
+
terminate(reason: TerminationReason): boolean;
|
|
61
|
+
/**
|
|
62
|
+
* THE OUT-OF-EVENT GRANT CHANNEL. A registered node asks for the responder
|
|
63
|
+
* between touch events, and the ordinary negotiation runs against a
|
|
64
|
+
* synthesized event at the last known pointer position.
|
|
65
|
+
*
|
|
66
|
+
* RN negotiates inside touch events only, so a recognizer that changes its
|
|
67
|
+
* mind on a TIMER has no way to take the interaction until the pointer next
|
|
68
|
+
* moves. `activateAfterLongPress` is exactly that recognizer: the press
|
|
69
|
+
* matures while the pointer is still, and waiting for the next move puts
|
|
70
|
+
* the "lifted" visual one frame late — or, for a press-and-hold that never
|
|
71
|
+
* moves again, never.
|
|
72
|
+
*
|
|
73
|
+
* The precedent is react-native-web, which added
|
|
74
|
+
* `onScrollShouldSetResponder` and `onSelectionChangeShouldSetResponder`
|
|
75
|
+
* for its own platform's realities; extending the model where the platform
|
|
76
|
+
* demands it is recorded as acceptable in docs/research/gestures.md, and
|
|
77
|
+
* this channel is documented there with its reason.
|
|
78
|
+
*
|
|
79
|
+
* Deliberately NOT a new prop and not a new grant path: it reuses
|
|
80
|
+
* `negotiateAndTransfer` unchanged, so capture still beats bubble, the LCA
|
|
81
|
+
* pruning still applies, and an ancestor that wants the interaction still
|
|
82
|
+
* wins it. The only thing that is new is WHEN the question gets asked. The
|
|
83
|
+
* synthesized event is the same one `terminate()` already builds from
|
|
84
|
+
* `session.lastTouch`, for the same reason.
|
|
85
|
+
*
|
|
86
|
+
* No `onResponderMove` is dispatched afterwards: the pointer did not move,
|
|
87
|
+
* and inventing a move to announce a grant would put a fabricated
|
|
88
|
+
* coordinate into every consumer's translation arithmetic.
|
|
89
|
+
*
|
|
90
|
+
* Returns whether `host` holds the responder once the negotiation is over
|
|
91
|
+
* — `false` when there is no interaction, when `host` is not on the path
|
|
92
|
+
* the interaction is travelling, or when somebody else won.
|
|
93
|
+
*/
|
|
94
|
+
requestResponder(host: ResponderHost): boolean;
|
|
24
95
|
/** The node currently holding the responder, or null. */
|
|
25
96
|
getResponder(): ResponderHost | null;
|
|
97
|
+
/** The node whose event source is carrying the interaction, or null. */
|
|
98
|
+
getSource(): ResponderHost | null;
|
|
26
99
|
};
|
|
27
100
|
export declare const createResponderSystem: (options: ResponderSystemOptions) => ResponderSystem;
|