@symbiote-native/react 0.2.7 → 0.2.8

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.
@@ -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 { dlog } from '@symbiote-native/engine';
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 pending delayPressIn timer, so a release before it fires can flush it.
25
- const pressInTimer = useRef(undefined);
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
- function clearPressInTimer() {
37
- if (pressInTimer.current !== undefined) {
38
- clearTimeout(pressInTimer.current);
39
- pressInTimer.current = undefined;
40
- }
41
- }
42
- function activate(event) {
43
- activatedAt.current = Date.now();
44
- setOpacityTo(activeOpacity, OPACITY_ACTIVE_DURATION_MS);
45
- onPressIn?.(event);
46
- }
47
- function deactivate(event) {
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
- if (!pressed)
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
  };