@symbiote-native/react 0.2.7 → 0.3.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.
- package/build/bootstrap.js +4 -5
- package/build/components/activity-indicator/index.android.d.ts +2 -1
- package/build/components/activity-indicator/index.android.js +14 -10
- package/build/components/activity-indicator/index.ios.d.ts +2 -1
- package/build/components/activity-indicator/index.ios.js +9 -3
- package/build/components/activity-indicator/shared.d.ts +1 -2
- package/build/components/activity-indicator/shared.js +13 -11
- package/build/components/keyboard-avoiding-view/index.js +1 -1
- package/build/components/modal/index.d.ts +3 -2
- package/build/components/scroll-view/index.android.js +0 -2
- package/build/components/scroll-view/index.ios.js +10 -10
- package/build/components/scroll-view/shared.js +28 -32
- package/build/components/scroll-view/sticky-header.js +98 -74
- package/build/components/section-list/index.js +4 -6
- package/build/components/switch/index.android.d.ts +2 -1
- package/build/components/switch/index.android.js +9 -3
- package/build/components/switch/index.ios.d.ts +2 -1
- package/build/components/switch/index.ios.js +9 -3
- package/build/components/switch/shared.d.ts +2 -3
- package/build/components/switch/shared.js +44 -43
- package/build/components/text-input/index.js +1 -1
- package/build/components/touchable/index.js +22 -54
- package/build/components/virtualized-list/index.js +219 -305
- package/build/components/virtualized-section-list/index.js +2 -4
- package/build/create-tunnel/index.js +14 -20
- package/build/hooks/use-color-scheme.d.ts +1 -1
- package/build/hooks/use-color-scheme.js +1 -1
- package/build/hooks/use-window-dimensions.d.ts +1 -1
- package/build/hooks/use-window-dimensions.js +1 -1
- package/build/host-instance.js +5 -6
- package/build/index.d.ts +6 -31
- package/build/index.js +15 -25
- package/build/modules/animated/create-animated-component.js +24 -65
- package/build/render.js +28 -2
- package/metro-css-parser.cjs +7 -12
- package/package.json +4 -4
- package/build/modules/action-sheet-ios.d.ts +0 -2
- package/build/modules/action-sheet-ios.js +0 -4
- package/build/modules/alert.d.ts +0 -2
- package/build/modules/alert.js +0 -5
- package/build/modules/app-state.d.ts +0 -2
- package/build/modules/app-state.js +0 -3
- package/build/modules/appearance.d.ts +0 -2
- package/build/modules/appearance.js +0 -3
- package/build/modules/back-handler.d.ts +0 -2
- package/build/modules/back-handler.js +0 -3
- package/build/modules/dimensions.d.ts +0 -2
- package/build/modules/dimensions.js +0 -3
- package/build/modules/i18n-manager.d.ts +0 -2
- package/build/modules/i18n-manager.js +0 -4
- package/build/modules/keyboard.d.ts +0 -2
- package/build/modules/keyboard.js +0 -3
- package/build/modules/layout-animation.d.ts +0 -2
- package/build/modules/layout-animation.js +0 -3
- package/build/modules/linking.d.ts +0 -2
- package/build/modules/linking.js +0 -4
- package/build/modules/permissions-android.d.ts +0 -2
- package/build/modules/permissions-android.js +0 -3
- package/build/modules/settings.d.ts +0 -1
- package/build/modules/settings.js +0 -4
- package/build/modules/share.d.ts +0 -2
- package/build/modules/share.js +0 -4
- package/build/modules/text-input-state.d.ts +0 -1
- package/build/modules/text-input-state.js +0 -3
- package/build/modules/toast-android.d.ts +0 -1
- package/build/modules/toast-android.js +0 -4
- package/build/modules/vibration.d.ts +0 -1
- package/build/modules/vibration.js +0 -4
|
@@ -9,51 +9,52 @@
|
|
|
9
9
|
// JS commands the old value back down (a plain prop re-push cannot cover the no-op case: the
|
|
10
10
|
// prop never changes, so the retained tree never diverges). The command name is platform-
|
|
11
11
|
// specific (iOS setValue / Android setNativeValue) and arrives via `platform`.
|
|
12
|
+
//
|
|
13
|
+
// useSwitchLogic is a plain hook, not a component factory returning a closure: React Compiler's
|
|
14
|
+
// component/hook detection only walks top-level declarations, so index.ios.ts / index.android.ts
|
|
15
|
+
// each declare their OWN top-level `Switch` function that calls this hook, rather than exporting
|
|
16
|
+
// whatever a factory here returns.
|
|
12
17
|
import { useCallback, useLayoutEffect, useReducer, useRef } from 'react';
|
|
13
18
|
import { renderSwitch, switchReducer, createInitialSwitchState, shouldSnapBack, valueFromChange, } from '@symbiote-native/components';
|
|
14
19
|
import { dispatchViewCommand, dlog, } from '@symbiote-native/engine';
|
|
15
20
|
import { resolveAccessibilityProps } from '@symbiote-native/components';
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
const
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
const
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
passthrough: { ...passthrough, ref, onChange: handleChange },
|
|
56
|
-
}, platform);
|
|
57
|
-
return descriptorToReact(descriptor);
|
|
58
|
-
};
|
|
21
|
+
export function useSwitchLogic(rawProps, platform) {
|
|
22
|
+
// Switch owns its host element rather than rendering through a symbiote View, so it folds
|
|
23
|
+
// aria/role into accessibility* here; the resolved accessibility* fields (plus testID etc.)
|
|
24
|
+
// ride down to the host node via `passthrough`.
|
|
25
|
+
const props = resolveAccessibilityProps(rawProps);
|
|
26
|
+
const { value, onValueChange, disabled, trackColor, thumbColor, ios_backgroundColor, style, ...passthrough } = props;
|
|
27
|
+
const ref = useRef(null);
|
|
28
|
+
const [state, dispatch] = useReducer(switchReducer, undefined, createInitialSwitchState);
|
|
29
|
+
const handleChange = useCallback((event) => {
|
|
30
|
+
const next = valueFromChange(event);
|
|
31
|
+
dlog(`Switch onChange value=${String(next)} eventCount=${String(event.nativeEvent.eventCount)}`);
|
|
32
|
+
if (next === undefined)
|
|
33
|
+
return;
|
|
34
|
+
onValueChange?.(next, event);
|
|
35
|
+
dispatch({ type: 'native-reported', value: next });
|
|
36
|
+
}, [onValueChange]);
|
|
37
|
+
// value is a real Fabric prop, folded to a strict boolean: RN sends `value === true`, so
|
|
38
|
+
// an undefined prop reads as "off" rather than absent.
|
|
39
|
+
const fabricValue = value === true;
|
|
40
|
+
useLayoutEffect(() => {
|
|
41
|
+
const node = ref.current;
|
|
42
|
+
if (node === null)
|
|
43
|
+
return;
|
|
44
|
+
if (!shouldSnapBack(state, fabricValue)) {
|
|
45
|
+
dlog(`Switch snap-back no-op reported=${String(state.lastNativeReport)} value=${fabricValue}`);
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
dlog(`Switch ${platform.snapBackCommand} snap-back reported=${String(state.lastNativeReport)} value=${fabricValue}`);
|
|
49
|
+
dispatchViewCommand(node, platform.snapBackCommand, [fabricValue]);
|
|
50
|
+
}, [fabricValue, state]);
|
|
51
|
+
return renderSwitch({
|
|
52
|
+
value: fabricValue,
|
|
53
|
+
disabled,
|
|
54
|
+
trackColor,
|
|
55
|
+
thumbColor,
|
|
56
|
+
ios_backgroundColor,
|
|
57
|
+
style,
|
|
58
|
+
passthrough: { ...passthrough, ref, onChange: handleChange },
|
|
59
|
+
}, platform);
|
|
59
60
|
}
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
// (setTextAndSelection), never a plain prop re-push. See @symbiote-native/components/state/text-input.
|
|
11
11
|
import { forwardRef, useCallback, useEffect, useImperativeHandle, useLayoutEffect, useRef, useState, } from 'react';
|
|
12
12
|
import { dispatchViewCommand, dlog, } from '@symbiote-native/engine';
|
|
13
|
-
import { blurTextInput, setInputBlurred, setInputFocused } from '
|
|
13
|
+
import { blurTextInput, setInputBlurred, setInputFocused } from '@symbiote-native/engine';
|
|
14
14
|
import { resolveAccessibilityProps, resolveTextInputProps, renderTextInput, foldText, textFromChange, eventCountFromChange, shouldCommandText, INITIAL_EVENT_COUNT, SELECTION_NONE, } from '@symbiote-native/components';
|
|
15
15
|
import { descriptorToReact } from '../../descriptor-to-react/index.js';
|
|
16
16
|
export const TextInput = forwardRef((rawProps, forwardedRef) => {
|
|
@@ -8,10 +8,15 @@
|
|
|
8
8
|
// pressed-state style (RN drives this with setState, not Animated, faithfully).
|
|
9
9
|
// TouchableWithoutFeedback: no visual change, just the press wiring.
|
|
10
10
|
import { createElement, useRef } from 'react';
|
|
11
|
-
import {
|
|
12
|
-
import { computePressOutWait, DEFAULT_ACTIVE_OPACITY, DEFAULT_HIGHLIGHT_CHILD_OPACITY, DEFAULT_MIN_PRESS_DURATION_MS, DEFAULT_UNDERLAY_COLOR, OPACITY_ACTIVE_DURATION_MS, OPACITY_INACTIVE_DURATION_MS, RESTING_OPACITY, } from '@symbiote-native/components';
|
|
11
|
+
import { createTouchableFeedbackHandlers, createTouchableFeedbackRuntime, highlightPressedStyle, DEFAULT_ACTIVE_OPACITY, DEFAULT_HIGHLIGHT_CHILD_OPACITY, DEFAULT_MIN_PRESS_DURATION_MS, DEFAULT_UNDERLAY_COLOR, OPACITY_ACTIVE_DURATION_MS, OPACITY_INACTIVE_DURATION_MS, RESTING_OPACITY, } from '@symbiote-native/components';
|
|
13
12
|
import { Pressable } from '../pressable/index.js';
|
|
14
13
|
import { Animated } from '../../modules/animated/index.js';
|
|
14
|
+
// The real setTimeout the shared feedback machine schedules its deferred activation/deactivation on
|
|
15
|
+
// (core/components has no timer globals). Returns a canceller so an early release flushes the timer.
|
|
16
|
+
function scheduleTimeout(callback, ms) {
|
|
17
|
+
const id = setTimeout(callback, ms);
|
|
18
|
+
return () => clearTimeout(id);
|
|
19
|
+
}
|
|
15
20
|
export const TouchableOpacity = props => {
|
|
16
21
|
const { activeOpacity = DEFAULT_ACTIVE_OPACITY, style,
|
|
17
22
|
// className is pulled out here, like style, and applied to the inner Animated.View below —
|
|
@@ -21,10 +26,8 @@ export const TouchableOpacity = props => {
|
|
|
21
26
|
// One Animated.Value per mount, resting at full opacity. The Animated.View leaf commits its
|
|
22
27
|
// current value every frame, so timing it animates the real view.
|
|
23
28
|
const opacity = useRef(new Animated.Value(RESTING_OPACITY)).current;
|
|
24
|
-
// The
|
|
25
|
-
const
|
|
26
|
-
// When the active visual actually started, to floor onPressOut by minPressDuration.
|
|
27
|
-
const activatedAt = useRef(undefined);
|
|
29
|
+
// The shared press-scheduling cell (delayPressIn timer + activation clock), held across renders.
|
|
30
|
+
const runtime = useRef(createTouchableFeedbackRuntime()).current;
|
|
28
31
|
function setOpacityTo(toValue, duration) {
|
|
29
32
|
Animated.timing(opacity, {
|
|
30
33
|
toValue,
|
|
@@ -33,59 +36,24 @@ export const TouchableOpacity = props => {
|
|
|
33
36
|
useNativeDriver: false,
|
|
34
37
|
}).start();
|
|
35
38
|
}
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
activatedAt.current = undefined;
|
|
49
|
-
setOpacityTo(RESTING_OPACITY, OPACITY_INACTIVE_DURATION_MS);
|
|
50
|
-
onPressOut?.(event);
|
|
51
|
-
}
|
|
52
|
-
// RN's _createPressabilityConfig forwards delayPressIn: defer the active visual and onPressIn
|
|
53
|
-
// behind the delay (a release before it elapses flushes it synchronously).
|
|
54
|
-
function handlePressIn(event) {
|
|
55
|
-
if (delayPressIn > 0) {
|
|
56
|
-
dlog(`TouchableOpacity pressIn deferred ${delayPressIn}ms`);
|
|
57
|
-
pressInTimer.current = setTimeout(() => {
|
|
58
|
-
pressInTimer.current = undefined;
|
|
59
|
-
activate(event);
|
|
60
|
-
}, delayPressIn);
|
|
61
|
-
return;
|
|
62
|
-
}
|
|
63
|
-
activate(event);
|
|
64
|
-
}
|
|
65
|
-
// delayPressOut + minPressDuration (RN _deactivate): the press-out waits at least minPress-
|
|
66
|
-
// Duration past activation (so a fast tap holds the active visual) and at least delayPressOut.
|
|
67
|
-
function handlePressOut(event) {
|
|
68
|
-
if (pressInTimer.current !== undefined) {
|
|
69
|
-
clearPressInTimer();
|
|
70
|
-
activate(event);
|
|
71
|
-
}
|
|
72
|
-
const heldFor = activatedAt.current === undefined ? 0 : Date.now() - activatedAt.current;
|
|
73
|
-
const wait = computePressOutWait(heldFor, minPressDuration, delayPressOut);
|
|
74
|
-
if (wait > 0) {
|
|
75
|
-
dlog(`TouchableOpacity pressOut deferred ${wait}ms`);
|
|
76
|
-
setTimeout(() => deactivate(event), wait);
|
|
77
|
-
return;
|
|
78
|
-
}
|
|
79
|
-
deactivate(event);
|
|
80
|
-
}
|
|
39
|
+
// The shared machine owns the delayPressIn/minPressDuration scheduling; the adapter supplies only
|
|
40
|
+
// the native seam — the Animated opacity fade + the framework emit — as activate/deactivate.
|
|
41
|
+
const { handlePressIn, handlePressOut } = createTouchableFeedbackHandlers({ delayPressIn, delayPressOut, minPressDuration, schedule: scheduleTimeout, now: Date.now }, runtime, {
|
|
42
|
+
activate(event) {
|
|
43
|
+
setOpacityTo(activeOpacity, OPACITY_ACTIVE_DURATION_MS);
|
|
44
|
+
onPressIn?.(event);
|
|
45
|
+
},
|
|
46
|
+
deactivate(event) {
|
|
47
|
+
setOpacityTo(RESTING_OPACITY, OPACITY_INACTIVE_DURATION_MS);
|
|
48
|
+
onPressOut?.(event);
|
|
49
|
+
},
|
|
50
|
+
});
|
|
81
51
|
return createElement(Pressable, { ...rest, onPressIn: handlePressIn, onPressOut: handlePressOut }, createElement(Animated.View, { style: [style, { opacity }], className }, children));
|
|
82
52
|
};
|
|
83
53
|
export const TouchableHighlight = props => {
|
|
84
54
|
const { activeOpacity = DEFAULT_HIGHLIGHT_CHILD_OPACITY, underlayColor = DEFAULT_UNDERLAY_COLOR, style, children, ...rest } = props;
|
|
85
55
|
function pressedStyle({ pressed }) {
|
|
86
|
-
|
|
87
|
-
return style;
|
|
88
|
-
return [style, { backgroundColor: underlayColor, opacity: activeOpacity }];
|
|
56
|
+
return highlightPressedStyle(pressed, style, underlayColor, activeOpacity);
|
|
89
57
|
}
|
|
90
58
|
return createElement(Pressable, { ...rest, style: pressedStyle }, children);
|
|
91
59
|
};
|