@symbiote-native/engine 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (195) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +124 -0
  3. package/build/accessibility-info/index.android.d.ts +3 -0
  4. package/build/accessibility-info/index.android.js +166 -0
  5. package/build/accessibility-info/index.d.ts +1 -0
  6. package/build/accessibility-info/index.ios.d.ts +3 -0
  7. package/build/accessibility-info/index.ios.js +219 -0
  8. package/build/accessibility-info/index.js +5 -0
  9. package/build/accessibility-info/shared.d.ts +34 -0
  10. package/build/accessibility-info/shared.js +13 -0
  11. package/build/action-sheet-ios/index.d.ts +36 -0
  12. package/build/action-sheet-ios/index.js +74 -0
  13. package/build/alert/index.android.d.ts +5 -0
  14. package/build/alert/index.android.js +117 -0
  15. package/build/alert/index.d.ts +1 -0
  16. package/build/alert/index.ios.d.ts +7 -0
  17. package/build/alert/index.ios.js +83 -0
  18. package/build/alert/index.js +8 -0
  19. package/build/alert/shared.d.ts +19 -0
  20. package/build/alert/shared.js +17 -0
  21. package/build/animated/animated-component-shared.d.ts +5 -0
  22. package/build/animated/animated-component-shared.js +54 -0
  23. package/build/animated/animation.d.ts +9 -0
  24. package/build/animated/animation.js +6 -0
  25. package/build/animated/animations/base.d.ts +27 -0
  26. package/build/animated/animations/base.js +90 -0
  27. package/build/animated/animations/composition.d.ts +38 -0
  28. package/build/animated/animations/composition.js +236 -0
  29. package/build/animated/animations/decay.d.ts +22 -0
  30. package/build/animated/animations/decay.js +65 -0
  31. package/build/animated/animations/raf.d.ts +5 -0
  32. package/build/animated/animations/raf.js +39 -0
  33. package/build/animated/animations/spring-config.d.ts +6 -0
  34. package/build/animated/animations/spring-config.js +55 -0
  35. package/build/animated/animations/spring.d.ts +50 -0
  36. package/build/animated/animations/spring.js +207 -0
  37. package/build/animated/animations/timing.d.ts +27 -0
  38. package/build/animated/animations/timing.js +101 -0
  39. package/build/animated/animations/tracking.d.ts +14 -0
  40. package/build/animated/animations/tracking.js +43 -0
  41. package/build/animated/bezier.d.ts +1 -0
  42. package/build/animated/bezier.js +101 -0
  43. package/build/animated/color.d.ts +37 -0
  44. package/build/animated/color.js +183 -0
  45. package/build/animated/easing.d.ts +20 -0
  46. package/build/animated/easing.js +96 -0
  47. package/build/animated/event.d.ts +36 -0
  48. package/build/animated/event.js +252 -0
  49. package/build/animated/graph.d.ts +38 -0
  50. package/build/animated/graph.js +227 -0
  51. package/build/animated/index.d.ts +20 -0
  52. package/build/animated/index.js +28 -0
  53. package/build/animated/interpolation-node.d.ts +16 -0
  54. package/build/animated/interpolation-node.js +57 -0
  55. package/build/animated/interpolation.d.ts +22 -0
  56. package/build/animated/interpolation.js +199 -0
  57. package/build/animated/mock.d.ts +56 -0
  58. package/build/animated/mock.js +127 -0
  59. package/build/animated/native/native-animated.d.ts +43 -0
  60. package/build/animated/native/native-animated.js +146 -0
  61. package/build/animated/operators.d.ts +80 -0
  62. package/build/animated/operators.js +266 -0
  63. package/build/animated/props.d.ts +20 -0
  64. package/build/animated/props.js +187 -0
  65. package/build/animated/style.d.ts +26 -0
  66. package/build/animated/style.js +187 -0
  67. package/build/animated/value-xy.d.ts +35 -0
  68. package/build/animated/value-xy.js +106 -0
  69. package/build/animated/value.d.ts +36 -0
  70. package/build/animated/value.js +185 -0
  71. package/build/app-registry/index.d.ts +40 -0
  72. package/build/app-registry/index.js +144 -0
  73. package/build/app-state/index.d.ts +16 -0
  74. package/build/app-state/index.js +105 -0
  75. package/build/appearance/index.d.ts +12 -0
  76. package/build/appearance/index.js +84 -0
  77. package/build/back-handler/index.d.ts +14 -0
  78. package/build/back-handler/index.js +106 -0
  79. package/build/commit.d.ts +16 -0
  80. package/build/commit.js +678 -0
  81. package/build/debug.d.ts +5 -0
  82. package/build/debug.js +18 -0
  83. package/build/dimensions/index.d.ts +28 -0
  84. package/build/dimensions/index.js +148 -0
  85. package/build/dispatch.d.ts +2 -0
  86. package/build/dispatch.js +18 -0
  87. package/build/events/index.d.ts +1 -0
  88. package/build/events/index.js +691 -0
  89. package/build/fabric.d.ts +32 -0
  90. package/build/fabric.js +59 -0
  91. package/build/host-instance/index.d.ts +11 -0
  92. package/build/host-instance/index.js +49 -0
  93. package/build/i18n-manager/index.d.ts +13 -0
  94. package/build/i18n-manager/index.js +91 -0
  95. package/build/index.d.ts +80 -0
  96. package/build/index.js +72 -0
  97. package/build/interaction-manager/index.d.ts +45 -0
  98. package/build/interaction-manager/index.js +222 -0
  99. package/build/keyboard/index.d.ts +31 -0
  100. package/build/keyboard/index.js +142 -0
  101. package/build/layout-animation/index.d.ts +66 -0
  102. package/build/layout-animation/index.js +183 -0
  103. package/build/linking/index.android.d.ts +2 -0
  104. package/build/linking/index.android.js +18 -0
  105. package/build/linking/index.d.ts +1 -0
  106. package/build/linking/index.ios.d.ts +2 -0
  107. package/build/linking/index.ios.js +9 -0
  108. package/build/linking/index.js +6 -0
  109. package/build/linking/shared.d.ts +32 -0
  110. package/build/linking/shared.js +98 -0
  111. package/build/native-events.d.ts +24 -0
  112. package/build/native-events.js +129 -0
  113. package/build/native-modules.d.ts +6 -0
  114. package/build/native-modules.js +57 -0
  115. package/build/node.d.ts +36 -0
  116. package/build/node.js +194 -0
  117. package/build/pan-responder/index.d.ts +53 -0
  118. package/build/pan-responder/index.js +353 -0
  119. package/build/permissions-android/index.d.ts +115 -0
  120. package/build/permissions-android/index.js +185 -0
  121. package/build/pixel-ratio/index.d.ts +8 -0
  122. package/build/pixel-ratio/index.js +27 -0
  123. package/build/platform/index.android.d.ts +22 -0
  124. package/build/platform/index.android.js +60 -0
  125. package/build/platform/index.d.ts +1 -0
  126. package/build/platform/index.ios.d.ts +18 -0
  127. package/build/platform/index.ios.js +62 -0
  128. package/build/platform/index.js +5 -0
  129. package/build/platform/shared.d.ts +25 -0
  130. package/build/platform/shared.js +41 -0
  131. package/build/platform-color.d.ts +19 -0
  132. package/build/platform-color.js +25 -0
  133. package/build/post-commit.d.ts +4 -0
  134. package/build/post-commit.js +16 -0
  135. package/build/process-aspect-ratio.d.ts +1 -0
  136. package/build/process-aspect-ratio.js +34 -0
  137. package/build/process-background-image/index.d.ts +28 -0
  138. package/build/process-background-image/index.js +557 -0
  139. package/build/process-box-shadow/index.d.ts +11 -0
  140. package/build/process-box-shadow/index.js +193 -0
  141. package/build/process-filter.d.ts +31 -0
  142. package/build/process-filter.js +304 -0
  143. package/build/process-font-variant.d.ts +1 -0
  144. package/build/process-font-variant.js +17 -0
  145. package/build/process-transform/index.d.ts +5 -0
  146. package/build/process-transform/index.js +120 -0
  147. package/build/process-transform-origin/index.d.ts +3 -0
  148. package/build/process-transform-origin/index.js +108 -0
  149. package/build/registry.d.ts +31 -0
  150. package/build/registry.js +145 -0
  151. package/build/settings/index.d.ts +8 -0
  152. package/build/settings/index.js +126 -0
  153. package/build/share/index.android.d.ts +3 -0
  154. package/build/share/index.android.js +56 -0
  155. package/build/share/index.d.ts +1 -0
  156. package/build/share/index.ios.d.ts +3 -0
  157. package/build/share/index.ios.js +47 -0
  158. package/build/share/index.js +6 -0
  159. package/build/share/shared.d.ts +32 -0
  160. package/build/share/shared.js +32 -0
  161. package/build/status-bar/index.android.d.ts +5 -0
  162. package/build/status-bar/index.android.js +83 -0
  163. package/build/status-bar/index.d.ts +1 -0
  164. package/build/status-bar/index.ios.d.ts +5 -0
  165. package/build/status-bar/index.ios.js +66 -0
  166. package/build/status-bar/index.js +4 -0
  167. package/build/status-bar/shared.d.ts +22 -0
  168. package/build/status-bar/shared.js +22 -0
  169. package/build/style/index.d.ts +1 -0
  170. package/build/style/index.js +30 -0
  171. package/build/style-registry/index.d.ts +11 -0
  172. package/build/style-registry/index.js +165 -0
  173. package/build/style-sheet/index.d.ts +20 -0
  174. package/build/style-sheet/index.js +121 -0
  175. package/build/styles.d.ts +220 -0
  176. package/build/styles.js +7 -0
  177. package/build/surface.d.ts +16 -0
  178. package/build/surface.js +67 -0
  179. package/build/tags.d.ts +1 -0
  180. package/build/tags.js +10 -0
  181. package/build/text-input-state.d.ts +5 -0
  182. package/build/text-input-state.js +29 -0
  183. package/build/toast-android/index.d.ts +10 -0
  184. package/build/toast-android/index.js +108 -0
  185. package/build/vibration/index.android.d.ts +2 -0
  186. package/build/vibration/index.android.js +18 -0
  187. package/build/vibration/index.d.ts +1 -0
  188. package/build/vibration/index.ios.d.ts +2 -0
  189. package/build/vibration/index.ios.js +54 -0
  190. package/build/vibration/index.js +6 -0
  191. package/build/vibration/shared.d.ts +15 -0
  192. package/build/vibration/shared.js +68 -0
  193. package/build/view-config.d.ts +1 -0
  194. package/build/view-config.js +114 -0
  195. package/package.json +41 -0
@@ -0,0 +1,74 @@
1
+ // ActionSheetIOS: a JS->native imperative module, no Fabric view, no React. It
2
+ // drives the `ActionSheetManager` native module: `showActionSheetWithOptions`
3
+ // passes options straight through and the native `callback(buttonIndex)` reports
4
+ // the tapped row. We mirror RN faithfully.
5
+ //
6
+ // The native contract is confirmed from RN's TurboModule spec at
7
+ // .vendors/react-native/.../src/private/specs_DEPRECATED/modules/INativeActionSheetManager.js:
8
+ // showActionSheetWithOptions(options, callback: (buttonIndex: number) => void)
9
+ // showShareActionSheetWithOptions(options, failureCallback, successCallback)
10
+ // dismissActionSheet?()
11
+ //
12
+ // iOS only. Non-throwing, like StatusBar: a missing native module is a no-op,
13
+ // never a crash (on a device the module may be absent).
14
+ //
15
+ // Color note: RN runs `tintColor` / `cancelButtonTintColor` / `titleTextColor`
16
+ // through processColor before handing them to native. symbiote centralizes color
17
+ // processing in @symbiote-native/engine, so we do NOT process colors here; options pass
18
+ // through untouched. The canary needs no colors; revisit when wiring real colors.
19
+ import { dlog } from '../debug';
20
+ import { getNativeModule } from '../native-modules';
21
+ const ACTION_SHEET_MANAGER = 'ActionSheetManager';
22
+ // The static imperative API RN exposes, mirrored as a static-method object.
23
+ export const ActionSheetIOS = {
24
+ showActionSheetWithOptions(options, callback) {
25
+ dlog('ActionSheetIOS.showActionSheetWithOptions');
26
+ const manager = getNativeModule(ACTION_SHEET_MANAGER);
27
+ if (manager === null) {
28
+ dlog(`ActionSheetIOS: "${ACTION_SHEET_MANAGER}" unresolved — no-op`);
29
+ return;
30
+ }
31
+ // Normalize the single-index legacy form to the array RN's native side expects
32
+ // (RN ActionSheetIOS.js ~95-101): a `destructiveButtonIndex: number` becomes
33
+ // `destructiveButtonIndices: [number]`; an existing array passes through. Without
34
+ // this the destructive row isn't highlighted on a real iOS host. Colors are still
35
+ // not processed here (see file header).
36
+ const { destructiveButtonIndex, ...remainingOptions } = options;
37
+ let destructiveButtonIndices = options.destructiveButtonIndices;
38
+ if (Array.isArray(destructiveButtonIndex)) {
39
+ destructiveButtonIndices = destructiveButtonIndex;
40
+ }
41
+ else if (typeof destructiveButtonIndex === 'number') {
42
+ destructiveButtonIndices = [destructiveButtonIndex];
43
+ }
44
+ const nativeOptions = { ...remainingOptions, destructiveButtonIndices };
45
+ manager.showActionSheetWithOptions(nativeOptions, buttonIndex => {
46
+ dlog(`ActionSheetIOS callback buttonIndex=${buttonIndex}`);
47
+ callback(buttonIndex);
48
+ });
49
+ },
50
+ showShareActionSheetWithOptions(options, failureCallback, successCallback) {
51
+ dlog('ActionSheetIOS.showShareActionSheetWithOptions');
52
+ const manager = getNativeModule(ACTION_SHEET_MANAGER);
53
+ if (manager === null) {
54
+ dlog(`ActionSheetIOS: "${ACTION_SHEET_MANAGER}" unresolved — no-op`);
55
+ return;
56
+ }
57
+ manager.showShareActionSheetWithOptions(options, error => {
58
+ dlog('ActionSheetIOS share failure callback');
59
+ failureCallback(error);
60
+ }, (completed, activityType) => {
61
+ dlog(`ActionSheetIOS share success completed=${completed}`);
62
+ successCallback(completed, activityType);
63
+ });
64
+ },
65
+ dismissActionSheet() {
66
+ dlog('ActionSheetIOS.dismissActionSheet');
67
+ const manager = getNativeModule(ACTION_SHEET_MANAGER);
68
+ if (manager === null) {
69
+ dlog(`ActionSheetIOS: "${ACTION_SHEET_MANAGER}" unresolved — no-op`);
70
+ return;
71
+ }
72
+ manager.dismissActionSheet?.();
73
+ },
74
+ };
@@ -0,0 +1,5 @@
1
+ import { type IAlertStatic } from './shared';
2
+ export type { IAlertButton, IAlertButtonStyle, IAlertButtons, IAlertOptions, IAlertType, } from './shared';
3
+ export declare const Alert: IAlertStatic & {
4
+ prompt: () => void;
5
+ };
@@ -0,0 +1,117 @@
1
+ // Alert, Android build. The native module is `DialogManagerAndroid`
2
+ // (RN's TurboModuleRegistry.get('DialogManagerAndroid')): `showAlert(config, onError,
3
+ // onAction)` pops the native dialog, and `onAction(action, buttonKey)` reports the action
4
+ // plus the tapped button's key constant. At most three buttons map onto positive/negative/
5
+ // neutral, last-to-first as RN does. Everything platform-agnostic is the shared core.
6
+ // Metro picks this file on an Android host.
7
+ //
8
+ // The native contract is confirmed from RN's TurboModule spec:
9
+ // .vendors/.../specs_DEPRECATED/modules/INativeDialogManagerAndroid.js
10
+ // getConstants(): { buttonClicked, dismissed, buttonPositive, buttonNegative,
11
+ // buttonNeutral }
12
+ // showAlert(config, onError: (msg) => void, onAction: (action, buttonKey?) => void)
13
+ //
14
+ // device-verify-pending: the `DialogManagerAndroid` name and routing are confirmed from RN
15
+ // source but not yet exercised on a real Android host; only a bridgeless resolution log
16
+ // there can prove the name. See .docs/native-module-platform-routing.md.
17
+ //
18
+ // Non-throwing, like StatusBar: a missing native module is a no-op, never a crash.
19
+ import { dlog } from '../debug';
20
+ import { getNativeModule } from '../native-modules';
21
+ import { DEFAULT_POSITIVE_TEXT, normalizeButtons, } from './shared';
22
+ const DIALOG_MANAGER = 'DialogManagerAndroid';
23
+ // RN's hardwired Android fallbacks for the button-key constants (NativeDialogManager-
24
+ // Android documents buttonPositive=-1, buttonNegative=-2, buttonNeutral=-3, and the
25
+ // 'buttonClicked'/'dismissed' actions). Used when getConstants() omits a key.
26
+ const ANDROID_DIALOG_CONSTANTS = {
27
+ buttonClicked: 'buttonClicked',
28
+ dismissed: 'dismissed',
29
+ buttonPositive: -1,
30
+ buttonNegative: -2,
31
+ buttonNeutral: -3,
32
+ };
33
+ // The trust boundary for getConstants(): native sends an untyped HostObject. Read each key
34
+ // with a typeof guard and fall back to RN's documented default when it's missing.
35
+ function isRecord(value) {
36
+ return typeof value === 'object' && value !== null;
37
+ }
38
+ function readDialogConstants(raw) {
39
+ if (!isRecord(raw)) {
40
+ dlog('Alert: DialogManagerAndroid.getConstants() returned a non-object — using defaults');
41
+ return ANDROID_DIALOG_CONSTANTS;
42
+ }
43
+ const action = (key) => typeof raw[key] === 'string' ? raw[key] : ANDROID_DIALOG_CONSTANTS[key];
44
+ const buttonKey = (key) => typeof raw[key] === 'number' ? raw[key] : ANDROID_DIALOG_CONSTANTS[key];
45
+ return {
46
+ buttonClicked: action('buttonClicked'),
47
+ dismissed: action('dismissed'),
48
+ buttonPositive: buttonKey('buttonPositive'),
49
+ buttonNegative: buttonKey('buttonNegative'),
50
+ buttonNeutral: buttonKey('buttonNeutral'),
51
+ };
52
+ }
53
+ // The static imperative API RN exposes, mirrored as a static-method object. `prompt` has
54
+ // no Android counterpart in RN, so it is a dlog'd no-op here (documented below).
55
+ export const Alert = {
56
+ // The Android dialog path. RN keeps at most three buttons and maps them, last-to-first,
57
+ // onto positive/negative/neutral; onAction reads the native button-key constant back and
58
+ // fires that button's onPress. Non-throwing: no module -> no-op.
59
+ alert(title, message, buttons, options) {
60
+ dlog('Alert.alert (android)');
61
+ const manager = getNativeModule(DIALOG_MANAGER);
62
+ if (manager === null) {
63
+ dlog(`Alert.alert: "${DIALOG_MANAGER}" unresolved — no-op`);
64
+ return;
65
+ }
66
+ const constants = readDialogConstants(manager.getConstants());
67
+ const config = {
68
+ title: title || '',
69
+ message: message || '',
70
+ cancelable: options?.cancelable ?? false,
71
+ };
72
+ // At most three buttons (neutral, negative, positive). Ignore the rest. RN pops
73
+ // last-to-first, so the LAST button becomes positive and the FIRST neutral.
74
+ const validButtons = normalizeButtons(buttons).slice(0, 3);
75
+ const buttonPositive = validButtons.pop();
76
+ const buttonNegative = validButtons.pop();
77
+ const buttonNeutral = validButtons.pop();
78
+ if (buttonNeutral) {
79
+ config.buttonNeutral = buttonNeutral.text || '';
80
+ }
81
+ if (buttonNegative) {
82
+ config.buttonNegative = buttonNegative.text || '';
83
+ }
84
+ if (buttonPositive) {
85
+ config.buttonPositive = buttonPositive.text || DEFAULT_POSITIVE_TEXT;
86
+ }
87
+ // onAction maps the returned button-key constant back to the matching button's onPress;
88
+ // the dismiss action fires options.onDismiss.
89
+ const onAction = (action, buttonKey) => {
90
+ dlog(`Alert onAction action=${action} buttonKey=${String(buttonKey)}`);
91
+ if (action === constants.buttonClicked) {
92
+ if (buttonKey === constants.buttonNeutral) {
93
+ buttonNeutral?.onPress?.();
94
+ }
95
+ else if (buttonKey === constants.buttonNegative) {
96
+ buttonNegative?.onPress?.();
97
+ }
98
+ else if (buttonKey === constants.buttonPositive) {
99
+ buttonPositive?.onPress?.();
100
+ }
101
+ }
102
+ else if (action === constants.dismissed) {
103
+ options?.onDismiss?.();
104
+ }
105
+ };
106
+ const onError = (errorMessage) => {
107
+ dlog(`Alert onError: ${errorMessage}`);
108
+ };
109
+ manager.showAlert(config, onError, onAction);
110
+ },
111
+ // Android has no native `prompt` (RN's Alert.prompt is iOS-only; there is no
112
+ // DialogManagerAndroid equivalent). Keep the symbol so the surface matches, but no-op
113
+ // with a dlog rather than route to a single-input dialog.
114
+ prompt() {
115
+ dlog('Alert.prompt: no Android equivalent — no-op');
116
+ },
117
+ };
@@ -0,0 +1 @@
1
+ export * from './index.ios';
@@ -0,0 +1,7 @@
1
+ import type { IAlertButtons, IAlertOptions, IAlertStatic, IAlertType } from './shared';
2
+ export type { IAlertButton, IAlertButtonStyle, IAlertButtons, IAlertOptions, IAlertType, } from './shared';
3
+ type IPromptCallbackOrButtons = ((text: string) => void) | IAlertButtons;
4
+ declare function prompt(title?: string, message?: string, callbackOrButtons?: IPromptCallbackOrButtons, type?: IAlertType, defaultValue?: string, keyboardType?: string, options?: IAlertOptions): void;
5
+ export declare const Alert: IAlertStatic & {
6
+ prompt: typeof prompt;
7
+ };
@@ -0,0 +1,83 @@
1
+ // Alert: iOS build. The native module is `AlertManager`
2
+ // (RN's TurboModuleRegistry.get('AlertManager')); `alertWithArgs(args, callback)` pops the
3
+ // native alert, and the native `callback(id, value)` reports which button (by numeric id)
4
+ // the user tapped plus any text-input value. `alert` delegates to `prompt`, the same
5
+ // AlertManager path RN uses. Metro picks this file on an iOS host; the base alert.ts
6
+ // re-exports it for web/headless.
7
+ //
8
+ // The native contract is confirmed from RN's TurboModule spec:
9
+ // .vendors/.../specs_DEPRECATED/modules/INativeAlertManager.js
10
+ // alertWithArgs(args: Args, callback: (id: number, value: string) => void)
11
+ //
12
+ // Non-throwing, like StatusBar: a missing native module is a no-op, never a crash (on a
13
+ // device the module may be absent).
14
+ import { dlog } from '../debug';
15
+ import { getNativeModule } from '../native-modules';
16
+ const ALERT_MANAGER = 'AlertManager';
17
+ // prompt builds the native args, assigns each button its array index as id, and dispatches
18
+ // the matching button's onPress when the native callback returns that id. Non-throwing: no
19
+ // native module -> dlog + no-op.
20
+ function prompt(title, message, callbackOrButtons, type = 'plain-text', defaultValue, keyboardType, options) {
21
+ dlog('Alert.prompt');
22
+ // callbacks[id] is the onPress for the button at that index: the id->onPress map the
23
+ // native callback indexes into. The native always supplies a real string value, so the
24
+ // element accepts `string`; a button's `onPress` (`value?: string`) is contravariantly
25
+ // assignable to it.
26
+ let callbacks = [];
27
+ const buttons = [];
28
+ let cancelButtonKey;
29
+ let destructiveButtonKey;
30
+ let preferredButtonKey;
31
+ if (typeof callbackOrButtons === 'function') {
32
+ callbacks = [callbackOrButtons];
33
+ }
34
+ else if (Array.isArray(callbackOrButtons)) {
35
+ callbackOrButtons.forEach((btn, index) => {
36
+ callbacks[index] = btn.onPress;
37
+ if (btn.style === 'cancel') {
38
+ cancelButtonKey = String(index);
39
+ }
40
+ else if (btn.style === 'destructive') {
41
+ destructiveButtonKey = String(index);
42
+ }
43
+ if (btn.isPreferred) {
44
+ preferredButtonKey = String(index);
45
+ }
46
+ if (btn.text !== undefined || index < callbackOrButtons.length - 1) {
47
+ buttons.push({ [index]: btn.text ?? '' });
48
+ }
49
+ });
50
+ }
51
+ const manager = getNativeModule(ALERT_MANAGER);
52
+ if (manager === null) {
53
+ dlog(`Alert.prompt: "${ALERT_MANAGER}" unresolved — no-op`);
54
+ return;
55
+ }
56
+ manager.alertWithArgs({
57
+ title: title ?? '',
58
+ message: message || undefined,
59
+ buttons,
60
+ type: type || undefined,
61
+ defaultValue,
62
+ cancelButtonKey,
63
+ destructiveButtonKey,
64
+ preferredButtonKey,
65
+ keyboardType,
66
+ userInterfaceStyle: options?.userInterfaceStyle || undefined,
67
+ },
68
+ // The native callback crossing back: `id` is the tapped button's index, `value` the
69
+ // text-input contents. Index into callbacks and fire onPress.
70
+ (id, value) => {
71
+ dlog(`Alert callback id=${id}`);
72
+ callbacks[id]?.(value);
73
+ });
74
+ }
75
+ // The static imperative API RN exposes, mirrored as a static-method object. `prompt` is
76
+ // iOS-only, so it lives beyond IAlertStatic on this build.
77
+ export const Alert = {
78
+ // alert delegates to prompt (same AlertManager path), exactly as RN does on iOS.
79
+ alert(title, message, buttons, options) {
80
+ prompt(title, message, buttons, 'default', undefined, undefined, options);
81
+ },
82
+ prompt,
83
+ };
@@ -0,0 +1,8 @@
1
+ // Alert: base / default build (web, headless tsx, any target without a dedicated platform
2
+ // file). Metro overrides this with alert.ios.ts / alert.android.ts on a real iOS/Android
3
+ // host; off those, the iOS build is the fallback (its AlertManager resolves null elsewhere
4
+ // → graceful no-op). The barrel imports './alert', which resolves here under tsc/tsx and to
5
+ // the platform file under Metro. The `export *` re-exports the public type names
6
+ // (AlertType, AlertButtonStyle, AlertButton, AlertButtons, AlertOptions) so the barrel's
7
+ // `export type { ... } from '../alert'` still resolves. See ADR 0019.
8
+ export * from './index.ios';
@@ -0,0 +1,19 @@
1
+ export type IAlertType = 'default' | 'plain-text' | 'secure-text' | 'login-password';
2
+ export type IAlertButtonStyle = 'default' | 'cancel' | 'destructive';
3
+ export interface IAlertButton {
4
+ text?: string;
5
+ onPress?: (value?: string) => void;
6
+ isPreferred?: boolean;
7
+ style?: IAlertButtonStyle;
8
+ }
9
+ export type IAlertButtons = IAlertButton[];
10
+ export interface IAlertOptions {
11
+ cancelable?: boolean;
12
+ userInterfaceStyle?: 'unspecified' | 'light' | 'dark';
13
+ onDismiss?: () => void;
14
+ }
15
+ export interface IAlertStatic {
16
+ alert(title?: string, message?: string, buttons?: IAlertButtons, options?: IAlertOptions): void;
17
+ }
18
+ export declare const DEFAULT_POSITIVE_TEXT = "OK";
19
+ export declare function normalizeButtons(buttons?: IAlertButtons): IAlertButtons;
@@ -0,0 +1,17 @@
1
+ // Shared core of the Alert module, everything that does NOT differ by platform: the
2
+ // public contract (the type union, button shapes, IAlertStatic), the Android button-key
3
+ // constant defaults, and the button-normalization helper. The per-platform files
4
+ // (alert.ios.ts / alert.android.ts) implement `alert()` fully against their own native
5
+ // module (iOS keeps `prompt` too); the two native call shapes are too divergent to share
6
+ // a factory. No native, no `Platform.OS` read here. See ADR 0019.
7
+ // The default positive label RN uses when a button carries no text.
8
+ export const DEFAULT_POSITIVE_TEXT = 'OK';
9
+ // Normalize the `buttons` arg into a consistent list: undefined/empty becomes a single
10
+ // default "OK" button, exactly as RN does before handing the list to native. Both
11
+ // platform files start from this so the no-buttons case behaves identically.
12
+ export function normalizeButtons(buttons) {
13
+ if (buttons === undefined || buttons.length === 0) {
14
+ return [{ text: DEFAULT_POSITIVE_TEXT }];
15
+ }
16
+ return buttons;
17
+ }
@@ -0,0 +1,5 @@
1
+ import { AnimatedNode } from './graph';
2
+ export declare function isAnimatedNode(value: unknown): value is AnimatedNode;
3
+ export declare function readPassthroughStyle(passthrough: unknown): unknown;
4
+ export declare function reduceProps(props: Record<string, unknown>): Record<string, unknown>;
5
+ export declare function resolveHostNode(instance: unknown): unknown;
@@ -0,0 +1,54 @@
1
+ // Framework-agnostic helpers for createAnimatedComponent. Both the React and Vue
2
+ // adapters wrap a base component so it accepts AnimatedNodes in its props; the wrap
3
+ // mechanism (capture the host node, build an AnimatedProps leaf, reduce animated
4
+ // props to their current values, override with the passthrough style) is pure JS,
5
+ // identical across frameworks. Only `assignRef` is framework-ref-specific and stays
6
+ // per-adapter; everything here is shared. Extracted from the React wrapper (ADR
7
+ // 0016/0017) so a new adapter reuses it verbatim.
8
+ import { AnimatedNode } from './graph';
9
+ import { AnimatedStyle } from './style';
10
+ export function isAnimatedNode(value) {
11
+ return value instanceof AnimatedNode;
12
+ }
13
+ // RN's `passthroughAnimatedPropExplicitValues` carries explicit (already-rasterized) prop
14
+ // values (e.g. a sticky header's debounced `{style:{transform:[{translateY}]}}`) that must
15
+ // override the animated prop in the COMMITTED props so the Fabric ShadowTree (hit-testing)
16
+ // stays current while the native driver animates. Read its `style` without a cast.
17
+ export function readPassthroughStyle(passthrough) {
18
+ if (typeof passthrough !== 'object' || passthrough === null)
19
+ return undefined;
20
+ return Reflect.get(passthrough, 'style');
21
+ }
22
+ // Replace animated entries in a props map with their current rasterized values so the
23
+ // first paint (and every re-render) carries concrete props. `style` is run through
24
+ // AnimatedStyle so an animated style key resolves to its current number.
25
+ export function reduceProps(props) {
26
+ const out = {};
27
+ for (const key of Object.keys(props)) {
28
+ const value = props[key];
29
+ if (key === 'style') {
30
+ const styleNode = AnimatedStyle.from(value);
31
+ out[key] = styleNode !== undefined ? styleNode.__getValue() : value;
32
+ }
33
+ else if (isAnimatedNode(value)) {
34
+ out[key] = value.__getValue();
35
+ }
36
+ else {
37
+ out[key] = value;
38
+ }
39
+ }
40
+ return out;
41
+ }
42
+ // A ScrollView / FlatList / SectionList ref captures an imperative handle (RN's
43
+ // getScrollableNode pattern), NOT the raw host node, so a native event or animated
44
+ // props have nothing to bind to. Unwrap it via getScrollNode() to the underlying
45
+ // SymbioteNode; View / Text / Image already hand back the node directly, so they fall
46
+ // through unchanged.
47
+ export function resolveHostNode(instance) {
48
+ if (instance !== null && typeof instance === 'object') {
49
+ const getScrollNode = Reflect.get(instance, 'getScrollNode');
50
+ if (typeof getScrollNode === 'function')
51
+ return getScrollNode.call(instance);
52
+ }
53
+ return instance;
54
+ }
@@ -0,0 +1,9 @@
1
+ import type { AnimatedValue } from './value';
2
+ export interface IEndResult {
3
+ finished: boolean;
4
+ }
5
+ export type IEndCallback = (result: IEndResult) => void;
6
+ export interface IAnimation {
7
+ start(fromValue: number, onUpdate: (value: number) => void, onEnd: IEndCallback, previousAnimation: IAnimation | null, animatedValue: AnimatedValue): void;
8
+ stop(): void;
9
+ }
@@ -0,0 +1,6 @@
1
+ // The driver contract. A concrete animation (timing / spring / decay, all
2
+ // Phase 2) is a number -> number machine: `start` is handed the value's current
3
+ // number and an `onUpdate` it calls each frame with the next number; `onEnd`
4
+ // fires exactly once. This interface is the seam between AnimatedValue and the
5
+ // drivers, so it lives here, free of any concrete driver.
6
+ export {};
@@ -0,0 +1,27 @@
1
+ import type { IAnimation, IEndCallback, IEndResult } from '../animation';
2
+ import type { AnimatedValue } from '../value';
3
+ import { type INativeAnimationConfig, type IPlatformConfig } from '../native/native-animated';
4
+ export interface IAnimationConfig {
5
+ isInteraction?: boolean;
6
+ iterations?: number;
7
+ useNativeDriver?: boolean;
8
+ platformConfig?: IPlatformConfig;
9
+ debugID?: string;
10
+ }
11
+ export declare abstract class BaseAnimation implements IAnimation {
12
+ protected __active: boolean;
13
+ protected __iterations: number;
14
+ protected readonly __platformConfig: IPlatformConfig | undefined;
15
+ private readonly __debugID;
16
+ private onEndCallback;
17
+ private readonly nativeDriverRequested;
18
+ private nativeId;
19
+ constructor(config: IAnimationConfig);
20
+ protected __getDebugID(): string | undefined;
21
+ abstract start(fromValue: number, onUpdate: (value: number) => void, onEnd: IEndCallback, previousAnimation: IAnimation | null, animatedValue: AnimatedValue): void;
22
+ protected begin(onEnd: IEndCallback): void;
23
+ protected getNativeAnimationConfig(): INativeAnimationConfig;
24
+ protected startNativeIfNeeded(animatedValue: AnimatedValue): boolean;
25
+ stop(): void;
26
+ protected __notifyAnimationEnd(result: IEndResult): void;
27
+ }
@@ -0,0 +1,90 @@
1
+ // Minimal driver base, ported from RN's animations/Animation.js with every
2
+ // native path removed (ADR 0016): no NativeAnimatedHelper, no
3
+ // __startAnimationIfNative, no shouldUseNativeDriver, no FeatureFlags. What
4
+ // remains is the JS-only contract: hold the end callback, track whether the
5
+ // animation is still active, and fire onEnd at most once.
6
+ //
7
+ // start() / stop() are abstract: each concrete driver (timing / spring / decay)
8
+ // owns its own requestAnimationFrame loop. They are declared as methods (not
9
+ // class fields) so a subclass override is not shadowed under
10
+ // useDefineForClassFields.
11
+ import { flushValue } from '../graph';
12
+ import { dlog, isDebug } from '../../debug';
13
+ import { generateNativeAnimationId, isNativeAnimatedAvailable, nativeAnimated, } from '../native/native-animated';
14
+ export class BaseAnimation {
15
+ // `protected` so subclasses read it inside their rAF loop to decide whether to
16
+ // schedule the next frame; cleared by stop().
17
+ __active = false;
18
+ __iterations;
19
+ // RN's Animation holds `_platformConfig` / `__debugID` and folds them into the
20
+ // native config (Animation.js:60-62). Subclasses read them via the protected
21
+ // accessors below so every driver's config carries them uniformly.
22
+ __platformConfig;
23
+ __debugID;
24
+ onEndCallback = null;
25
+ nativeDriverRequested;
26
+ nativeId;
27
+ constructor(config) {
28
+ this.__iterations = config.iterations ?? 1;
29
+ this.nativeDriverRequested = config.useNativeDriver === true;
30
+ this.__platformConfig = config.platformConfig;
31
+ this.__debugID = config.debugID;
32
+ }
33
+ // Mirrors RN's Animation.__getDebugID (Animation.js:192). Returns the label only
34
+ // under DEBUG so production native configs stay lean, undefined otherwise.
35
+ __getDebugID() {
36
+ return isDebug() ? this.__debugID : undefined;
37
+ }
38
+ // Subclasses call super.start(...) shape via this helper to wire the end
39
+ // callback and arm the active flag before launching their loop.
40
+ begin(onEnd) {
41
+ this.onEndCallback = onEnd;
42
+ this.__active = true;
43
+ }
44
+ // A native driver overrides this with its curve config (`{type:'frames'|'spring'|'decay', …}`).
45
+ getNativeAnimationConfig() {
46
+ throw new Error('This animation type cannot be offloaded to the native driver');
47
+ }
48
+ // If useNativeDriver was requested and the module is present, mirror the value
49
+ // graph into native and hand the curve to native. The JS rAF loop is then
50
+ // skipped entirely. Returns true when native took over. Falls back to JS (false)
51
+ // when the module is missing (ADR 0016 path), so an app without RCTAnimation
52
+ // still animates.
53
+ startNativeIfNeeded(animatedValue) {
54
+ if (!this.nativeDriverRequested)
55
+ return false;
56
+ if (!isNativeAnimatedAvailable()) {
57
+ dlog('useNativeDriver requested but native animated module is missing; using JS driver');
58
+ return false;
59
+ }
60
+ const config = this.getNativeAnimationConfig();
61
+ // RN hands the curve's platform bag down to the value node (Animation.js:137)
62
+ // so the node's create config carries it too.
63
+ animatedValue.__makeNative(this.__platformConfig);
64
+ this.nativeId = generateNativeAnimationId();
65
+ nativeAnimated.startAnimatingNode(this.nativeId, animatedValue.__getNativeTag(), config, result => {
66
+ this.__notifyAnimationEnd({ finished: result.finished });
67
+ // Sync the JS value to native's final value, then run leaf callbacks once.
68
+ if (result.value !== undefined) {
69
+ animatedValue.__onNativeUpdate(result.value, result.offset);
70
+ flushValue(animatedValue);
71
+ }
72
+ });
73
+ return true;
74
+ }
75
+ stop() {
76
+ if (this.nativeId !== undefined) {
77
+ nativeAnimated.stopAnimation(this.nativeId);
78
+ }
79
+ this.__active = false;
80
+ }
81
+ // Fire the completion callback at most once. start() and stop() each run at
82
+ // most once over an animation's life, and so does this.
83
+ __notifyAnimationEnd(result) {
84
+ const callback = this.onEndCallback;
85
+ if (callback !== null) {
86
+ this.onEndCallback = null;
87
+ callback(result);
88
+ }
89
+ }
90
+ }
@@ -0,0 +1,38 @@
1
+ import type { IEndCallback } from '../animation';
2
+ import { AnimatedNode } from '../graph';
3
+ import { AnimatedValue } from '../value';
4
+ import { type ITimingAnimationConfig } from './timing';
5
+ import { type ISpringAnimationConfig } from './spring';
6
+ import { type IDecayAnimationConfig } from './decay';
7
+ export interface ICompositeAnimation {
8
+ start(callback?: IEndCallback, isLooping?: boolean): void;
9
+ stop(): void;
10
+ reset(): void;
11
+ _nativeLoop?(iterations: number, callback?: IEndCallback): boolean;
12
+ }
13
+ interface IWithOnComplete {
14
+ onComplete?: IEndCallback;
15
+ }
16
+ export type ITimingConfig = Omit<ITimingAnimationConfig, 'toValue'> & {
17
+ toValue: number | AnimatedNode;
18
+ } & IWithOnComplete;
19
+ export type ISpringConfig = Omit<ISpringAnimationConfig, 'toValue'> & {
20
+ toValue: number | AnimatedNode;
21
+ } & IWithOnComplete;
22
+ export type IDecayConfig = IDecayAnimationConfig & IWithOnComplete;
23
+ export declare function timing(value: AnimatedValue, config: ITimingConfig): ICompositeAnimation;
24
+ export declare function spring(value: AnimatedValue, config: ISpringConfig): ICompositeAnimation;
25
+ export declare function decay(value: AnimatedValue, config: IDecayConfig): ICompositeAnimation;
26
+ export interface IParallelConfig {
27
+ stopTogether?: boolean;
28
+ }
29
+ export declare function parallel(animations: ICompositeAnimation[], config?: IParallelConfig): ICompositeAnimation;
30
+ export declare function sequence(animations: ICompositeAnimation[]): ICompositeAnimation;
31
+ export declare function delay(time: number): ICompositeAnimation;
32
+ export declare function stagger(time: number, animations: ICompositeAnimation[]): ICompositeAnimation;
33
+ export interface ILoopAnimationConfig {
34
+ iterations?: number;
35
+ resetBeforeIteration?: boolean;
36
+ }
37
+ export declare function loop(animation: ICompositeAnimation, config?: ILoopAnimationConfig): ICompositeAnimation;
38
+ export {};