react-native-gtkx 0.1.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.
Files changed (213) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +73 -0
  3. package/dist/animated/composite.d.ts +5 -0
  4. package/dist/animated/composite.js +132 -0
  5. package/dist/animated/composite.js.map +1 -0
  6. package/dist/animated/create-animated.d.ts +12 -0
  7. package/dist/animated/create-animated.js +17 -0
  8. package/dist/animated/create-animated.js.map +1 -0
  9. package/dist/animated/easing.d.ts +11 -0
  10. package/dist/animated/easing.js +91 -0
  11. package/dist/animated/easing.js.map +1 -0
  12. package/dist/animated/frame-loop.d.ts +6 -0
  13. package/dist/animated/frame-loop.js +25 -0
  14. package/dist/animated/frame-loop.js.map +1 -0
  15. package/dist/animated/index.d.ts +6 -0
  16. package/dist/animated/index.js +7 -0
  17. package/dist/animated/index.js.map +1 -0
  18. package/dist/animated/interpolate.d.ts +2 -0
  19. package/dist/animated/interpolate.js +90 -0
  20. package/dist/animated/interpolate.js.map +1 -0
  21. package/dist/animated/native-driver.d.ts +1 -0
  22. package/dist/animated/native-driver.js +17 -0
  23. package/dist/animated/native-driver.js.map +1 -0
  24. package/dist/animated/spring.d.ts +3 -0
  25. package/dist/animated/spring.js +67 -0
  26. package/dist/animated/spring.js.map +1 -0
  27. package/dist/animated/timing.d.ts +3 -0
  28. package/dist/animated/timing.js +30 -0
  29. package/dist/animated/timing.js.map +1 -0
  30. package/dist/animated/types.d.ts +51 -0
  31. package/dist/animated/types.js +6 -0
  32. package/dist/animated/types.js.map +1 -0
  33. package/dist/animated/value-animation.d.ts +9 -0
  34. package/dist/animated/value-animation.js +65 -0
  35. package/dist/animated/value-animation.js.map +1 -0
  36. package/dist/animated/value.d.ts +46 -0
  37. package/dist/animated/value.js +130 -0
  38. package/dist/animated/value.js.map +1 -0
  39. package/dist/apis/alert.d.ts +16 -0
  40. package/dist/apis/alert.js +33 -0
  41. package/dist/apis/alert.js.map +1 -0
  42. package/dist/apis/app-state.d.ts +11 -0
  43. package/dist/apis/app-state.js +54 -0
  44. package/dist/apis/app-state.js.map +1 -0
  45. package/dist/apis/appearance.d.ts +12 -0
  46. package/dist/apis/appearance.js +33 -0
  47. package/dist/apis/appearance.js.map +1 -0
  48. package/dist/apis/dev-settings.d.ts +9 -0
  49. package/dist/apis/dev-settings.js +25 -0
  50. package/dist/apis/dev-settings.js.map +1 -0
  51. package/dist/apis/dimensions.d.ts +14 -0
  52. package/dist/apis/dimensions.js +80 -0
  53. package/dist/apis/dimensions.js.map +1 -0
  54. package/dist/apis/emitter.d.ts +8 -0
  55. package/dist/apis/emitter.js +35 -0
  56. package/dist/apis/emitter.js.map +1 -0
  57. package/dist/apis/hooks.d.ts +11 -0
  58. package/dist/apis/hooks.js +29 -0
  59. package/dist/apis/hooks.js.map +1 -0
  60. package/dist/apis/host.d.ts +45 -0
  61. package/dist/apis/host.gtkx.d.ts +2 -0
  62. package/dist/apis/host.gtkx.js +301 -0
  63. package/dist/apis/host.gtkx.js.map +1 -0
  64. package/dist/apis/host.js +6 -0
  65. package/dist/apis/host.js.map +1 -0
  66. package/dist/apis/index.d.ts +39 -0
  67. package/dist/apis/index.js +21 -0
  68. package/dist/apis/index.js.map +1 -0
  69. package/dist/apis/linking.d.ts +7 -0
  70. package/dist/apis/linking.js +28 -0
  71. package/dist/apis/linking.js.map +1 -0
  72. package/dist/apis/platform.d.ts +14 -0
  73. package/dist/apis/platform.js +23 -0
  74. package/dist/apis/platform.js.map +1 -0
  75. package/dist/components/activity-indicator.d.ts +10 -0
  76. package/dist/components/activity-indicator.js +21 -0
  77. package/dist/components/activity-indicator.js.map +1 -0
  78. package/dist/components/animated.d.ts +34 -0
  79. package/dist/components/animated.js +152 -0
  80. package/dist/components/animated.js.map +1 -0
  81. package/dist/components/app-registry.d.ts +14 -0
  82. package/dist/components/app-registry.js +61 -0
  83. package/dist/components/app-registry.js.map +1 -0
  84. package/dist/components/flat-list.d.ts +48 -0
  85. package/dist/components/flat-list.js +23 -0
  86. package/dist/components/flat-list.js.map +1 -0
  87. package/dist/components/host-node.d.ts +10 -0
  88. package/dist/components/host-node.js +10 -0
  89. package/dist/components/host-node.js.map +1 -0
  90. package/dist/components/image-loader.d.ts +17 -0
  91. package/dist/components/image-loader.js +54 -0
  92. package/dist/components/image-loader.js.map +1 -0
  93. package/dist/components/image.d.ts +19 -0
  94. package/dist/components/image.js +73 -0
  95. package/dist/components/image.js.map +1 -0
  96. package/dist/components/index.d.ts +14 -0
  97. package/dist/components/index.js +14 -0
  98. package/dist/components/index.js.map +1 -0
  99. package/dist/components/modal.d.ts +12 -0
  100. package/dist/components/modal.js +18 -0
  101. package/dist/components/modal.js.map +1 -0
  102. package/dist/components/pressable.d.ts +33 -0
  103. package/dist/components/pressable.js +116 -0
  104. package/dist/components/pressable.js.map +1 -0
  105. package/dist/components/rect-store.d.ts +17 -0
  106. package/dist/components/rect-store.js +40 -0
  107. package/dist/components/rect-store.js.map +1 -0
  108. package/dist/components/root.d.ts +8 -0
  109. package/dist/components/root.js +59 -0
  110. package/dist/components/root.js.map +1 -0
  111. package/dist/components/scroll-view.d.ts +56 -0
  112. package/dist/components/scroll-view.js +324 -0
  113. package/dist/components/scroll-view.js.map +1 -0
  114. package/dist/components/switch.d.ts +11 -0
  115. package/dist/components/switch.js +20 -0
  116. package/dist/components/switch.js.map +1 -0
  117. package/dist/components/text-input.d.ts +23 -0
  118. package/dist/components/text-input.js +151 -0
  119. package/dist/components/text-input.js.map +1 -0
  120. package/dist/components/text.d.ts +11 -0
  121. package/dist/components/text.js +100 -0
  122. package/dist/components/text.js.map +1 -0
  123. package/dist/components/use-layout-child.d.ts +36 -0
  124. package/dist/components/use-layout-child.js +177 -0
  125. package/dist/components/use-layout-child.js.map +1 -0
  126. package/dist/components/view.d.ts +13 -0
  127. package/dist/components/view.js +60 -0
  128. package/dist/components/view.js.map +1 -0
  129. package/dist/components/virtualized-list.d.ts +67 -0
  130. package/dist/components/virtualized-list.js +519 -0
  131. package/dist/components/virtualized-list.js.map +1 -0
  132. package/dist/contracts.d.ts +119 -0
  133. package/dist/contracts.js +5 -0
  134. package/dist/contracts.js.map +1 -0
  135. package/dist/gtkx/bridge/index.d.ts +16 -0
  136. package/dist/gtkx/bridge/index.js +25 -0
  137. package/dist/gtkx/bridge/index.js.map +1 -0
  138. package/dist/gtkx/bridge/layout-manager.d.ts +11 -0
  139. package/dist/gtkx/bridge/layout-manager.js +87 -0
  140. package/dist/gtkx/bridge/layout-manager.js.map +1 -0
  141. package/dist/gtkx/bridge/measure.d.ts +9 -0
  142. package/dist/gtkx/bridge/measure.js +20 -0
  143. package/dist/gtkx/bridge/measure.js.map +1 -0
  144. package/dist/gtkx/bridge/theme.d.ts +4 -0
  145. package/dist/gtkx/bridge/theme.js +5 -0
  146. package/dist/gtkx/bridge/theme.js.map +1 -0
  147. package/dist/gtkx/bridge/view-box.d.ts +7 -0
  148. package/dist/gtkx/bridge/view-box.js +40 -0
  149. package/dist/gtkx/bridge/view-box.js.map +1 -0
  150. package/dist/index.d.ts +6 -0
  151. package/dist/index.js +7 -0
  152. package/dist/index.js.map +1 -0
  153. package/dist/layout/apply-style.d.ts +4 -0
  154. package/dist/layout/apply-style.js +148 -0
  155. package/dist/layout/apply-style.js.map +1 -0
  156. package/dist/layout/engine.d.ts +22 -0
  157. package/dist/layout/engine.js +90 -0
  158. package/dist/layout/engine.js.map +1 -0
  159. package/dist/layout/index.d.ts +3 -0
  160. package/dist/layout/index.js +4 -0
  161. package/dist/layout/index.js.map +1 -0
  162. package/dist/layout/node.d.ts +33 -0
  163. package/dist/layout/node.js +151 -0
  164. package/dist/layout/node.js.map +1 -0
  165. package/dist/layout/yoga.d.ts +13 -0
  166. package/dist/layout/yoga.js +52 -0
  167. package/dist/layout/yoga.js.map +1 -0
  168. package/dist/metro/index.d.ts +42 -0
  169. package/dist/metro/index.js +119 -0
  170. package/dist/metro/index.js.map +1 -0
  171. package/dist/runner/host-dev.d.ts +1 -0
  172. package/dist/runner/host-dev.js +208 -0
  173. package/dist/runner/host-dev.js.map +1 -0
  174. package/dist/runner/host.d.ts +1 -0
  175. package/dist/runner/host.js +101 -0
  176. package/dist/runner/host.js.map +1 -0
  177. package/dist/runner/index.d.ts +26 -0
  178. package/dist/runner/index.js +179 -0
  179. package/dist/runner/index.js.map +1 -0
  180. package/dist/style/colors.d.ts +17 -0
  181. package/dist/style/colors.js +375 -0
  182. package/dist/style/colors.js.map +1 -0
  183. package/dist/style/dev-warning.d.ts +2 -0
  184. package/dist/style/dev-warning.js +18 -0
  185. package/dist/style/dev-warning.js.map +1 -0
  186. package/dist/style/index.d.ts +7 -0
  187. package/dist/style/index.js +14 -0
  188. package/dist/style/index.js.map +1 -0
  189. package/dist/style/registry.d.ts +12 -0
  190. package/dist/style/registry.gtkx.d.ts +2 -0
  191. package/dist/style/registry.gtkx.js +9 -0
  192. package/dist/style/registry.gtkx.js.map +1 -0
  193. package/dist/style/registry.js +23 -0
  194. package/dist/style/registry.js.map +1 -0
  195. package/dist/style/split-style.d.ts +6 -0
  196. package/dist/style/split-style.js +107 -0
  197. package/dist/style/split-style.js.map +1 -0
  198. package/dist/style/style-sheet.d.ts +43 -0
  199. package/dist/style/style-sheet.js +57 -0
  200. package/dist/style/style-sheet.js.map +1 -0
  201. package/dist/style/text-align.d.ts +7 -0
  202. package/dist/style/text-align.js +22 -0
  203. package/dist/style/text-align.js.map +1 -0
  204. package/dist/style/visual-css.d.ts +6 -0
  205. package/dist/style/visual-css.js +133 -0
  206. package/dist/style/visual-css.js.map +1 -0
  207. package/dist/vite/index.d.ts +53 -0
  208. package/dist/vite/index.js +127 -0
  209. package/dist/vite/index.js.map +1 -0
  210. package/package.json +88 -0
  211. package/react-native.config.js +21 -0
  212. package/types.d.ts +43 -0
  213. package/types.js +4 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Anton Petrov
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,73 @@
1
+ <p align="center">
2
+ <img src="https://raw.githubusercontent.com/itsmepetrov/react-native-gtkx/main/docs/icon.svg" width="128" alt="react-native-gtkx" />
3
+ </p>
4
+
5
+ <h1 align="center">react-native-gtkx</h1>
6
+
7
+ <p align="center"><b>React Native for the Linux desktop.</b><br/>
8
+ Write apps against the familiar React Native API — they run as native GNOME<br/>
9
+ applications on real GTK4/Adwaita widgets, with no WebView and no canvas rendering.</p>
10
+
11
+ Under the hood: [gtkx](https://github.com/gtkx-org/gtkx) (a React reconciler for GTK4 on Node.js) + [Yoga](https://yogalayout.dev) (the RN flexbox engine). The model follows react-native-web: a compatibility layer on top of another renderer, with the `react-native` → `react-native-gtkx` alias provided by the Metro preset (Linux as a standard RN [out-of-tree platform](https://reactnative.dev/docs/out-of-tree-platforms) — `npx react-native run-linux` next to `run-ios`/`run-android`) or by the vite preset for Linux-first projects.
12
+
13
+ <p align="center">
14
+ <img src="https://raw.githubusercontent.com/itsmepetrov/react-native-gtkx/main/docs/shots/monitor.png" width="610" alt="system monitor — react-native-gtkx" />
15
+ </p>
16
+
17
+ _`examples/monitor`, live in a native GTK window: the UI is the React Native API, the data is the plain Node runtime (`node:os`, `node:fs`, timers). On this platform "native modules" are just Node — no bindings, no bridge, no permissions dance._
18
+
19
+ And the portability proof — `examples/profile` renders ONE source file with both renderers, not a single `@gtkx/*` import in it:
20
+
21
+ | react-native-gtkx (GTK4) | react-native-web (browser) |
22
+ | ------------------------------------------------------------------- | ----------------------------------------------------------------------- |
23
+ | <img src="https://raw.githubusercontent.com/itsmepetrov/react-native-gtkx/main/docs/shots/profile.png" width="400" alt="profile — GTK"/> | <img src="https://raw.githubusercontent.com/itsmepetrov/react-native-gtkx/main/docs/shots/profile-web.png" width="400" alt="profile — web"/> |
24
+
25
+ ## Status
26
+
27
+ - [x] Yoga + GtkFixed spike — **GO** (0 px accuracy, 500-node reflow in 0.17 ms, 60 fps — `docs/research/yoga-gtk-spike.md`)
28
+ - [x] Dev environment (UTM VM with a native GNOME session, headless sway for tests) and dev workflow
29
+ - [x] gtkx bridge (isolation from the RC API; [rc.1 workaround catalog](https://github.com/itsmepetrov/react-native-gtkx/blob/main/docs/gtkx-rc1-vs-main.md))
30
+ - [x] Layout engine (Yoga shadow tree, measure via Pango, batching, diffing, onLayout)
31
+ - [x] StyleSheet: layout/visual split, CSS Color 4 colors, PlatformColor → Adwaita
32
+ - [x] View / Text / Image / AppRegistry — first RN render in GTK
33
+ - [x] Platform / Dimensions / Appearance / AppState / Alert / Linking (+ hooks)
34
+ - [x] Pressable / TouchableOpacity / TextInput / ScrollView / FlatList / Switch / Modal / Animated
35
+ - [x] Vite preset (alias, platform extensions) + project template (install → window in 63 s)
36
+ - [x] Component gallery and documentation
37
+ - [x] Windowed lists: virtualization (10k rows), sticky headers, SectionList, scrollToIndex, viewability, inverted (RN chat semantics), refresh parity
38
+ - [x] Linux as an RN **out-of-tree platform**: the standard Metro/Babel toolchain, `react-native.config.js` declared by the dependency, `npx react-native run-linux`, compiled package distribution (attw-checked) — see `examples/rn-app` (a cli-init app with ios + android + linux)
39
+ - [x] **Fast Refresh on both toolchains**: `run-linux --dev` (Metro dev server + HMR in the GTK host, state preserved) and `gtkx dev` (vite)
40
+
41
+ Verified live: `examples/gallery` (the whole surface) and the interactive `examples/playground` — 372 tests (unit + component tests under headless Wayland).
42
+
43
+ ## Performance architecture
44
+
45
+ There is no "bridge tax" here. React Native's historic bottleneck — JSON
46
+ batches serialized between the JS and native threads — does not exist in this
47
+ architecture: gtkx binds GTK through an in-process FFI (NAPI-RS), so a widget
48
+ call is a synchronous C call on the same thread, with numbers and pointers
49
+ marshalled directly. That is the same direction React Native itself took with
50
+ JSI/Fabric, where Yoga and view commits run through direct synchronous calls.
51
+
52
+ Layout math runs in Yoga compiled to WASM (near-native speed): a 500-node
53
+ reflow measures at 0.13–0.17 ms. The GTK side is driven by our own
54
+ GtkLayoutManager subclass; a full measure+allocate pass over a 50-child
55
+ container costs ~0.21 ms including every FFI hop. Animation frames bypass
56
+ layout entirely — an Animated value write is a WeakMap store plus one queued
57
+ GTK allocation. Two orders of magnitude of headroom against a 60 fps frame
58
+ budget, measured, not estimated (see docs/research/yoga-gtk-spike.md and
59
+ docs/research/layout-manager.md).
60
+
61
+ ## Documentation
62
+
63
+ - [Getting Started](https://github.com/itsmepetrov/react-native-gtkx/blob/main/docs/getting-started.md) — a new project in a minute, and adding Linux to an existing RN app;
64
+ - [API v1](https://github.com/itsmepetrov/react-native-gtkx/blob/main/docs/api.md) — the full surface and differences from RN;
65
+ - [CONTRIBUTING](https://github.com/itsmepetrov/react-native-gtkx/blob/main/CONTRIBUTING.md) — developing the library (from macOS — via the UTM VM).
66
+
67
+ ## Requirements
68
+
69
+ Linux, GTK4 ≥ 4.20, libadwaita ≥ 1.8, Node.js ≥ 22.15 (24 recommended).
70
+
71
+ ## License
72
+
73
+ MIT
@@ -0,0 +1,5 @@
1
+ import type { CompositeAnimation, FrameScheduler, LoopConfig, ParallelConfig } from "./types";
2
+ export declare const sequence: (animations: CompositeAnimation[]) => CompositeAnimation;
3
+ export declare const parallel: (animations: CompositeAnimation[], config?: ParallelConfig) => CompositeAnimation;
4
+ export declare const createDelay: (scheduler: FrameScheduler, ms: number) => CompositeAnimation;
5
+ export declare const loop: (animation: CompositeAnimation, config?: LoopConfig) => CompositeAnimation;
@@ -0,0 +1,132 @@
1
+ // Composition operators over CompositeAnimation with RN finished-semantics:
2
+ // sequence aborts on the first unfinished child; parallel (stopTogether on by
3
+ // default) stops the siblings when one child ends unfinished and reports
4
+ // finished only when every child finished; loop restarts on natural
5
+ // completion, resetting the child before each iteration, and propagates an
6
+ // unfinished child result. delay(ms) is RN's own trick: a zero-duration
7
+ // timing with the given delay on a throwaway value.
8
+ import { Easing } from "./easing";
9
+ import { createTiming } from "./timing";
10
+ import { AnimatedValue } from "./value";
11
+ export const sequence = (animations) => {
12
+ // Index of the running child, -1 while idle.
13
+ let current = -1;
14
+ return {
15
+ start(callback) {
16
+ if (current !== -1) {
17
+ // Restart: abort the previous run first (its callback fires with
18
+ // { finished: false } synchronously).
19
+ animations[current].stop();
20
+ }
21
+ const startFrom = (index) => {
22
+ if (index >= animations.length) {
23
+ current = -1;
24
+ callback?.({ finished: true });
25
+ return;
26
+ }
27
+ current = index;
28
+ animations[index].start((result) => {
29
+ if (!result.finished) {
30
+ current = -1;
31
+ callback?.(result);
32
+ return;
33
+ }
34
+ startFrom(index + 1);
35
+ });
36
+ };
37
+ startFrom(0);
38
+ },
39
+ stop() {
40
+ if (current !== -1) {
41
+ animations[current].stop();
42
+ }
43
+ },
44
+ reset() {
45
+ current = -1;
46
+ for (const animation of animations) {
47
+ animation.reset();
48
+ }
49
+ },
50
+ };
51
+ };
52
+ export const parallel = (animations, config) => {
53
+ const stopTogether = config?.stopTogether ?? true;
54
+ const stopAll = () => {
55
+ for (const animation of animations) {
56
+ animation.stop();
57
+ }
58
+ };
59
+ return {
60
+ start(callback) {
61
+ if (animations.length === 0) {
62
+ callback?.({ finished: true });
63
+ return;
64
+ }
65
+ let remaining = animations.length;
66
+ let allFinished = true;
67
+ let done = false;
68
+ let stopping = false;
69
+ for (const animation of animations) {
70
+ animation.start((result) => {
71
+ remaining--;
72
+ if (!result.finished) {
73
+ allFinished = false;
74
+ if (stopTogether && !stopping && !done) {
75
+ stopping = true;
76
+ // Stops fire the sibling callbacks synchronously, so remaining
77
+ // reaches zero within this call chain.
78
+ stopAll();
79
+ }
80
+ }
81
+ if (remaining === 0 && !done) {
82
+ done = true;
83
+ callback?.({ finished: allFinished });
84
+ }
85
+ });
86
+ }
87
+ },
88
+ stop: stopAll,
89
+ reset() {
90
+ for (const animation of animations) {
91
+ animation.reset();
92
+ }
93
+ },
94
+ };
95
+ };
96
+ export const createDelay = (scheduler, ms) => createTiming(scheduler, new AnimatedValue(0), {
97
+ toValue: 0,
98
+ duration: 0,
99
+ delay: ms,
100
+ easing: Easing.linear,
101
+ });
102
+ export const loop = (animation, config) => {
103
+ const iterations = config?.iterations ?? -1;
104
+ const resetBeforeIteration = config?.resetBeforeIteration ?? true;
105
+ let stopped = false;
106
+ return {
107
+ start(callback) {
108
+ stopped = false;
109
+ let iterationsDone = 0;
110
+ const onIteration = (result) => {
111
+ if (stopped || !result.finished || iterationsDone === iterations) {
112
+ callback?.(result);
113
+ return;
114
+ }
115
+ iterationsDone++;
116
+ if (resetBeforeIteration) {
117
+ animation.reset();
118
+ }
119
+ animation.start(onIteration);
120
+ };
121
+ onIteration({ finished: true });
122
+ },
123
+ stop() {
124
+ stopped = true;
125
+ animation.stop();
126
+ },
127
+ reset() {
128
+ animation.reset();
129
+ },
130
+ };
131
+ };
132
+ //# sourceMappingURL=composite.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"composite.js","sourceRoot":"","sources":["../../src/animated/composite.ts"],"names":[],"mappings":"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","sourcesContent":["// Composition operators over CompositeAnimation with RN finished-semantics:\n// sequence aborts on the first unfinished child; parallel (stopTogether on by\n// default) stops the siblings when one child ends unfinished and reports\n// finished only when every child finished; loop restarts on natural\n// completion, resetting the child before each iteration, and propagates an\n// unfinished child result. delay(ms) is RN's own trick: a zero-duration\n// timing with the given delay on a throwaway value.\n\nimport { Easing } from \"./easing\"\nimport { createTiming } from \"./timing\"\nimport type {\n CompositeAnimation,\n EndResult,\n FrameScheduler,\n LoopConfig,\n ParallelConfig,\n} from \"./types\"\nimport { AnimatedValue } from \"./value\"\n\nexport const sequence = (\n animations: CompositeAnimation[],\n): CompositeAnimation => {\n // Index of the running child, -1 while idle.\n let current = -1\n return {\n start(callback) {\n if (current !== -1) {\n // Restart: abort the previous run first (its callback fires with\n // { finished: false } synchronously).\n animations[current]!.stop()\n }\n const startFrom = (index: number): void => {\n if (index >= animations.length) {\n current = -1\n callback?.({ finished: true })\n return\n }\n current = index\n animations[index]!.start((result) => {\n if (!result.finished) {\n current = -1\n callback?.(result)\n return\n }\n startFrom(index + 1)\n })\n }\n startFrom(0)\n },\n stop() {\n if (current !== -1) {\n animations[current]!.stop()\n }\n },\n reset() {\n current = -1\n for (const animation of animations) {\n animation.reset()\n }\n },\n }\n}\n\nexport const parallel = (\n animations: CompositeAnimation[],\n config?: ParallelConfig,\n): CompositeAnimation => {\n const stopTogether = config?.stopTogether ?? true\n const stopAll = (): void => {\n for (const animation of animations) {\n animation.stop()\n }\n }\n return {\n start(callback) {\n if (animations.length === 0) {\n callback?.({ finished: true })\n return\n }\n let remaining = animations.length\n let allFinished = true\n let done = false\n let stopping = false\n for (const animation of animations) {\n animation.start((result) => {\n remaining--\n if (!result.finished) {\n allFinished = false\n if (stopTogether && !stopping && !done) {\n stopping = true\n // Stops fire the sibling callbacks synchronously, so remaining\n // reaches zero within this call chain.\n stopAll()\n }\n }\n if (remaining === 0 && !done) {\n done = true\n callback?.({ finished: allFinished })\n }\n })\n }\n },\n stop: stopAll,\n reset() {\n for (const animation of animations) {\n animation.reset()\n }\n },\n }\n}\n\nexport const createDelay = (\n scheduler: FrameScheduler,\n ms: number,\n): CompositeAnimation =>\n createTiming(scheduler, new AnimatedValue(0), {\n toValue: 0,\n duration: 0,\n delay: ms,\n easing: Easing.linear,\n })\n\nexport const loop = (\n animation: CompositeAnimation,\n config?: LoopConfig,\n): CompositeAnimation => {\n const iterations = config?.iterations ?? -1\n const resetBeforeIteration = config?.resetBeforeIteration ?? true\n let stopped = false\n return {\n start(callback) {\n stopped = false\n let iterationsDone = 0\n const onIteration = (result: EndResult): void => {\n if (stopped || !result.finished || iterationsDone === iterations) {\n callback?.(result)\n return\n }\n iterationsDone++\n if (resetBeforeIteration) {\n animation.reset()\n }\n animation.start(onIteration)\n }\n onIteration({ finished: true })\n },\n stop() {\n stopped = true\n animation.stop()\n },\n reset() {\n animation.reset()\n },\n }\n}\n"]}
@@ -0,0 +1,12 @@
1
+ import type { CompositeAnimation, FrameScheduler, LoopConfig, ParallelConfig, SpringConfig, TimingConfig } from "./types";
2
+ import { AnimatedValue } from "./value";
3
+ export type AnimatedApi = {
4
+ Value: typeof AnimatedValue;
5
+ timing(value: AnimatedValue, config: TimingConfig): CompositeAnimation;
6
+ spring(value: AnimatedValue, config: SpringConfig): CompositeAnimation;
7
+ sequence(animations: CompositeAnimation[]): CompositeAnimation;
8
+ parallel(animations: CompositeAnimation[], config?: ParallelConfig): CompositeAnimation;
9
+ delay(ms: number): CompositeAnimation;
10
+ loop(animation: CompositeAnimation, config?: LoopConfig): CompositeAnimation;
11
+ };
12
+ export declare const createAnimated: (scheduler: FrameScheduler) => AnimatedApi;
@@ -0,0 +1,17 @@
1
+ // Factory wiring the frame driver into the whole Animated API. The GTK side
2
+ // passes a scheduler backed by the frame clock (orchestrator, task 009);
3
+ // tests pass a manual scheduler and drive frames by hand.
4
+ import { createDelay, loop, parallel, sequence } from "./composite";
5
+ import { createSpring } from "./spring";
6
+ import { createTiming } from "./timing";
7
+ import { AnimatedValue } from "./value";
8
+ export const createAnimated = (scheduler) => ({
9
+ Value: AnimatedValue,
10
+ timing: (value, config) => createTiming(scheduler, value, config),
11
+ spring: (value, config) => createSpring(scheduler, value, config),
12
+ sequence,
13
+ parallel,
14
+ delay: (ms) => createDelay(scheduler, ms),
15
+ loop,
16
+ });
17
+ //# sourceMappingURL=create-animated.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"create-animated.js","sourceRoot":"","sources":["../../src/animated/create-animated.ts"],"names":[],"mappings":"AAAA,4EAA4E;AAC5E,yEAAyE;AACzE,0DAA0D;AAE1D,OAAO,EAAE,WAAW,EAAE,IAAI,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAA;AACnE,OAAO,EAAE,YAAY,EAAE,MAAM,UAAU,CAAA;AACvC,OAAO,EAAE,YAAY,EAAE,MAAM,UAAU,CAAA;AASvC,OAAO,EAAE,aAAa,EAAE,MAAM,SAAS,CAAA;AAevC,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,SAAyB,EAAe,EAAE,CAAC,CAAC;IACzE,KAAK,EAAE,aAAa;IACpB,MAAM,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,CAAC,YAAY,CAAC,SAAS,EAAE,KAAK,EAAE,MAAM,CAAC;IACjE,MAAM,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,CAAC,YAAY,CAAC,SAAS,EAAE,KAAK,EAAE,MAAM,CAAC;IACjE,QAAQ;IACR,QAAQ;IACR,KAAK,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,WAAW,CAAC,SAAS,EAAE,EAAE,CAAC;IACzC,IAAI;CACL,CAAC,CAAA","sourcesContent":["// Factory wiring the frame driver into the whole Animated API. The GTK side\n// passes a scheduler backed by the frame clock (orchestrator, task 009);\n// tests pass a manual scheduler and drive frames by hand.\n\nimport { createDelay, loop, parallel, sequence } from \"./composite\"\nimport { createSpring } from \"./spring\"\nimport { createTiming } from \"./timing\"\nimport type {\n CompositeAnimation,\n FrameScheduler,\n LoopConfig,\n ParallelConfig,\n SpringConfig,\n TimingConfig,\n} from \"./types\"\nimport { AnimatedValue } from \"./value\"\n\nexport type AnimatedApi = {\n Value: typeof AnimatedValue\n timing(value: AnimatedValue, config: TimingConfig): CompositeAnimation\n spring(value: AnimatedValue, config: SpringConfig): CompositeAnimation\n sequence(animations: CompositeAnimation[]): CompositeAnimation\n parallel(\n animations: CompositeAnimation[],\n config?: ParallelConfig,\n ): CompositeAnimation\n delay(ms: number): CompositeAnimation\n loop(animation: CompositeAnimation, config?: LoopConfig): CompositeAnimation\n}\n\nexport const createAnimated = (scheduler: FrameScheduler): AnimatedApi => ({\n Value: AnimatedValue,\n timing: (value, config) => createTiming(scheduler, value, config),\n spring: (value, config) => createSpring(scheduler, value, config),\n sequence,\n parallel,\n delay: (ms) => createDelay(scheduler, ms),\n loop,\n})\n"]}
@@ -0,0 +1,11 @@
1
+ export type EasingFunction = (t: number) => number;
2
+ export declare const Easing: {
3
+ linear: EasingFunction;
4
+ ease: EasingFunction;
5
+ quad: EasingFunction;
6
+ cubic: EasingFunction;
7
+ bezier: (x1: number, y1: number, x2: number, y2: number) => EasingFunction;
8
+ in: (easing: EasingFunction) => EasingFunction;
9
+ out: (easing: EasingFunction) => EasingFunction;
10
+ inOut: (easing: EasingFunction) => EasingFunction;
11
+ };
@@ -0,0 +1,91 @@
1
+ // RN-compatible Easing subset. Every base function maps progress t in [0, 1]
2
+ // to a gain; in/out/inOut are modifiers over any base function, as in RN.
3
+ // Cubic bezier solver — the same approach as the bezier-easing package RN
4
+ // embeds: a coarse sample table brackets the parameter, Newton-Raphson
5
+ // refines it, and binary subdivision is the fallback where the curve is too
6
+ // flat for Newton to be reliable.
7
+ const SPLINE_TABLE_SIZE = 11;
8
+ const SAMPLE_STEP = 1 / (SPLINE_TABLE_SIZE - 1);
9
+ const NEWTON_ITERATIONS = 4;
10
+ const NEWTON_MIN_SLOPE = 0.001;
11
+ const SUBDIVISION_PRECISION = 1e-7;
12
+ const SUBDIVISION_MAX_ITERATIONS = 10;
13
+ const coeffA = (a1, a2) => 1 - 3 * a2 + 3 * a1;
14
+ const coeffB = (a1, a2) => 3 * a2 - 6 * a1;
15
+ const coeffC = (a1) => 3 * a1;
16
+ const calcBezier = (t, a1, a2) => ((coeffA(a1, a2) * t + coeffB(a1, a2)) * t + coeffC(a1)) * t;
17
+ const getSlope = (t, a1, a2) => 3 * coeffA(a1, a2) * t * t + 2 * coeffB(a1, a2) * t + coeffC(a1);
18
+ const bezier = (x1, y1, x2, y2) => {
19
+ if (x1 < 0 || x1 > 1 || x2 < 0 || x2 > 1) {
20
+ throw new Error("Easing.bezier: x1 and x2 must be in the [0, 1] range");
21
+ }
22
+ if (x1 === y1 && x2 === y2) {
23
+ return (t) => t;
24
+ }
25
+ const samples = new Float64Array(SPLINE_TABLE_SIZE);
26
+ for (let i = 0; i < SPLINE_TABLE_SIZE; i++) {
27
+ samples[i] = calcBezier(i * SAMPLE_STEP, x1, x2);
28
+ }
29
+ const getTForX = (x) => {
30
+ let intervalStart = 0;
31
+ let currentSample = 1;
32
+ for (; currentSample < SPLINE_TABLE_SIZE - 1 && samples[currentSample] <= x; currentSample++) {
33
+ intervalStart += SAMPLE_STEP;
34
+ }
35
+ currentSample--;
36
+ const dist = (x - samples[currentSample]) /
37
+ (samples[currentSample + 1] - samples[currentSample]);
38
+ let guess = intervalStart + dist * SAMPLE_STEP;
39
+ const initialSlope = getSlope(guess, x1, x2);
40
+ if (initialSlope >= NEWTON_MIN_SLOPE) {
41
+ for (let i = 0; i < NEWTON_ITERATIONS; i++) {
42
+ const slope = getSlope(guess, x1, x2);
43
+ if (slope === 0) {
44
+ return guess;
45
+ }
46
+ guess -= (calcBezier(guess, x1, x2) - x) / slope;
47
+ }
48
+ return guess;
49
+ }
50
+ if (initialSlope === 0) {
51
+ return guess;
52
+ }
53
+ let lower = intervalStart;
54
+ let upper = intervalStart + SAMPLE_STEP;
55
+ let t = guess;
56
+ for (let i = 0; i < SUBDIVISION_MAX_ITERATIONS; i++) {
57
+ t = lower + (upper - lower) / 2;
58
+ const error = calcBezier(t, x1, x2) - x;
59
+ if (Math.abs(error) <= SUBDIVISION_PRECISION) {
60
+ break;
61
+ }
62
+ if (error > 0) {
63
+ upper = t;
64
+ }
65
+ else {
66
+ lower = t;
67
+ }
68
+ }
69
+ return t;
70
+ };
71
+ return (t) => {
72
+ if (t <= 0) {
73
+ return 0;
74
+ }
75
+ if (t >= 1) {
76
+ return 1;
77
+ }
78
+ return calcBezier(getTForX(t), y1, y2);
79
+ };
80
+ };
81
+ export const Easing = {
82
+ linear: ((t) => t),
83
+ ease: bezier(0.42, 0, 1, 1),
84
+ quad: ((t) => t * t),
85
+ cubic: ((t) => t * t * t),
86
+ bezier,
87
+ in: (easing) => easing,
88
+ out: (easing) => (t) => 1 - easing(1 - t),
89
+ inOut: (easing) => (t) => t < 0.5 ? easing(t * 2) / 2 : 1 - easing((1 - t) * 2) / 2,
90
+ };
91
+ //# sourceMappingURL=easing.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"easing.js","sourceRoot":"","sources":["../../src/animated/easing.ts"],"names":[],"mappings":"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","sourcesContent":["// RN-compatible Easing subset. Every base function maps progress t in [0, 1]\n// to a gain; in/out/inOut are modifiers over any base function, as in RN.\n\nexport type EasingFunction = (t: number) => number\n\n// Cubic bezier solver — the same approach as the bezier-easing package RN\n// embeds: a coarse sample table brackets the parameter, Newton-Raphson\n// refines it, and binary subdivision is the fallback where the curve is too\n// flat for Newton to be reliable.\nconst SPLINE_TABLE_SIZE = 11\nconst SAMPLE_STEP = 1 / (SPLINE_TABLE_SIZE - 1)\nconst NEWTON_ITERATIONS = 4\nconst NEWTON_MIN_SLOPE = 0.001\nconst SUBDIVISION_PRECISION = 1e-7\nconst SUBDIVISION_MAX_ITERATIONS = 10\n\nconst coeffA = (a1: number, a2: number) => 1 - 3 * a2 + 3 * a1\nconst coeffB = (a1: number, a2: number) => 3 * a2 - 6 * a1\nconst coeffC = (a1: number) => 3 * a1\n\nconst calcBezier = (t: number, a1: number, a2: number) =>\n ((coeffA(a1, a2) * t + coeffB(a1, a2)) * t + coeffC(a1)) * t\n\nconst getSlope = (t: number, a1: number, a2: number) =>\n 3 * coeffA(a1, a2) * t * t + 2 * coeffB(a1, a2) * t + coeffC(a1)\n\nconst bezier = (\n x1: number,\n y1: number,\n x2: number,\n y2: number,\n): EasingFunction => {\n if (x1 < 0 || x1 > 1 || x2 < 0 || x2 > 1) {\n throw new Error(\"Easing.bezier: x1 and x2 must be in the [0, 1] range\")\n }\n if (x1 === y1 && x2 === y2) {\n return (t) => t\n }\n\n const samples = new Float64Array(SPLINE_TABLE_SIZE)\n for (let i = 0; i < SPLINE_TABLE_SIZE; i++) {\n samples[i] = calcBezier(i * SAMPLE_STEP, x1, x2)\n }\n\n const getTForX = (x: number): number => {\n let intervalStart = 0\n let currentSample = 1\n for (\n ;\n currentSample < SPLINE_TABLE_SIZE - 1 && samples[currentSample]! <= x;\n currentSample++\n ) {\n intervalStart += SAMPLE_STEP\n }\n currentSample--\n\n const dist =\n (x - samples[currentSample]!) /\n (samples[currentSample + 1]! - samples[currentSample]!)\n let guess = intervalStart + dist * SAMPLE_STEP\n\n const initialSlope = getSlope(guess, x1, x2)\n if (initialSlope >= NEWTON_MIN_SLOPE) {\n for (let i = 0; i < NEWTON_ITERATIONS; i++) {\n const slope = getSlope(guess, x1, x2)\n if (slope === 0) {\n return guess\n }\n guess -= (calcBezier(guess, x1, x2) - x) / slope\n }\n return guess\n }\n if (initialSlope === 0) {\n return guess\n }\n\n let lower = intervalStart\n let upper = intervalStart + SAMPLE_STEP\n let t = guess\n for (let i = 0; i < SUBDIVISION_MAX_ITERATIONS; i++) {\n t = lower + (upper - lower) / 2\n const error = calcBezier(t, x1, x2) - x\n if (Math.abs(error) <= SUBDIVISION_PRECISION) {\n break\n }\n if (error > 0) {\n upper = t\n } else {\n lower = t\n }\n }\n return t\n }\n\n return (t) => {\n if (t <= 0) {\n return 0\n }\n if (t >= 1) {\n return 1\n }\n return calcBezier(getTForX(t), y1, y2)\n }\n}\n\nexport const Easing = {\n linear: ((t) => t) as EasingFunction,\n ease: bezier(0.42, 0, 1, 1),\n quad: ((t) => t * t) as EasingFunction,\n cubic: ((t) => t * t * t) as EasingFunction,\n bezier,\n in: (easing: EasingFunction): EasingFunction => easing,\n out:\n (easing: EasingFunction): EasingFunction =>\n (t) =>\n 1 - easing(1 - t),\n inOut:\n (easing: EasingFunction): EasingFunction =>\n (t) =>\n t < 0.5 ? easing(t * 2) / 2 : 1 - easing((1 - t) * 2) / 2,\n}\n"]}
@@ -0,0 +1,6 @@
1
+ import type { FrameScheduler } from "./types";
2
+ export type FrameLoop = {
3
+ start(): void;
4
+ stop(): void;
5
+ };
6
+ export declare const createFrameLoop: (scheduler: FrameScheduler, step: (timeMs: number) => boolean) => FrameLoop;
@@ -0,0 +1,25 @@
1
+ // Minimal requestAnimationFrame-style pump over the injected scheduler: keeps
2
+ // re-booking one-shot frame callbacks while step() returns true. stop()
3
+ // cancels the pending booking, so a stopped loop holds no scheduler
4
+ // subscription (no idle ticks).
5
+ export const createFrameLoop = (scheduler, step) => {
6
+ let cancel = null;
7
+ const onFrame = (timeMs) => {
8
+ cancel = null;
9
+ if (step(timeMs)) {
10
+ cancel = scheduler.schedule(onFrame);
11
+ }
12
+ };
13
+ return {
14
+ start: () => {
15
+ if (cancel === null) {
16
+ cancel = scheduler.schedule(onFrame);
17
+ }
18
+ },
19
+ stop: () => {
20
+ cancel?.();
21
+ cancel = null;
22
+ },
23
+ };
24
+ };
25
+ //# sourceMappingURL=frame-loop.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"frame-loop.js","sourceRoot":"","sources":["../../src/animated/frame-loop.ts"],"names":[],"mappings":"AAAA,8EAA8E;AAC9E,wEAAwE;AACxE,oEAAoE;AACpE,gCAAgC;AAShC,MAAM,CAAC,MAAM,eAAe,GAAG,CAC7B,SAAyB,EACzB,IAAiC,EACtB,EAAE;IACb,IAAI,MAAM,GAAwB,IAAI,CAAA;IAEtC,MAAM,OAAO,GAAG,CAAC,MAAc,EAAQ,EAAE;QACvC,MAAM,GAAG,IAAI,CAAA;QACb,IAAI,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC;YACjB,MAAM,GAAG,SAAS,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAA;QACtC,CAAC;IACH,CAAC,CAAA;IAED,OAAO;QACL,KAAK,EAAE,GAAG,EAAE;YACV,IAAI,MAAM,KAAK,IAAI,EAAE,CAAC;gBACpB,MAAM,GAAG,SAAS,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAA;YACtC,CAAC;QACH,CAAC;QACD,IAAI,EAAE,GAAG,EAAE;YACT,MAAM,EAAE,EAAE,CAAA;YACV,MAAM,GAAG,IAAI,CAAA;QACf,CAAC;KACF,CAAA;AACH,CAAC,CAAA","sourcesContent":["// Minimal requestAnimationFrame-style pump over the injected scheduler: keeps\n// re-booking one-shot frame callbacks while step() returns true. stop()\n// cancels the pending booking, so a stopped loop holds no scheduler\n// subscription (no idle ticks).\n\nimport type { FrameScheduler } from \"./types\"\n\nexport type FrameLoop = {\n start(): void\n stop(): void\n}\n\nexport const createFrameLoop = (\n scheduler: FrameScheduler,\n step: (timeMs: number) => boolean,\n): FrameLoop => {\n let cancel: (() => void) | null = null\n\n const onFrame = (timeMs: number): void => {\n cancel = null\n if (step(timeMs)) {\n cancel = scheduler.schedule(onFrame)\n }\n }\n\n return {\n start: () => {\n if (cancel === null) {\n cancel = scheduler.schedule(onFrame)\n }\n },\n stop: () => {\n cancel?.()\n cancel = null\n },\n }\n}\n"]}
@@ -0,0 +1,6 @@
1
+ export type { AnimatedApi } from "./create-animated";
2
+ export { createAnimated } from "./create-animated";
3
+ export type { EasingFunction } from "./easing";
4
+ export { Easing } from "./easing";
5
+ export type { CompositeAnimation, EndCallback, EndResult, ExtrapolateType, FrameScheduler, InterpolationConfig, InterpolationListener, LoopConfig, ParallelConfig, SpringConfig, TimingConfig, ValueListener, } from "./types";
6
+ export { AnimatedInterpolation, AnimatedValue } from "./value";
@@ -0,0 +1,7 @@
1
+ // Animated module entry point (task 009, stream "animated"). Pure by
2
+ // contract: everything is driven by an injected FrameScheduler — the
3
+ // orchestrator connects the GTK frame clock and the Animated.* components.
4
+ export { createAnimated } from "./create-animated";
5
+ export { Easing } from "./easing";
6
+ export { AnimatedInterpolation, AnimatedValue } from "./value";
7
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/animated/index.ts"],"names":[],"mappings":"AAAA,qEAAqE;AACrE,qEAAqE;AACrE,2EAA2E;AAG3E,OAAO,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAA;AAElD,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAA;AAejC,OAAO,EAAE,qBAAqB,EAAE,aAAa,EAAE,MAAM,SAAS,CAAA","sourcesContent":["// Animated module entry point (task 009, stream \"animated\"). Pure by\n// contract: everything is driven by an injected FrameScheduler — the\n// orchestrator connects the GTK frame clock and the Animated.* components.\n\nexport type { AnimatedApi } from \"./create-animated\"\nexport { createAnimated } from \"./create-animated\"\nexport type { EasingFunction } from \"./easing\"\nexport { Easing } from \"./easing\"\nexport type {\n CompositeAnimation,\n EndCallback,\n EndResult,\n ExtrapolateType,\n FrameScheduler,\n InterpolationConfig,\n InterpolationListener,\n LoopConfig,\n ParallelConfig,\n SpringConfig,\n TimingConfig,\n ValueListener,\n} from \"./types\"\nexport { AnimatedInterpolation, AnimatedValue } from \"./value\"\n"]}
@@ -0,0 +1,2 @@
1
+ import type { InterpolationConfig } from "./types";
2
+ export declare const createInterpolator: (config: InterpolationConfig) => ((input: number) => number | string);
@@ -0,0 +1,90 @@
1
+ // Pure interpolation compiler: turns an InterpolationConfig into a
2
+ // number → number|string mapping. Supports multi-segment input ranges,
3
+ // "extend"/"clamp"/"identity" extrapolation (both sides) and suffixed string
4
+ // outputs ("45deg", "3.14rad"): the numeric part is interpolated, the shared
5
+ // suffix is preserved.
6
+ const NUMBER_WITH_SUFFIX = /^([+-]?(?:\d+\.?\d*|\.\d+)(?:[eE][+-]?\d+)?)(.*)$/;
7
+ const parseOutputRange = (outputRange) => {
8
+ const values = [];
9
+ let suffix = null;
10
+ for (const entry of outputRange) {
11
+ if (typeof entry === "number") {
12
+ if (suffix !== null && suffix !== "") {
13
+ throw new Error("interpolate: outputRange mixes numbers and strings");
14
+ }
15
+ suffix = "";
16
+ values.push(entry);
17
+ continue;
18
+ }
19
+ const match = NUMBER_WITH_SUFFIX.exec(entry);
20
+ if (!match) {
21
+ throw new Error(`interpolate: cannot parse output value "${entry}"`);
22
+ }
23
+ const entrySuffix = match[2] ?? "";
24
+ if (suffix === null) {
25
+ suffix = entrySuffix;
26
+ }
27
+ else if (suffix !== entrySuffix) {
28
+ throw new Error(`interpolate: outputRange mixes units ("${suffix}" vs "${entrySuffix}")`);
29
+ }
30
+ values.push(parseFloat(match[1]));
31
+ }
32
+ return { values, suffix: suffix ?? "" };
33
+ };
34
+ const validate = (config) => {
35
+ const { inputRange, outputRange } = config;
36
+ if (inputRange.length < 2) {
37
+ throw new Error("interpolate: inputRange must have at least 2 elements");
38
+ }
39
+ if (outputRange.length !== inputRange.length) {
40
+ throw new Error("interpolate: inputRange and outputRange must have the same length");
41
+ }
42
+ for (let i = 1; i < inputRange.length; i++) {
43
+ if (inputRange[i] < inputRange[i - 1]) {
44
+ throw new Error("interpolate: inputRange must be monotonically non-decreasing");
45
+ }
46
+ }
47
+ };
48
+ // Largest segment whose start is at or below the input (RN's findRange):
49
+ // inputs left of the range use the first segment, inputs right of it the
50
+ // last one, which is what "extend" extrapolation builds on.
51
+ const findSegment = (input, inputRange) => {
52
+ let i = 1;
53
+ for (; i < inputRange.length - 1; i++) {
54
+ if (inputRange[i] >= input) {
55
+ break;
56
+ }
57
+ }
58
+ return i - 1;
59
+ };
60
+ export const createInterpolator = (config) => {
61
+ validate(config);
62
+ const inputRange = [...config.inputRange];
63
+ const extrapolate = config.extrapolate ?? "extend";
64
+ const { values: outputValues, suffix } = parseOutputRange(config.outputRange);
65
+ const first = inputRange[0];
66
+ const last = inputRange[inputRange.length - 1];
67
+ const interpolateNumber = (rawInput) => {
68
+ const input = extrapolate === "clamp"
69
+ ? Math.min(Math.max(rawInput, first), last)
70
+ : rawInput;
71
+ const i = findSegment(input, inputRange);
72
+ const inMin = inputRange[i];
73
+ const inMax = inputRange[i + 1];
74
+ const outMin = outputValues[i];
75
+ const outMax = outputValues[i + 1];
76
+ if (inMin === inMax) {
77
+ return input <= inMin ? outMin : outMax;
78
+ }
79
+ const progress = (input - inMin) / (inMax - inMin);
80
+ return outMin + progress * (outMax - outMin);
81
+ };
82
+ return (input) => {
83
+ const outOfRange = input < first || input > last;
84
+ const result = extrapolate === "identity" && outOfRange
85
+ ? input
86
+ : interpolateNumber(input);
87
+ return suffix === "" ? result : `${result}${suffix}`;
88
+ };
89
+ };
90
+ //# sourceMappingURL=interpolate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"interpolate.js","sourceRoot":"","sources":["../../src/animated/interpolate.ts"],"names":[],"mappings":"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","sourcesContent":["// Pure interpolation compiler: turns an InterpolationConfig into a\n// number → number|string mapping. Supports multi-segment input ranges,\n// \"extend\"/\"clamp\"/\"identity\" extrapolation (both sides) and suffixed string\n// outputs (\"45deg\", \"3.14rad\"): the numeric part is interpolated, the shared\n// suffix is preserved.\n\nimport type { InterpolationConfig } from \"./types\"\n\nconst NUMBER_WITH_SUFFIX = /^([+-]?(?:\\d+\\.?\\d*|\\.\\d+)(?:[eE][+-]?\\d+)?)(.*)$/\n\ntype ParsedOutputRange = { values: number[]; suffix: string }\n\nconst parseOutputRange = (\n outputRange: readonly (number | string)[],\n): ParsedOutputRange => {\n const values: number[] = []\n let suffix: string | null = null\n for (const entry of outputRange) {\n if (typeof entry === \"number\") {\n if (suffix !== null && suffix !== \"\") {\n throw new Error(\"interpolate: outputRange mixes numbers and strings\")\n }\n suffix = \"\"\n values.push(entry)\n continue\n }\n const match = NUMBER_WITH_SUFFIX.exec(entry)\n if (!match) {\n throw new Error(`interpolate: cannot parse output value \"${entry}\"`)\n }\n const entrySuffix = match[2] ?? \"\"\n if (suffix === null) {\n suffix = entrySuffix\n } else if (suffix !== entrySuffix) {\n throw new Error(\n `interpolate: outputRange mixes units (\"${suffix}\" vs \"${entrySuffix}\")`,\n )\n }\n values.push(parseFloat(match[1]!))\n }\n return { values, suffix: suffix ?? \"\" }\n}\n\nconst validate = (config: InterpolationConfig): void => {\n const { inputRange, outputRange } = config\n if (inputRange.length < 2) {\n throw new Error(\"interpolate: inputRange must have at least 2 elements\")\n }\n if (outputRange.length !== inputRange.length) {\n throw new Error(\n \"interpolate: inputRange and outputRange must have the same length\",\n )\n }\n for (let i = 1; i < inputRange.length; i++) {\n if (inputRange[i]! < inputRange[i - 1]!) {\n throw new Error(\n \"interpolate: inputRange must be monotonically non-decreasing\",\n )\n }\n }\n}\n\n// Largest segment whose start is at or below the input (RN's findRange):\n// inputs left of the range use the first segment, inputs right of it the\n// last one, which is what \"extend\" extrapolation builds on.\nconst findSegment = (input: number, inputRange: number[]): number => {\n let i = 1\n for (; i < inputRange.length - 1; i++) {\n if (inputRange[i]! >= input) {\n break\n }\n }\n return i - 1\n}\n\nexport const createInterpolator = (\n config: InterpolationConfig,\n): ((input: number) => number | string) => {\n validate(config)\n const inputRange = [...config.inputRange]\n const extrapolate = config.extrapolate ?? \"extend\"\n const { values: outputValues, suffix } = parseOutputRange(config.outputRange)\n const first = inputRange[0]!\n const last = inputRange[inputRange.length - 1]!\n\n const interpolateNumber = (rawInput: number): number => {\n const input =\n extrapolate === \"clamp\"\n ? Math.min(Math.max(rawInput, first), last)\n : rawInput\n const i = findSegment(input, inputRange)\n const inMin = inputRange[i]!\n const inMax = inputRange[i + 1]!\n const outMin = outputValues[i]!\n const outMax = outputValues[i + 1]!\n if (inMin === inMax) {\n return input <= inMin ? outMin : outMax\n }\n const progress = (input - inMin) / (inMax - inMin)\n return outMin + progress * (outMax - outMin)\n }\n\n return (input: number): number | string => {\n const outOfRange = input < first || input > last\n const result =\n extrapolate === \"identity\" && outOfRange\n ? input\n : interpolateNumber(input)\n return suffix === \"\" ? result : `${result}${suffix}`\n }\n}\n"]}
@@ -0,0 +1 @@
1
+ export declare const warnNativeDriverIgnored: () => void;
@@ -0,0 +1,17 @@
1
+ // The GTK backend has no "native driver" — every animation already runs on
2
+ // the direct path (frame clock → value listeners → imperative widget
3
+ // updates), so useNativeDriver is accepted for RN source compatibility and
4
+ // ignored, with one dev warning per session.
5
+ let warned = false;
6
+ export const warnNativeDriverIgnored = () => {
7
+ if (warned) {
8
+ return;
9
+ }
10
+ warned = true;
11
+ const isProduction = typeof process !== "undefined" && process.env.NODE_ENV === "production";
12
+ if (!isProduction) {
13
+ console.warn("Animated: useNativeDriver is ignored on react-native-gtkx — " +
14
+ "animations always run on the direct GTK frame-clock path.");
15
+ }
16
+ };
17
+ //# sourceMappingURL=native-driver.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"native-driver.js","sourceRoot":"","sources":["../../src/animated/native-driver.ts"],"names":[],"mappings":"AAAA,2EAA2E;AAC3E,qEAAqE;AACrE,2EAA2E;AAC3E,6CAA6C;AAE7C,IAAI,MAAM,GAAG,KAAK,CAAA;AAElB,MAAM,CAAC,MAAM,uBAAuB,GAAG,GAAS,EAAE;IAChD,IAAI,MAAM,EAAE,CAAC;QACX,OAAM;IACR,CAAC;IACD,MAAM,GAAG,IAAI,CAAA;IACb,MAAM,YAAY,GAChB,OAAO,OAAO,KAAK,WAAW,IAAI,OAAO,CAAC,GAAG,CAAC,QAAQ,KAAK,YAAY,CAAA;IACzE,IAAI,CAAC,YAAY,EAAE,CAAC;QAClB,OAAO,CAAC,IAAI,CACV,8DAA8D;YAC5D,2DAA2D,CAC9D,CAAA;IACH,CAAC;AACH,CAAC,CAAA","sourcesContent":["// The GTK backend has no \"native driver\" — every animation already runs on\n// the direct path (frame clock → value listeners → imperative widget\n// updates), so useNativeDriver is accepted for RN source compatibility and\n// ignored, with one dev warning per session.\n\nlet warned = false\n\nexport const warnNativeDriverIgnored = (): void => {\n if (warned) {\n return\n }\n warned = true\n const isProduction =\n typeof process !== \"undefined\" && process.env.NODE_ENV === \"production\"\n if (!isProduction) {\n console.warn(\n \"Animated: useNativeDriver is ignored on react-native-gtkx — \" +\n \"animations always run on the direct GTK frame-clock path.\",\n )\n }\n}\n"]}
@@ -0,0 +1,3 @@
1
+ import type { CompositeAnimation, FrameScheduler, SpringConfig } from "./types";
2
+ import type { AnimatedValue } from "./value";
3
+ export declare const createSpring: (scheduler: FrameScheduler, value: AnimatedValue, config: SpringConfig) => CompositeAnimation;