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
@@ -0,0 +1,67 @@
1
+ // Animated.spring: analytic damped harmonic oscillator — the same closed-form
2
+ // solution RN uses — evaluated from the elapsed time the frame scheduler
3
+ // reports, so the trajectory is deterministic for any frame cadence. The run
4
+ // completes when both velocity and displacement fall under the rest
5
+ // thresholds (or as soon as overshootClamping trips), then snaps exactly to
6
+ // toValue.
7
+ import { warnNativeDriverIgnored } from "./native-driver";
8
+ import { createValueAnimation } from "./value-animation";
9
+ export const createSpring = (scheduler, value, config) => {
10
+ const { toValue, delay = 0 } = config;
11
+ const stiffness = config.stiffness ?? 100;
12
+ const damping = config.damping ?? 10;
13
+ const mass = config.mass ?? 1;
14
+ const initialVelocity = config.initialVelocity ?? 0;
15
+ const overshootClamping = config.overshootClamping ?? false;
16
+ const restDisplacementThreshold = config.restDisplacementThreshold ?? 0.001;
17
+ const restSpeedThreshold = config.restSpeedThreshold ?? 0.001;
18
+ if (stiffness <= 0 || damping <= 0 || mass <= 0) {
19
+ throw new Error("Animated.spring: stiffness, damping and mass must be positive");
20
+ }
21
+ if (config.useNativeDriver) {
22
+ warnNativeDriverIgnored();
23
+ }
24
+ const zeta = damping / (2 * Math.sqrt(stiffness * mass));
25
+ const omega0 = Math.sqrt(stiffness / mass); // undamped frequency, rad/s
26
+ const omega1 = omega0 * Math.sqrt(Math.abs(1 - zeta * zeta));
27
+ return createValueAnimation(scheduler, value, (startValue) => {
28
+ const x0 = toValue - startValue;
29
+ const v0 = -initialVelocity;
30
+ return (elapsedMs) => {
31
+ const t = (elapsedMs - delay) / 1000;
32
+ if (t < 0) {
33
+ return { position: null, done: false };
34
+ }
35
+ let position;
36
+ let velocity;
37
+ if (zeta < 1) {
38
+ // Underdamped oscillation.
39
+ const envelope = Math.exp(-zeta * omega0 * t);
40
+ const sin = Math.sin(omega1 * t);
41
+ const cos = Math.cos(omega1 * t);
42
+ const a2 = (v0 + zeta * omega0 * x0) / omega1;
43
+ position = toValue - envelope * (a2 * sin + x0 * cos);
44
+ velocity =
45
+ zeta * omega0 * envelope * (a2 * sin + x0 * cos) -
46
+ envelope * (cos * (v0 + zeta * omega0 * x0) - omega1 * x0 * sin);
47
+ }
48
+ else {
49
+ // Critically damped (RN applies the same formula when overdamped).
50
+ const envelope = Math.exp(-omega0 * t);
51
+ position = toValue - envelope * (x0 + (v0 + omega0 * x0) * t);
52
+ velocity = envelope * (v0 * (t * omega0 - 1) + t * x0 * omega0 * omega0);
53
+ }
54
+ // Checked before publishing, so a clamped spring never reports a value
55
+ // past its target.
56
+ const overshooting = overshootClamping &&
57
+ (startValue < toValue ? position > toValue : position < toValue);
58
+ const atRest = Math.abs(velocity) <= restSpeedThreshold &&
59
+ Math.abs(toValue - position) <= restDisplacementThreshold;
60
+ if (overshooting || atRest) {
61
+ return { position: toValue, done: true };
62
+ }
63
+ return { position, done: false };
64
+ };
65
+ });
66
+ };
67
+ //# sourceMappingURL=spring.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"spring.js","sourceRoot":"","sources":["../../src/animated/spring.ts"],"names":[],"mappings":"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","sourcesContent":["// Animated.spring: analytic damped harmonic oscillator — the same closed-form\n// solution RN uses — evaluated from the elapsed time the frame scheduler\n// reports, so the trajectory is deterministic for any frame cadence. The run\n// completes when both velocity and displacement fall under the rest\n// thresholds (or as soon as overshootClamping trips), then snaps exactly to\n// toValue.\n\nimport { warnNativeDriverIgnored } from \"./native-driver\"\nimport type { CompositeAnimation, FrameScheduler, SpringConfig } from \"./types\"\nimport type { AnimatedValue } from \"./value\"\nimport { createValueAnimation } from \"./value-animation\"\n\nexport const createSpring = (\n scheduler: FrameScheduler,\n value: AnimatedValue,\n config: SpringConfig,\n): CompositeAnimation => {\n const { toValue, delay = 0 } = config\n const stiffness = config.stiffness ?? 100\n const damping = config.damping ?? 10\n const mass = config.mass ?? 1\n const initialVelocity = config.initialVelocity ?? 0\n const overshootClamping = config.overshootClamping ?? false\n const restDisplacementThreshold = config.restDisplacementThreshold ?? 0.001\n const restSpeedThreshold = config.restSpeedThreshold ?? 0.001\n if (stiffness <= 0 || damping <= 0 || mass <= 0) {\n throw new Error(\n \"Animated.spring: stiffness, damping and mass must be positive\",\n )\n }\n if (config.useNativeDriver) {\n warnNativeDriverIgnored()\n }\n\n const zeta = damping / (2 * Math.sqrt(stiffness * mass))\n const omega0 = Math.sqrt(stiffness / mass) // undamped frequency, rad/s\n const omega1 = omega0 * Math.sqrt(Math.abs(1 - zeta * zeta))\n\n return createValueAnimation(scheduler, value, (startValue) => {\n const x0 = toValue - startValue\n const v0 = -initialVelocity\n return (elapsedMs) => {\n const t = (elapsedMs - delay) / 1000\n if (t < 0) {\n return { position: null, done: false }\n }\n\n let position: number\n let velocity: number\n if (zeta < 1) {\n // Underdamped oscillation.\n const envelope = Math.exp(-zeta * omega0 * t)\n const sin = Math.sin(omega1 * t)\n const cos = Math.cos(omega1 * t)\n const a2 = (v0 + zeta * omega0 * x0) / omega1\n position = toValue - envelope * (a2 * sin + x0 * cos)\n velocity =\n zeta * omega0 * envelope * (a2 * sin + x0 * cos) -\n envelope * (cos * (v0 + zeta * omega0 * x0) - omega1 * x0 * sin)\n } else {\n // Critically damped (RN applies the same formula when overdamped).\n const envelope = Math.exp(-omega0 * t)\n position = toValue - envelope * (x0 + (v0 + omega0 * x0) * t)\n velocity = envelope * (v0 * (t * omega0 - 1) + t * x0 * omega0 * omega0)\n }\n\n // Checked before publishing, so a clamped spring never reports a value\n // past its target.\n const overshooting =\n overshootClamping &&\n (startValue < toValue ? position > toValue : position < toValue)\n const atRest =\n Math.abs(velocity) <= restSpeedThreshold &&\n Math.abs(toValue - position) <= restDisplacementThreshold\n if (overshooting || atRest) {\n return { position: toValue, done: true }\n }\n return { position, done: false }\n }\n })\n}\n"]}
@@ -0,0 +1,3 @@
1
+ import type { CompositeAnimation, FrameScheduler, TimingConfig } from "./types";
2
+ import type { AnimatedValue } from "./value";
3
+ export declare const createTiming: (scheduler: FrameScheduler, value: AnimatedValue, config: TimingConfig) => CompositeAnimation;
@@ -0,0 +1,30 @@
1
+ // Animated.timing: duration-based easing toward toValue with RN defaults
2
+ // (duration 500 ms, easing inOut(ease)). delay waits out frames without
3
+ // touching the value; duration 0 jumps to toValue on the first frame past
4
+ // the delay.
5
+ import { Easing } from "./easing";
6
+ import { warnNativeDriverIgnored } from "./native-driver";
7
+ import { createValueAnimation } from "./value-animation";
8
+ const defaultEasing = Easing.inOut(Easing.ease);
9
+ export const createTiming = (scheduler, value, config) => {
10
+ const { toValue, delay = 0 } = config;
11
+ const duration = config.duration ?? 500;
12
+ const easing = config.easing ?? defaultEasing;
13
+ if (config.useNativeDriver) {
14
+ warnNativeDriverIgnored();
15
+ }
16
+ return createValueAnimation(scheduler, value, (startValue) => (elapsedMs) => {
17
+ const t = elapsedMs - delay;
18
+ if (t < 0) {
19
+ return { position: null, done: false };
20
+ }
21
+ if (duration <= 0 || t >= duration) {
22
+ return { position: toValue, done: true };
23
+ }
24
+ return {
25
+ position: startValue + easing(t / duration) * (toValue - startValue),
26
+ done: false,
27
+ };
28
+ });
29
+ };
30
+ //# sourceMappingURL=timing.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"timing.js","sourceRoot":"","sources":["../../src/animated/timing.ts"],"names":[],"mappings":"AAAA,yEAAyE;AACzE,wEAAwE;AACxE,0EAA0E;AAC1E,aAAa;AAEb,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAA;AACjC,OAAO,EAAE,uBAAuB,EAAE,MAAM,iBAAiB,CAAA;AAGzD,OAAO,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAA;AAExD,MAAM,aAAa,GAAG,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,CAAA;AAE/C,MAAM,CAAC,MAAM,YAAY,GAAG,CAC1B,SAAyB,EACzB,KAAoB,EACpB,MAAoB,EACA,EAAE;IACtB,MAAM,EAAE,OAAO,EAAE,KAAK,GAAG,CAAC,EAAE,GAAG,MAAM,CAAA;IACrC,MAAM,QAAQ,GAAG,MAAM,CAAC,QAAQ,IAAI,GAAG,CAAA;IACvC,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,IAAI,aAAa,CAAA;IAC7C,IAAI,MAAM,CAAC,eAAe,EAAE,CAAC;QAC3B,uBAAuB,EAAE,CAAA;IAC3B,CAAC;IAED,OAAO,oBAAoB,CAAC,SAAS,EAAE,KAAK,EAAE,CAAC,UAAU,EAAE,EAAE,CAAC,CAAC,SAAS,EAAE,EAAE;QAC1E,MAAM,CAAC,GAAG,SAAS,GAAG,KAAK,CAAA;QAC3B,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;YACV,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,CAAA;QACxC,CAAC;QACD,IAAI,QAAQ,IAAI,CAAC,IAAI,CAAC,IAAI,QAAQ,EAAE,CAAC;YACnC,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,CAAA;QAC1C,CAAC;QACD,OAAO;YACL,QAAQ,EAAE,UAAU,GAAG,MAAM,CAAC,CAAC,GAAG,QAAQ,CAAC,GAAG,CAAC,OAAO,GAAG,UAAU,CAAC;YACpE,IAAI,EAAE,KAAK;SACZ,CAAA;IACH,CAAC,CAAC,CAAA;AACJ,CAAC,CAAA","sourcesContent":["// Animated.timing: duration-based easing toward toValue with RN defaults\n// (duration 500 ms, easing inOut(ease)). delay waits out frames without\n// touching the value; duration 0 jumps to toValue on the first frame past\n// the delay.\n\nimport { Easing } from \"./easing\"\nimport { warnNativeDriverIgnored } from \"./native-driver\"\nimport type { CompositeAnimation, FrameScheduler, TimingConfig } from \"./types\"\nimport type { AnimatedValue } from \"./value\"\nimport { createValueAnimation } from \"./value-animation\"\n\nconst defaultEasing = Easing.inOut(Easing.ease)\n\nexport const createTiming = (\n scheduler: FrameScheduler,\n value: AnimatedValue,\n config: TimingConfig,\n): CompositeAnimation => {\n const { toValue, delay = 0 } = config\n const duration = config.duration ?? 500\n const easing = config.easing ?? defaultEasing\n if (config.useNativeDriver) {\n warnNativeDriverIgnored()\n }\n\n return createValueAnimation(scheduler, value, (startValue) => (elapsedMs) => {\n const t = elapsedMs - delay\n if (t < 0) {\n return { position: null, done: false }\n }\n if (duration <= 0 || t >= duration) {\n return { position: toValue, done: true }\n }\n return {\n position: startValue + easing(t / duration) * (toValue - startValue),\n done: false,\n }\n })\n}\n"]}
@@ -0,0 +1,51 @@
1
+ import type { EasingFunction } from "./easing";
2
+ export type FrameScheduler = {
3
+ schedule(cb: (timeMs: number) => void): () => void;
4
+ };
5
+ export type EndResult = {
6
+ finished: boolean;
7
+ };
8
+ export type EndCallback = (result: EndResult) => void;
9
+ export type CompositeAnimation = {
10
+ start(callback?: EndCallback): void;
11
+ stop(): void;
12
+ reset(): void;
13
+ };
14
+ export type ValueListener = (event: {
15
+ value: number;
16
+ }) => void;
17
+ export type InterpolationListener = (event: {
18
+ value: number | string;
19
+ }) => void;
20
+ export type ExtrapolateType = "extend" | "clamp" | "identity";
21
+ export type InterpolationConfig = {
22
+ inputRange: number[];
23
+ outputRange: number[] | string[];
24
+ extrapolate?: ExtrapolateType;
25
+ };
26
+ export type TimingConfig = {
27
+ toValue: number;
28
+ duration?: number;
29
+ delay?: number;
30
+ easing?: EasingFunction;
31
+ useNativeDriver?: boolean;
32
+ };
33
+ export type SpringConfig = {
34
+ toValue: number;
35
+ stiffness?: number;
36
+ damping?: number;
37
+ mass?: number;
38
+ initialVelocity?: number;
39
+ overshootClamping?: boolean;
40
+ restDisplacementThreshold?: number;
41
+ restSpeedThreshold?: number;
42
+ delay?: number;
43
+ useNativeDriver?: boolean;
44
+ };
45
+ export type ParallelConfig = {
46
+ stopTogether?: boolean;
47
+ };
48
+ export type LoopConfig = {
49
+ iterations?: number;
50
+ resetBeforeIteration?: boolean;
51
+ };
@@ -0,0 +1,6 @@
1
+ // Public contracts of the Animated module. The module is pure: no bridge or
2
+ // gtkx imports, no timers, no Date — time only ever arrives through the
3
+ // injected FrameScheduler, so the GTK frame clock (production) and a manual
4
+ // test driver are interchangeable.
5
+ export {};
6
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/animated/types.ts"],"names":[],"mappings":"AAAA,4EAA4E;AAC5E,wEAAwE;AACxE,4EAA4E;AAC5E,mCAAmC","sourcesContent":["// Public contracts of the Animated module. The module is pure: no bridge or\n// gtkx imports, no timers, no Date — time only ever arrives through the\n// injected FrameScheduler, so the GTK frame clock (production) and a manual\n// test driver are interchangeable.\n\nimport type { EasingFunction } from \"./easing\"\n\n// Frame driver injected by the host (GTK frame clock in production, a manual\n// scheduler in tests). schedule() books a one-shot callback for the next\n// frame — re-book from inside the callback to keep ticking — and returns an\n// unsubscribe that cancels the pending callback.\nexport type FrameScheduler = {\n schedule(cb: (timeMs: number) => void): () => void\n}\n\nexport type EndResult = { finished: boolean }\n\nexport type EndCallback = (result: EndResult) => void\n\n// RN CompositeAnimation subset, plus reset() which loop() relies on to snap\n// values back before each iteration (RN has it too).\nexport type CompositeAnimation = {\n start(callback?: EndCallback): void\n stop(): void\n reset(): void\n}\n\nexport type ValueListener = (event: { value: number }) => void\n\nexport type InterpolationListener = (event: { value: number | string }) => void\n\nexport type ExtrapolateType = \"extend\" | \"clamp\" | \"identity\"\n\nexport type InterpolationConfig = {\n inputRange: number[]\n outputRange: number[] | string[]\n // Applied to both sides of the input range (RN's extrapolateLeft/Right are\n // not split out in this subset). Default: \"extend\".\n extrapolate?: ExtrapolateType\n}\n\nexport type TimingConfig = {\n toValue: number\n duration?: number\n delay?: number\n easing?: EasingFunction\n // Accepted for RN source compatibility; the GTK backend has no native\n // driver (everything already runs on the direct frame-clock path), so the\n // flag is ignored with a single dev warning per session.\n useNativeDriver?: boolean\n}\n\nexport type SpringConfig = {\n toValue: number\n stiffness?: number\n damping?: number\n mass?: number\n initialVelocity?: number\n overshootClamping?: boolean\n restDisplacementThreshold?: number\n restSpeedThreshold?: number\n delay?: number\n useNativeDriver?: boolean\n}\n\nexport type ParallelConfig = {\n // Like RN: when one child ends unfinished, stop the remaining ones too.\n // Default: true.\n stopTogether?: boolean\n}\n\nexport type LoopConfig = {\n // -1 (default) loops forever.\n iterations?: number\n // Snap the child animation back to its starting value before every\n // iteration (RN default: true).\n resetBeforeIteration?: boolean\n}\n"]}
@@ -0,0 +1,9 @@
1
+ import type { CompositeAnimation, FrameScheduler } from "./types";
2
+ import type { AnimatedValue } from "./value";
3
+ export type StepResult = {
4
+ position: number | null;
5
+ done: boolean;
6
+ };
7
+ export type StepFn = (elapsedMs: number) => StepResult;
8
+ export type MakeStep = (startValue: number) => StepFn;
9
+ export declare const createValueAnimation: (scheduler: FrameScheduler, value: AnimatedValue, makeStep: MakeStep) => CompositeAnimation;
@@ -0,0 +1,65 @@
1
+ // Shared lifecycle for animations that drive a single AnimatedValue (timing,
2
+ // spring). Implements the RN semantics: a value runs at most one animation —
3
+ // a newer start() preempts the previous one with { finished: false }; natural
4
+ // completion reports { finished: true }; a finished or stopped run drops its
5
+ // frame subscription immediately (no idle ticks). The first frame after
6
+ // start() establishes t = 0 — there is no wall clock in this module, time
7
+ // only ever comes from the scheduler.
8
+ import { createFrameLoop } from "./frame-loop";
9
+ export const createValueAnimation = (scheduler, value, makeStep) => {
10
+ let stopActiveRun = null;
11
+ const start = (callback) => {
12
+ const step = makeStep(value.__getValue());
13
+ let startTime = null;
14
+ let ended = false;
15
+ const loop = createFrameLoop(scheduler, (timeMs) => {
16
+ if (ended) {
17
+ return false;
18
+ }
19
+ if (startTime === null) {
20
+ startTime = timeMs;
21
+ }
22
+ const { position, done } = step(timeMs - startTime);
23
+ if (position !== null) {
24
+ value.__updateValue(position);
25
+ }
26
+ if (done) {
27
+ end(true);
28
+ return false;
29
+ }
30
+ return true;
31
+ });
32
+ const handle = { stop: () => end(false) };
33
+ const end = (finished) => {
34
+ if (ended) {
35
+ return;
36
+ }
37
+ ended = true;
38
+ loop.stop();
39
+ if (stopActiveRun === handle.stop) {
40
+ stopActiveRun = null;
41
+ }
42
+ value.__endAnimation(handle);
43
+ callback?.({ finished });
44
+ };
45
+ stopActiveRun = handle.stop;
46
+ // Attaching preempts whatever ran on this value before (this animation's
47
+ // own previous run included) — the preempted run ends { finished: false }.
48
+ value.__startAnimation(handle);
49
+ if (!ended) {
50
+ loop.start();
51
+ }
52
+ };
53
+ return {
54
+ start,
55
+ stop: () => {
56
+ stopActiveRun?.();
57
+ },
58
+ // RN parity: composite reset stops the run and snaps the value back to
59
+ // its construction-time value (loop() relies on this between iterations).
60
+ reset: () => {
61
+ value.resetAnimation();
62
+ },
63
+ };
64
+ };
65
+ //# sourceMappingURL=value-animation.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"value-animation.js","sourceRoot":"","sources":["../../src/animated/value-animation.ts"],"names":[],"mappings":"AAAA,6EAA6E;AAC7E,6EAA6E;AAC7E,8EAA8E;AAC9E,6EAA6E;AAC7E,wEAAwE;AACxE,0EAA0E;AAC1E,sCAAsC;AAEtC,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAA;AAa9C,MAAM,CAAC,MAAM,oBAAoB,GAAG,CAClC,SAAyB,EACzB,KAAoB,EACpB,QAAkB,EACE,EAAE;IACtB,IAAI,aAAa,GAAwB,IAAI,CAAA;IAE7C,MAAM,KAAK,GAAG,CAAC,QAAsB,EAAQ,EAAE;QAC7C,MAAM,IAAI,GAAG,QAAQ,CAAC,KAAK,CAAC,UAAU,EAAE,CAAC,CAAA;QACzC,IAAI,SAAS,GAAkB,IAAI,CAAA;QACnC,IAAI,KAAK,GAAG,KAAK,CAAA;QAEjB,MAAM,IAAI,GAAG,eAAe,CAAC,SAAS,EAAE,CAAC,MAAM,EAAE,EAAE;YACjD,IAAI,KAAK,EAAE,CAAC;gBACV,OAAO,KAAK,CAAA;YACd,CAAC;YACD,IAAI,SAAS,KAAK,IAAI,EAAE,CAAC;gBACvB,SAAS,GAAG,MAAM,CAAA;YACpB,CAAC;YACD,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,GAAG,IAAI,CAAC,MAAM,GAAG,SAAS,CAAC,CAAA;YACnD,IAAI,QAAQ,KAAK,IAAI,EAAE,CAAC;gBACtB,KAAK,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAA;YAC/B,CAAC;YACD,IAAI,IAAI,EAAE,CAAC;gBACT,GAAG,CAAC,IAAI,CAAC,CAAA;gBACT,OAAO,KAAK,CAAA;YACd,CAAC;YACD,OAAO,IAAI,CAAA;QACb,CAAC,CAAC,CAAA;QAEF,MAAM,MAAM,GAAG,EAAE,IAAI,EAAE,GAAS,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAA;QAE/C,MAAM,GAAG,GAAG,CAAC,QAAiB,EAAQ,EAAE;YACtC,IAAI,KAAK,EAAE,CAAC;gBACV,OAAM;YACR,CAAC;YACD,KAAK,GAAG,IAAI,CAAA;YACZ,IAAI,CAAC,IAAI,EAAE,CAAA;YACX,IAAI,aAAa,KAAK,MAAM,CAAC,IAAI,EAAE,CAAC;gBAClC,aAAa,GAAG,IAAI,CAAA;YACtB,CAAC;YACD,KAAK,CAAC,cAAc,CAAC,MAAM,CAAC,CAAA;YAC5B,QAAQ,EAAE,CAAC,EAAE,QAAQ,EAAE,CAAC,CAAA;QAC1B,CAAC,CAAA;QAED,aAAa,GAAG,MAAM,CAAC,IAAI,CAAA;QAC3B,yEAAyE;QACzE,2EAA2E;QAC3E,KAAK,CAAC,gBAAgB,CAAC,MAAM,CAAC,CAAA;QAC9B,IAAI,CAAC,KAAK,EAAE,CAAC;YACX,IAAI,CAAC,KAAK,EAAE,CAAA;QACd,CAAC;IACH,CAAC,CAAA;IAED,OAAO;QACL,KAAK;QACL,IAAI,EAAE,GAAG,EAAE;YACT,aAAa,EAAE,EAAE,CAAA;QACnB,CAAC;QACD,uEAAuE;QACvE,0EAA0E;QAC1E,KAAK,EAAE,GAAG,EAAE;YACV,KAAK,CAAC,cAAc,EAAE,CAAA;QACxB,CAAC;KACF,CAAA;AACH,CAAC,CAAA","sourcesContent":["// Shared lifecycle for animations that drive a single AnimatedValue (timing,\n// spring). Implements the RN semantics: a value runs at most one animation —\n// a newer start() preempts the previous one with { finished: false }; natural\n// completion reports { finished: true }; a finished or stopped run drops its\n// frame subscription immediately (no idle ticks). The first frame after\n// start() establishes t = 0 — there is no wall clock in this module, time\n// only ever comes from the scheduler.\n\nimport { createFrameLoop } from \"./frame-loop\"\nimport type { CompositeAnimation, EndCallback, FrameScheduler } from \"./types\"\nimport type { AnimatedValue } from \"./value\"\n\n// Per-frame step: elapsed ms since the first frame of this run → the next\n// position (null while waiting out a delay: the value is not touched) and\n// whether the run is done. makeStep is invoked on every start() with the\n// value captured at that moment, so restarts pick up from wherever the value\n// currently is.\nexport type StepResult = { position: number | null; done: boolean }\nexport type StepFn = (elapsedMs: number) => StepResult\nexport type MakeStep = (startValue: number) => StepFn\n\nexport const createValueAnimation = (\n scheduler: FrameScheduler,\n value: AnimatedValue,\n makeStep: MakeStep,\n): CompositeAnimation => {\n let stopActiveRun: (() => void) | null = null\n\n const start = (callback?: EndCallback): void => {\n const step = makeStep(value.__getValue())\n let startTime: number | null = null\n let ended = false\n\n const loop = createFrameLoop(scheduler, (timeMs) => {\n if (ended) {\n return false\n }\n if (startTime === null) {\n startTime = timeMs\n }\n const { position, done } = step(timeMs - startTime)\n if (position !== null) {\n value.__updateValue(position)\n }\n if (done) {\n end(true)\n return false\n }\n return true\n })\n\n const handle = { stop: (): void => end(false) }\n\n const end = (finished: boolean): void => {\n if (ended) {\n return\n }\n ended = true\n loop.stop()\n if (stopActiveRun === handle.stop) {\n stopActiveRun = null\n }\n value.__endAnimation(handle)\n callback?.({ finished })\n }\n\n stopActiveRun = handle.stop\n // Attaching preempts whatever ran on this value before (this animation's\n // own previous run included) — the preempted run ends { finished: false }.\n value.__startAnimation(handle)\n if (!ended) {\n loop.start()\n }\n }\n\n return {\n start,\n stop: () => {\n stopActiveRun?.()\n },\n // RN parity: composite reset stops the run and snaps the value back to\n // its construction-time value (loop() relies on this between iterations).\n reset: () => {\n value.resetAnimation()\n },\n }\n}\n"]}
@@ -0,0 +1,46 @@
1
+ import type { InterpolationConfig, InterpolationListener, ValueListener } from "./types";
2
+ export type AnimationHandle = {
3
+ stop(): void;
4
+ };
5
+ type InterpolationParent = {
6
+ __getValue(): number | string;
7
+ addListener(listener: InterpolationListener): string;
8
+ removeListener(id: string): void;
9
+ };
10
+ export declare class AnimatedValue {
11
+ private _value;
12
+ private readonly _startingValue;
13
+ private readonly _listeners;
14
+ private _nextListenerId;
15
+ private _animation;
16
+ constructor(value: number);
17
+ setValue(value: number): void;
18
+ addListener(listener: ValueListener): string;
19
+ removeListener(id: string): void;
20
+ removeAllListeners(): void;
21
+ stopAnimation(callback?: (value: number) => void): void;
22
+ resetAnimation(callback?: (value: number) => void): void;
23
+ interpolate(config: InterpolationConfig): AnimatedInterpolation;
24
+ __getValue(): number;
25
+ /** @internal Called by the animation runner on every frame. */
26
+ __updateValue(value: number): void;
27
+ /** @internal Registers a running animation, preempting the previous one. */
28
+ __startAnimation(handle: AnimationHandle): void;
29
+ /** @internal */
30
+ __endAnimation(handle: AnimationHandle): void;
31
+ }
32
+ export declare class AnimatedInterpolation {
33
+ private readonly _parent;
34
+ private readonly _interpolator;
35
+ private readonly _listeners;
36
+ private _nextListenerId;
37
+ private _parentSubscription;
38
+ constructor(parent: InterpolationParent, config: InterpolationConfig);
39
+ __getValue(): number | string;
40
+ addListener(listener: InterpolationListener): string;
41
+ removeListener(id: string): void;
42
+ removeAllListeners(): void;
43
+ interpolate(config: InterpolationConfig): AnimatedInterpolation;
44
+ private _detachFromParent;
45
+ }
46
+ export {};
@@ -0,0 +1,130 @@
1
+ // Animated.Value and the read-only interpolation node. Values are observable
2
+ // numbers; the animation runner (value-animation.ts) drives them frame by
3
+ // frame through the __-prefixed internal hooks. Interpolation nodes subscribe
4
+ // to their parent lazily (only while they have listeners themselves) and can
5
+ // be interpolated again, cascading from the parent's numeric value.
6
+ import { createInterpolator } from "./interpolate";
7
+ // Cascading from a string-producing parent ("45deg") interpolates over its
8
+ // numeric part.
9
+ const numeric = (value) => typeof value === "number" ? value : parseFloat(value);
10
+ export class AnimatedValue {
11
+ _value;
12
+ _startingValue;
13
+ _listeners = new Map();
14
+ _nextListenerId = 1;
15
+ _animation = null;
16
+ constructor(value) {
17
+ this._value = value;
18
+ this._startingValue = value;
19
+ }
20
+ // Stops the running animation (its callback gets { finished: false }, as in
21
+ // RN) and jumps to the new value.
22
+ setValue(value) {
23
+ this._animation?.stop();
24
+ this.__updateValue(value);
25
+ }
26
+ addListener(listener) {
27
+ const id = String(this._nextListenerId++);
28
+ this._listeners.set(id, listener);
29
+ return id;
30
+ }
31
+ removeListener(id) {
32
+ this._listeners.delete(id);
33
+ }
34
+ removeAllListeners() {
35
+ this._listeners.clear();
36
+ }
37
+ // Stops the running animation where it stands and reports the current value
38
+ // to the callback. The stopped animation's own callback gets
39
+ // { finished: false }.
40
+ stopAnimation(callback) {
41
+ this._animation?.stop();
42
+ callback?.(this._value);
43
+ }
44
+ // Stops any running animation, then snaps back to the construction-time
45
+ // value. Unlike RN we do notify listeners about the snap-back: the direct
46
+ // GTK path renders from listener events, so a silent reset would leave
47
+ // widgets stale until the next animation frame.
48
+ resetAnimation(callback) {
49
+ this.stopAnimation(callback);
50
+ this.__updateValue(this._startingValue);
51
+ }
52
+ interpolate(config) {
53
+ return new AnimatedInterpolation(this, config);
54
+ }
55
+ __getValue() {
56
+ return this._value;
57
+ }
58
+ /** @internal Called by the animation runner on every frame. */
59
+ __updateValue(value) {
60
+ this._value = value;
61
+ for (const listener of [...this._listeners.values()]) {
62
+ listener({ value });
63
+ }
64
+ }
65
+ /** @internal Registers a running animation, preempting the previous one. */
66
+ __startAnimation(handle) {
67
+ const previous = this._animation;
68
+ this._animation = handle;
69
+ if (previous && previous !== handle) {
70
+ previous.stop();
71
+ }
72
+ }
73
+ /** @internal */
74
+ __endAnimation(handle) {
75
+ if (this._animation === handle) {
76
+ this._animation = null;
77
+ }
78
+ }
79
+ }
80
+ export class AnimatedInterpolation {
81
+ _parent;
82
+ _interpolator;
83
+ _listeners = new Map();
84
+ _nextListenerId = 1;
85
+ _parentSubscription = null;
86
+ constructor(parent, config) {
87
+ this._parent = parent;
88
+ this._interpolator = createInterpolator(config);
89
+ }
90
+ __getValue() {
91
+ return this._interpolator(numeric(this._parent.__getValue()));
92
+ }
93
+ addListener(listener) {
94
+ const id = String(this._nextListenerId++);
95
+ this._listeners.set(id, listener);
96
+ if (this._parentSubscription === null) {
97
+ // Lazy upstream subscription (same leak policy as the API emitters):
98
+ // attach with the first listener, detach with the last one.
99
+ this._parentSubscription = this._parent.addListener(({ value }) => {
100
+ const output = this._interpolator(numeric(value));
101
+ for (const entry of [...this._listeners.values()]) {
102
+ entry({ value: output });
103
+ }
104
+ });
105
+ }
106
+ return id;
107
+ }
108
+ removeListener(id) {
109
+ if (!this._listeners.delete(id)) {
110
+ return;
111
+ }
112
+ if (this._listeners.size === 0) {
113
+ this._detachFromParent();
114
+ }
115
+ }
116
+ removeAllListeners() {
117
+ this._listeners.clear();
118
+ this._detachFromParent();
119
+ }
120
+ interpolate(config) {
121
+ return new AnimatedInterpolation(this, config);
122
+ }
123
+ _detachFromParent() {
124
+ if (this._parentSubscription !== null) {
125
+ this._parent.removeListener(this._parentSubscription);
126
+ this._parentSubscription = null;
127
+ }
128
+ }
129
+ }
130
+ //# sourceMappingURL=value.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"value.js","sourceRoot":"","sources":["../../src/animated/value.ts"],"names":[],"mappings":"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","sourcesContent":["// Animated.Value and the read-only interpolation node. Values are observable\n// numbers; the animation runner (value-animation.ts) drives them frame by\n// frame through the __-prefixed internal hooks. Interpolation nodes subscribe\n// to their parent lazily (only while they have listeners themselves) and can\n// be interpolated again, cascading from the parent's numeric value.\n\nimport { createInterpolator } from \"./interpolate\"\nimport type {\n InterpolationConfig,\n InterpolationListener,\n ValueListener,\n} from \"./types\"\n\n// Internal handle a running animation registers on its value; the value calls\n// stop() to preempt it when a newer animation (or setValue) takes over — the\n// preempted animation ends with { finished: false }, matching RN.\nexport type AnimationHandle = { stop(): void }\n\n// Minimal parent protocol shared by AnimatedValue and AnimatedInterpolation,\n// enabling cascaded interpolate() chains over either kind of node.\ntype InterpolationParent = {\n __getValue(): number | string\n addListener(listener: InterpolationListener): string\n removeListener(id: string): void\n}\n\n// Cascading from a string-producing parent (\"45deg\") interpolates over its\n// numeric part.\nconst numeric = (value: number | string): number =>\n typeof value === \"number\" ? value : parseFloat(value)\n\nexport class AnimatedValue {\n private _value: number\n private readonly _startingValue: number\n private readonly _listeners = new Map<string, ValueListener>()\n private _nextListenerId = 1\n private _animation: AnimationHandle | null = null\n\n constructor(value: number) {\n this._value = value\n this._startingValue = value\n }\n\n // Stops the running animation (its callback gets { finished: false }, as in\n // RN) and jumps to the new value.\n setValue(value: number): void {\n this._animation?.stop()\n this.__updateValue(value)\n }\n\n addListener(listener: ValueListener): string {\n const id = String(this._nextListenerId++)\n this._listeners.set(id, listener)\n return id\n }\n\n removeListener(id: string): void {\n this._listeners.delete(id)\n }\n\n removeAllListeners(): void {\n this._listeners.clear()\n }\n\n // Stops the running animation where it stands and reports the current value\n // to the callback. The stopped animation's own callback gets\n // { finished: false }.\n stopAnimation(callback?: (value: number) => void): void {\n this._animation?.stop()\n callback?.(this._value)\n }\n\n // Stops any running animation, then snaps back to the construction-time\n // value. Unlike RN we do notify listeners about the snap-back: the direct\n // GTK path renders from listener events, so a silent reset would leave\n // widgets stale until the next animation frame.\n resetAnimation(callback?: (value: number) => void): void {\n this.stopAnimation(callback)\n this.__updateValue(this._startingValue)\n }\n\n interpolate(config: InterpolationConfig): AnimatedInterpolation {\n return new AnimatedInterpolation(this, config)\n }\n\n __getValue(): number {\n return this._value\n }\n\n /** @internal Called by the animation runner on every frame. */\n __updateValue(value: number): void {\n this._value = value\n for (const listener of [...this._listeners.values()]) {\n listener({ value })\n }\n }\n\n /** @internal Registers a running animation, preempting the previous one. */\n __startAnimation(handle: AnimationHandle): void {\n const previous = this._animation\n this._animation = handle\n if (previous && previous !== handle) {\n previous.stop()\n }\n }\n\n /** @internal */\n __endAnimation(handle: AnimationHandle): void {\n if (this._animation === handle) {\n this._animation = null\n }\n }\n}\n\nexport class AnimatedInterpolation {\n private readonly _parent: InterpolationParent\n private readonly _interpolator: (input: number) => number | string\n private readonly _listeners = new Map<string, InterpolationListener>()\n private _nextListenerId = 1\n private _parentSubscription: string | null = null\n\n constructor(parent: InterpolationParent, config: InterpolationConfig) {\n this._parent = parent\n this._interpolator = createInterpolator(config)\n }\n\n __getValue(): number | string {\n return this._interpolator(numeric(this._parent.__getValue()))\n }\n\n addListener(listener: InterpolationListener): string {\n const id = String(this._nextListenerId++)\n this._listeners.set(id, listener)\n if (this._parentSubscription === null) {\n // Lazy upstream subscription (same leak policy as the API emitters):\n // attach with the first listener, detach with the last one.\n this._parentSubscription = this._parent.addListener(({ value }) => {\n const output = this._interpolator(numeric(value))\n for (const entry of [...this._listeners.values()]) {\n entry({ value: output })\n }\n })\n }\n return id\n }\n\n removeListener(id: string): void {\n if (!this._listeners.delete(id)) {\n return\n }\n if (this._listeners.size === 0) {\n this._detachFromParent()\n }\n }\n\n removeAllListeners(): void {\n this._listeners.clear()\n this._detachFromParent()\n }\n\n interpolate(config: InterpolationConfig): AnimatedInterpolation {\n return new AnimatedInterpolation(this, config)\n }\n\n private _detachFromParent(): void {\n if (this._parentSubscription !== null) {\n this._parent.removeListener(this._parentSubscription)\n this._parentSubscription = null\n }\n }\n}\n"]}
@@ -0,0 +1,16 @@
1
+ import type { AlertButtonStyle, AlertHost } from "./host";
2
+ export type AlertButton = {
3
+ text?: string;
4
+ onPress?: (value?: string) => void;
5
+ isPreferred?: boolean;
6
+ style?: AlertButtonStyle;
7
+ };
8
+ export type AlertOptions = {
9
+ cancelable?: boolean;
10
+ onDismiss?: () => void;
11
+ userInterfaceStyle?: "unspecified" | "light" | "dark";
12
+ };
13
+ export declare const createAlert: (host: AlertHost) => {
14
+ alert: (title: string, message?: string, buttons?: AlertButton[], options?: AlertOptions) => void;
15
+ };
16
+ export type AlertModule = ReturnType<typeof createAlert>;
@@ -0,0 +1,33 @@
1
+ export const createAlert = (host) => {
2
+ // Fire-and-forget like react-native's Alert.alert: the pressed button's
3
+ // onPress (or options.onDismiss) is called when the dialog resolves.
4
+ const alert = (title, message, buttons, options) => {
5
+ const effective = buttons !== undefined && buttons.length > 0 ? buttons : [{ text: "OK" }];
6
+ const hostButtons = effective.map((button, index) => ({
7
+ id: String(index),
8
+ label: button.text ?? "",
9
+ style: button.style ?? "default",
10
+ isPreferred: button.isPreferred ?? false,
11
+ }));
12
+ void host
13
+ .showAlert({
14
+ title,
15
+ message,
16
+ buttons: hostButtons,
17
+ cancelable: options?.cancelable ?? true,
18
+ })
19
+ .then((responseId) => {
20
+ const pressed = responseId === null ? undefined : effective[Number(responseId)];
21
+ if (pressed) {
22
+ pressed.onPress?.();
23
+ return;
24
+ }
25
+ options?.onDismiss?.();
26
+ })
27
+ .catch((error) => {
28
+ console.error("[react-native-gtkx] Alert.alert failed:", error);
29
+ });
30
+ };
31
+ return { alert };
32
+ };
33
+ //# sourceMappingURL=alert.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"alert.js","sourceRoot":"","sources":["../../src/apis/alert.ts"],"names":[],"mappings":"AAiBA,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,IAAe,EAAE,EAAE;IAC7C,wEAAwE;IACxE,qEAAqE;IACrE,MAAM,KAAK,GAAG,CACZ,KAAa,EACb,OAAgB,EAChB,OAAuB,EACvB,OAAsB,EAChB,EAAE;QACR,MAAM,SAAS,GACb,OAAO,KAAK,SAAS,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAA;QAC1E,MAAM,WAAW,GAAsB,SAAS,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,KAAK,EAAE,EAAE,CAAC,CAAC;YACvE,EAAE,EAAE,MAAM,CAAC,KAAK,CAAC;YACjB,KAAK,EAAE,MAAM,CAAC,IAAI,IAAI,EAAE;YACxB,KAAK,EAAE,MAAM,CAAC,KAAK,IAAI,SAAS;YAChC,WAAW,EAAE,MAAM,CAAC,WAAW,IAAI,KAAK;SACzC,CAAC,CAAC,CAAA;QACH,KAAK,IAAI;aACN,SAAS,CAAC;YACT,KAAK;YACL,OAAO;YACP,OAAO,EAAE,WAAW;YACpB,UAAU,EAAE,OAAO,EAAE,UAAU,IAAI,IAAI;SACxC,CAAC;aACD,IAAI,CAAC,CAAC,UAAU,EAAE,EAAE;YACnB,MAAM,OAAO,GACX,UAAU,KAAK,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,CAAA;YACjE,IAAI,OAAO,EAAE,CAAC;gBACZ,OAAO,CAAC,OAAO,EAAE,EAAE,CAAA;gBACnB,OAAM;YACR,CAAC;YACD,OAAO,EAAE,SAAS,EAAE,EAAE,CAAA;QACxB,CAAC,CAAC;aACD,KAAK,CAAC,CAAC,KAAc,EAAE,EAAE;YACxB,OAAO,CAAC,KAAK,CAAC,yCAAyC,EAAE,KAAK,CAAC,CAAA;QACjE,CAAC,CAAC,CAAA;IACN,CAAC,CAAA;IAED,OAAO,EAAE,KAAK,EAAE,CAAA;AAClB,CAAC,CAAA","sourcesContent":["import type { AlertButtonStyle, AlertHost, HostAlertButton } from \"./host\"\n\nexport type AlertButton = {\n text?: string\n onPress?: (value?: string) => void\n isPreferred?: boolean\n style?: AlertButtonStyle\n}\n\nexport type AlertOptions = {\n cancelable?: boolean\n onDismiss?: () => void\n // Accepted for react-native parity; ignored here — the theme is controlled\n // globally via Appearance/AdwStyleManager.\n userInterfaceStyle?: \"unspecified\" | \"light\" | \"dark\"\n}\n\nexport const createAlert = (host: AlertHost) => {\n // Fire-and-forget like react-native's Alert.alert: the pressed button's\n // onPress (or options.onDismiss) is called when the dialog resolves.\n const alert = (\n title: string,\n message?: string,\n buttons?: AlertButton[],\n options?: AlertOptions,\n ): void => {\n const effective: AlertButton[] =\n buttons !== undefined && buttons.length > 0 ? buttons : [{ text: \"OK\" }]\n const hostButtons: HostAlertButton[] = effective.map((button, index) => ({\n id: String(index),\n label: button.text ?? \"\",\n style: button.style ?? \"default\",\n isPreferred: button.isPreferred ?? false,\n }))\n void host\n .showAlert({\n title,\n message,\n buttons: hostButtons,\n cancelable: options?.cancelable ?? true,\n })\n .then((responseId) => {\n const pressed =\n responseId === null ? undefined : effective[Number(responseId)]\n if (pressed) {\n pressed.onPress?.()\n return\n }\n options?.onDismiss?.()\n })\n .catch((error: unknown) => {\n console.error(\"[react-native-gtkx] Alert.alert failed:\", error)\n })\n }\n\n return { alert }\n}\n\nexport type AlertModule = ReturnType<typeof createAlert>\n"]}
@@ -0,0 +1,11 @@
1
+ import type { SubscriptionHandle } from "../contracts";
2
+ import type { AppStateHost } from "./host";
3
+ export type AppStateStatus = "active" | "background";
4
+ export type AppStateEvent = "change" | "focus" | "blur";
5
+ export type AppStateHandler = (state: AppStateStatus) => void;
6
+ export declare const createAppState: (host: AppStateHost) => {
7
+ isAvailable: true;
8
+ readonly currentState: AppStateStatus;
9
+ addEventListener: (type: AppStateEvent, handler: AppStateHandler) => SubscriptionHandle;
10
+ };
11
+ export type AppStateModule = ReturnType<typeof createAppState>;
@@ -0,0 +1,54 @@
1
+ const EVENT_TYPES = ["change", "focus", "blur"];
2
+ export const createAppState = (host) => {
3
+ const entries = new Set();
4
+ let hostSubscription = null;
5
+ let tracked = null;
6
+ const compute = () => host.isActive() ? "active" : "background";
7
+ const onHostChange = () => {
8
+ const next = compute();
9
+ if (next === tracked) {
10
+ return;
11
+ }
12
+ tracked = next;
13
+ for (const entry of [...entries]) {
14
+ if (entry.type === "change" ||
15
+ (entry.type === "focus" && next === "active") ||
16
+ (entry.type === "blur" && next === "background")) {
17
+ entry.handler(next);
18
+ }
19
+ }
20
+ };
21
+ const addEventListener = (type, handler) => {
22
+ if (!EVENT_TYPES.includes(type)) {
23
+ throw new Error(`AppState.addEventListener: unsupported event type "${String(type)}"`);
24
+ }
25
+ const entry = { type, handler };
26
+ entries.add(entry);
27
+ if (entries.size === 1) {
28
+ tracked = compute();
29
+ hostSubscription = host.onActiveChange(onHostChange);
30
+ }
31
+ return {
32
+ remove: () => {
33
+ if (!entries.delete(entry)) {
34
+ return;
35
+ }
36
+ if (entries.size === 0) {
37
+ hostSubscription?.remove();
38
+ hostSubscription = null;
39
+ tracked = null;
40
+ }
41
+ },
42
+ };
43
+ };
44
+ return {
45
+ isAvailable: true,
46
+ // Event-driven while at least one listener is attached, computed live
47
+ // from the host otherwise.
48
+ get currentState() {
49
+ return tracked ?? compute();
50
+ },
51
+ addEventListener,
52
+ };
53
+ };
54
+ //# sourceMappingURL=app-state.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"app-state.js","sourceRoot":"","sources":["../../src/apis/app-state.ts"],"names":[],"mappings":"AAWA,MAAM,WAAW,GAA6B,CAAC,QAAQ,EAAE,OAAO,EAAE,MAAM,CAAC,CAAA;AAEzE,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,IAAkB,EAAE,EAAE;IAGnD,MAAM,OAAO,GAAG,IAAI,GAAG,EAAS,CAAA;IAChC,IAAI,gBAAgB,GAA8B,IAAI,CAAA;IACtD,IAAI,OAAO,GAA0B,IAAI,CAAA;IAEzC,MAAM,OAAO,GAAG,GAAmB,EAAE,CACnC,IAAI,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,YAAY,CAAA;IAE3C,MAAM,YAAY,GAAG,GAAS,EAAE;QAC9B,MAAM,IAAI,GAAG,OAAO,EAAE,CAAA;QACtB,IAAI,IAAI,KAAK,OAAO,EAAE,CAAC;YACrB,OAAM;QACR,CAAC;QACD,OAAO,GAAG,IAAI,CAAA;QACd,KAAK,MAAM,KAAK,IAAI,CAAC,GAAG,OAAO,CAAC,EAAE,CAAC;YACjC,IACE,KAAK,CAAC,IAAI,KAAK,QAAQ;gBACvB,CAAC,KAAK,CAAC,IAAI,KAAK,OAAO,IAAI,IAAI,KAAK,QAAQ,CAAC;gBAC7C,CAAC,KAAK,CAAC,IAAI,KAAK,MAAM,IAAI,IAAI,KAAK,YAAY,CAAC,EAChD,CAAC;gBACD,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAA;YACrB,CAAC;QACH,CAAC;IACH,CAAC,CAAA;IAED,MAAM,gBAAgB,GAAG,CACvB,IAAmB,EACnB,OAAwB,EACJ,EAAE;QACtB,IAAI,CAAC,WAAW,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;YAChC,MAAM,IAAI,KAAK,CACb,sDAAsD,MAAM,CAAC,IAAI,CAAC,GAAG,CACtE,CAAA;QACH,CAAC;QACD,MAAM,KAAK,GAAU,EAAE,IAAI,EAAE,OAAO,EAAE,CAAA;QACtC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAA;QAClB,IAAI,OAAO,CAAC,IAAI,KAAK,CAAC,EAAE,CAAC;YACvB,OAAO,GAAG,OAAO,EAAE,CAAA;YACnB,gBAAgB,GAAG,IAAI,CAAC,cAAc,CAAC,YAAY,CAAC,CAAA;QACtD,CAAC;QACD,OAAO;YACL,MAAM,EAAE,GAAG,EAAE;gBACX,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC;oBAC3B,OAAM;gBACR,CAAC;gBACD,IAAI,OAAO,CAAC,IAAI,KAAK,CAAC,EAAE,CAAC;oBACvB,gBAAgB,EAAE,MAAM,EAAE,CAAA;oBAC1B,gBAAgB,GAAG,IAAI,CAAA;oBACvB,OAAO,GAAG,IAAI,CAAA;gBAChB,CAAC;YACH,CAAC;SACF,CAAA;IACH,CAAC,CAAA;IAED,OAAO;QACL,WAAW,EAAE,IAAa;QAC1B,sEAAsE;QACtE,2BAA2B;QAC3B,IAAI,YAAY;YACd,OAAO,OAAO,IAAI,OAAO,EAAE,CAAA;QAC7B,CAAC;QACD,gBAAgB;KACjB,CAAA;AACH,CAAC,CAAA","sourcesContent":["import type { SubscriptionHandle } from \"../contracts\"\nimport type { AppStateHost } from \"./host\"\n\n// Desktop windows are either focused or not: the RN \"inactive\" transitional\n// state has no GTK equivalent, so the surface is the active/background pair.\nexport type AppStateStatus = \"active\" | \"background\"\n\nexport type AppStateEvent = \"change\" | \"focus\" | \"blur\"\n\nexport type AppStateHandler = (state: AppStateStatus) => void\n\nconst EVENT_TYPES: readonly AppStateEvent[] = [\"change\", \"focus\", \"blur\"]\n\nexport const createAppState = (host: AppStateHost) => {\n type Entry = { type: AppStateEvent; handler: AppStateHandler }\n\n const entries = new Set<Entry>()\n let hostSubscription: SubscriptionHandle | null = null\n let tracked: AppStateStatus | null = null\n\n const compute = (): AppStateStatus =>\n host.isActive() ? \"active\" : \"background\"\n\n const onHostChange = (): void => {\n const next = compute()\n if (next === tracked) {\n return\n }\n tracked = next\n for (const entry of [...entries]) {\n if (\n entry.type === \"change\" ||\n (entry.type === \"focus\" && next === \"active\") ||\n (entry.type === \"blur\" && next === \"background\")\n ) {\n entry.handler(next)\n }\n }\n }\n\n const addEventListener = (\n type: AppStateEvent,\n handler: AppStateHandler,\n ): SubscriptionHandle => {\n if (!EVENT_TYPES.includes(type)) {\n throw new Error(\n `AppState.addEventListener: unsupported event type \"${String(type)}\"`,\n )\n }\n const entry: Entry = { type, handler }\n entries.add(entry)\n if (entries.size === 1) {\n tracked = compute()\n hostSubscription = host.onActiveChange(onHostChange)\n }\n return {\n remove: () => {\n if (!entries.delete(entry)) {\n return\n }\n if (entries.size === 0) {\n hostSubscription?.remove()\n hostSubscription = null\n tracked = null\n }\n },\n }\n }\n\n return {\n isAvailable: true as const,\n // Event-driven while at least one listener is attached, computed live\n // from the host otherwise.\n get currentState(): AppStateStatus {\n return tracked ?? compute()\n },\n addEventListener,\n }\n}\n\nexport type AppStateModule = ReturnType<typeof createAppState>\n"]}
@@ -0,0 +1,12 @@
1
+ import type { SubscriptionHandle } from "../contracts";
2
+ import type { AppearanceHost, ColorSchemeName } from "./host";
3
+ export type AppearancePreferences = {
4
+ colorScheme: ColorSchemeName;
5
+ };
6
+ export type AppearanceChangeHandler = (preferences: AppearancePreferences) => void;
7
+ export declare const createAppearance: (host: AppearanceHost) => {
8
+ getColorScheme: () => ColorSchemeName;
9
+ setColorScheme: (scheme: ColorSchemeName | null | undefined) => void;
10
+ addChangeListener: (handler: AppearanceChangeHandler) => SubscriptionHandle;
11
+ };
12
+ export type AppearanceModule = ReturnType<typeof createAppearance>;