@symbiote-native/angular 0.7.0 → 1.0.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 (188) hide show
  1. package/README.md +3 -3
  2. package/babel-lower-host-primitives.cjs +636 -0
  3. package/babel-register-composed.cjs +21 -3
  4. package/build/angular/anchor-host-registry.js +3 -1
  5. package/build/angular/anchor-host-registry.js.map +1 -1
  6. package/build/angular/bootstrap.js +1 -1
  7. package/build/angular/bootstrap.js.map +1 -1
  8. package/build/angular/components/activity-indicator/index.android.js +7 -2
  9. package/build/angular/components/activity-indicator/index.android.js.map +1 -1
  10. package/build/angular/components/activity-indicator/index.ios.js +3 -1
  11. package/build/angular/components/activity-indicator/index.ios.js.map +1 -1
  12. package/build/angular/components/activity-indicator/shared.d.ts +1 -1
  13. package/build/angular/components/activity-indicator/shared.js +1 -1
  14. package/build/angular/components/activity-indicator/shared.js.map +1 -1
  15. package/build/angular/components/button.d.ts +3 -0
  16. package/build/angular/components/button.js +22 -5
  17. package/build/angular/components/button.js.map +1 -1
  18. package/build/angular/components/flat-list/index.d.ts +1 -1
  19. package/build/angular/components/flat-list/index.js +47 -14
  20. package/build/angular/components/flat-list/index.js.map +1 -1
  21. package/build/angular/components/image/index.android.js +4 -10
  22. package/build/angular/components/image/index.android.js.map +1 -1
  23. package/build/angular/components/image/index.ios.js +4 -10
  24. package/build/angular/components/image/index.ios.js.map +1 -1
  25. package/build/angular/components/image/shared.d.ts +4 -4
  26. package/build/angular/components/image/shared.js +51 -33
  27. package/build/angular/components/image/shared.js.map +1 -1
  28. package/build/angular/components/image-background.d.ts +3 -0
  29. package/build/angular/components/image-background.js +32 -9
  30. package/build/angular/components/image-background.js.map +1 -1
  31. package/build/angular/components/input-accessory-view/index.d.ts +2 -1
  32. package/build/angular/components/input-accessory-view/index.js +18 -16
  33. package/build/angular/components/input-accessory-view/index.js.map +1 -1
  34. package/build/angular/components/keyboard-avoiding-view/index.d.ts +3 -1
  35. package/build/angular/components/keyboard-avoiding-view/index.js +56 -19
  36. package/build/angular/components/keyboard-avoiding-view/index.js.map +1 -1
  37. package/build/angular/components/modal/index.d.ts +1 -0
  38. package/build/angular/components/modal/index.js +21 -10
  39. package/build/angular/components/modal/index.js.map +1 -1
  40. package/build/angular/components/pressable/index.d.ts +10 -5
  41. package/build/angular/components/pressable/index.js +61 -16
  42. package/build/angular/components/pressable/index.js.map +1 -1
  43. package/build/angular/components/refresh-control/index.d.ts +2 -1
  44. package/build/angular/components/refresh-control/index.js +13 -9
  45. package/build/angular/components/refresh-control/index.js.map +1 -1
  46. package/build/angular/components/safe-area-view/index.d.ts +3 -1
  47. package/build/angular/components/safe-area-view/index.js +22 -20
  48. package/build/angular/components/safe-area-view/index.js.map +1 -1
  49. package/build/angular/components/scroll-view/index.android.js +44 -14
  50. package/build/angular/components/scroll-view/index.android.js.map +1 -1
  51. package/build/angular/components/scroll-view/index.ios.js +13 -5
  52. package/build/angular/components/scroll-view/index.ios.js.map +1 -1
  53. package/build/angular/components/scroll-view/projection.d.ts +32 -0
  54. package/build/angular/components/scroll-view/projection.js +212 -47
  55. package/build/angular/components/scroll-view/projection.js.map +1 -1
  56. package/build/angular/components/scroll-view/shared.d.ts +2 -0
  57. package/build/angular/components/scroll-view/shared.js +48 -11
  58. package/build/angular/components/scroll-view/shared.js.map +1 -1
  59. package/build/angular/components/scroll-view/sticky-header.js +7 -3
  60. package/build/angular/components/scroll-view/sticky-header.js.map +1 -1
  61. package/build/angular/components/section-list/index.d.ts +9 -1
  62. package/build/angular/components/section-list/index.js +72 -18
  63. package/build/angular/components/section-list/index.js.map +1 -1
  64. package/build/angular/components/switch/index.android.js +23 -9
  65. package/build/angular/components/switch/index.android.js.map +1 -1
  66. package/build/angular/components/switch/index.ios.js +23 -9
  67. package/build/angular/components/switch/index.ios.js.map +1 -1
  68. package/build/angular/components/switch/shared.d.ts +1 -1
  69. package/build/angular/components/switch/shared.js +5 -2
  70. package/build/angular/components/switch/shared.js.map +1 -1
  71. package/build/angular/components/text-input.d.ts +8 -2
  72. package/build/angular/components/text-input.js +79 -34
  73. package/build/angular/components/text-input.js.map +1 -1
  74. package/build/angular/components/touchable/index.d.ts +36 -7
  75. package/build/angular/components/touchable/index.js +280 -72
  76. package/build/angular/components/touchable/index.js.map +1 -1
  77. package/build/angular/components/touchable-native-feedback/index.d.ts +2 -1
  78. package/build/angular/components/touchable-native-feedback/index.js +19 -17
  79. package/build/angular/components/touchable-native-feedback/index.js.map +1 -1
  80. package/build/angular/components/virtualized-list/directives.js +4 -0
  81. package/build/angular/components/virtualized-list/directives.js.map +1 -1
  82. package/build/angular/components/virtualized-list/index.d.ts +8 -2
  83. package/build/angular/components/virtualized-list/index.js +207 -61
  84. package/build/angular/components/virtualized-list/index.js.map +1 -1
  85. package/build/angular/components/virtualized-section-list/directives.js.map +1 -1
  86. package/build/angular/components/virtualized-section-list/index.d.ts +21 -1
  87. package/build/angular/components/virtualized-section-list/index.js +100 -22
  88. package/build/angular/components/virtualized-section-list/index.js.map +1 -1
  89. package/build/angular/components.d.ts +2 -2
  90. package/build/angular/components.js +1 -1
  91. package/build/angular/components.js.map +1 -1
  92. package/build/angular/create-portal/index.d.ts +11 -2
  93. package/build/angular/create-portal/index.js +42 -12
  94. package/build/angular/create-portal/index.js.map +1 -1
  95. package/build/angular/create-tunnel/index.js.map +1 -1
  96. package/build/angular/descriptor-to-angular/index.js +3 -1
  97. package/build/angular/descriptor-to-angular/index.js.map +1 -1
  98. package/build/angular/diagnostics.d.ts +33 -0
  99. package/build/angular/diagnostics.js +82 -0
  100. package/build/angular/diagnostics.js.map +1 -0
  101. package/build/angular/gate-demand.d.ts +37 -0
  102. package/build/angular/gate-demand.js +84 -0
  103. package/build/angular/gate-demand.js.map +1 -0
  104. package/build/angular/host-instance/index.js +1 -1
  105. package/build/angular/host-instance/index.js.map +1 -1
  106. package/build/angular/index.d.ts +6 -2
  107. package/build/angular/index.js +16 -1
  108. package/build/angular/index.js.map +1 -1
  109. package/build/angular/modules/animated/create-animated-component.d.ts +1 -0
  110. package/build/angular/modules/animated/create-animated-component.js +41 -18
  111. package/build/angular/modules/animated/create-animated-component.js.map +1 -1
  112. package/build/angular/modules/app-registry/index.js.map +1 -1
  113. package/build/angular/modules/status-bar/index.js +1 -1
  114. package/build/angular/modules/status-bar/index.js.map +1 -1
  115. package/build/angular/primitives/index.d.ts +31 -2
  116. package/build/angular/primitives/index.js +81 -3
  117. package/build/angular/primitives/index.js.map +1 -1
  118. package/build/angular/primitives/shared.d.ts +9 -1
  119. package/build/angular/primitives/shared.js +49 -3
  120. package/build/angular/primitives/shared.js.map +1 -1
  121. package/build/angular/register.d.ts +1 -0
  122. package/build/angular/register.js +35 -0
  123. package/build/angular/register.js.map +1 -0
  124. package/build/angular/render/index.js +51 -6
  125. package/build/angular/render/index.js.map +1 -1
  126. package/build/angular/renderer/index.d.ts +1 -0
  127. package/build/angular/renderer/index.js +157 -21
  128. package/build/angular/renderer/index.js.map +1 -1
  129. package/build/angular/services/color-scheme.service.js.map +1 -1
  130. package/build/angular/services/window-dimensions.service.js +1 -1
  131. package/build/angular/services/window-dimensions.service.js.map +1 -1
  132. package/build/angular/state-style.d.ts +9 -0
  133. package/build/angular/state-style.js +39 -0
  134. package/build/angular/state-style.js.map +1 -0
  135. package/metro-transformer.cjs +69 -0
  136. package/package.json +27 -8
  137. package/src/anchor-host-registry.ts +3 -1
  138. package/src/bootstrap.ts +4 -1
  139. package/src/components/activity-indicator/index.android.ts +7 -2
  140. package/src/components/activity-indicator/index.ios.ts +3 -1
  141. package/src/components/activity-indicator/shared.ts +32 -13
  142. package/src/components/button.ts +36 -6
  143. package/src/components/flat-list/index.ts +91 -29
  144. package/src/components/image/index.android.ts +9 -6
  145. package/src/components/image/index.ios.ts +9 -6
  146. package/src/components/image/shared.ts +110 -45
  147. package/src/components/image-background.ts +47 -10
  148. package/src/components/input-accessory-view/index.ts +41 -18
  149. package/src/components/keyboard-avoiding-view/index.ts +76 -22
  150. package/src/components/modal/index.ts +39 -12
  151. package/src/components/pressable/index.ts +121 -31
  152. package/src/components/refresh-control/index.ts +36 -13
  153. package/src/components/safe-area-view/index.ts +44 -19
  154. package/src/components/scroll-view/index.android.ts +31 -9
  155. package/src/components/scroll-view/index.ios.ts +17 -4
  156. package/src/components/scroll-view/projection.ts +290 -63
  157. package/src/components/scroll-view/shared.ts +124 -30
  158. package/src/components/scroll-view/sticky-header.ts +25 -8
  159. package/src/components/section-list/index.ts +79 -19
  160. package/src/components/switch/index.android.ts +18 -7
  161. package/src/components/switch/index.ios.ts +18 -7
  162. package/src/components/switch/shared.ts +15 -4
  163. package/src/components/text-input.ts +119 -31
  164. package/src/components/touchable/index.ts +339 -72
  165. package/src/components/touchable-native-feedback/index.ts +50 -18
  166. package/src/components/virtualized-list/directives.ts +19 -5
  167. package/src/components/virtualized-list/index.ts +292 -72
  168. package/src/components/virtualized-section-list/directives.ts +6 -3
  169. package/src/components/virtualized-section-list/index.ts +164 -34
  170. package/src/components.ts +6 -1
  171. package/src/create-portal/index.ts +47 -11
  172. package/src/create-tunnel/index.ts +3 -1
  173. package/src/descriptor-to-angular/index.ts +29 -8
  174. package/src/diagnostics.ts +138 -0
  175. package/src/gate-demand.ts +109 -0
  176. package/src/host-instance/index.ts +9 -3
  177. package/src/index.ts +33 -2
  178. package/src/modules/animated/create-animated-component.ts +67 -19
  179. package/src/modules/app-registry/index.ts +3 -1
  180. package/src/modules/status-bar/index.ts +13 -4
  181. package/src/primitives/index.ts +73 -2
  182. package/src/primitives/shared.ts +70 -9
  183. package/src/register.ts +43 -0
  184. package/src/render/index.ts +59 -7
  185. package/src/renderer/index.ts +209 -37
  186. package/src/services/color-scheme.service.ts +3 -1
  187. package/src/services/window-dimensions.service.ts +11 -4
  188. package/src/state-style.ts +39 -0
@@ -6,9 +6,10 @@
6
6
  // to 1 on press-out, driven from Pressable's onPressIn/onPressOut. The opacity Value is held by
7
7
  // IDENTITY as a plain field (an engine object, never an @Input / reactive wrap) and the
8
8
  // <symbiote-animated-view> leaf commits it every frame.
9
- // TouchableHighlight: paint underlayColor + lower child opacity while pressed, via Pressable's
10
- // style-as-function (Pressable drives the pressed flag through its own responder lifecycle).
11
- // TouchableWithoutFeedback: no visual change, just the press wiring forwarded through Pressable.
9
+ // TouchableHighlight: paint underlayColor + lower child opacity while the underlay is SHOWN.
10
+ // RN drives that from onPressIn/onPress/onPressOut and holds it past the tap for delayPressOut,
11
+ // NOT from Pressable's pressed flag a tap too fast to see is already un-pressed by then.
12
+ // TouchableWithoutFeedback: no visual change, but RN still runs the full press-timing machine.
12
13
  //
13
14
  // Every Touchable's own press/hover/accessibility events are now real @Output() EventEmitters too,
14
15
  // matching Pressable (which they wrap) — `(press)="handler($event)"`, never `[onPress]="handler"`.
@@ -22,18 +23,35 @@
22
23
  // React's Touchable parity is against
23
24
  // the React Pressable surface.
24
25
  import { CUSTOM_ELEMENTS_SCHEMA, ChangeDetectionStrategy, Component, computed, ElementRef, EventEmitter, inject, Input, Output, signal, } from '@angular/core';
25
- 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';
26
+ import { createHighlightUnderlayHandlers, createHighlightUnderlayRuntime, createTouchableFeedbackHandlers, createTouchableFeedbackRuntime, hasTouchablePressHandler, resolveHighlightExtraStyles, restingOpacityFromStyle, DEFAULT_ACTIVE_OPACITY, OPACITY_ACTIVE_GRANT_DURATION_MS, OPACITY_INACTIVE_DURATION_MS, RESTING_OPACITY, TOUCHABLE_MIN_PRESS_DURATION_MS, } from '@symbiote-native/components';
26
27
  import {} from '@symbiote-native/engine';
27
- import { anchorHostStyle, anchorStyleProp, SymbioteStyleInputDirective } from '../../primitives';
28
+ import { anchorHostStyle, anchorStyleProp, SymbioteStyleInputDirective, } from '../../primitives';
28
29
  import { Pressable } from '../pressable';
29
30
  import { Animated, AnimatedView } from '../../modules/animated';
31
+ import { gateWanted, injectGateDemandAbove, provideGateDemand, } from '../../gate-demand';
30
32
  import * as i0 from "@angular/core";
31
33
  import * as i1 from "../../primitives/shared";
32
- // The real setTimeout the shared feedback machine schedules its deferred activation/deactivation on
33
- // (core/components has no timer globals). Returns a canceller so an early release flushes the timer.
34
- function scheduleTimeout(callback, ms) {
35
- const id = setTimeout(callback, ms);
36
- return () => clearTimeout(id);
34
+ function createTimerScheduler() {
35
+ const pending = new Set();
36
+ return {
37
+ schedule(callback, ms) {
38
+ const id = setTimeout(() => {
39
+ pending.delete(cancel);
40
+ callback();
41
+ }, ms);
42
+ const cancel = () => {
43
+ clearTimeout(id);
44
+ pending.delete(cancel);
45
+ };
46
+ pending.add(cancel);
47
+ return cancel;
48
+ },
49
+ cancelAll() {
50
+ for (const cancel of [...pending])
51
+ cancel();
52
+ pending.clear();
53
+ },
54
+ };
37
55
  }
38
56
  export class TouchableOpacity {
39
57
  press = new EventEmitter();
@@ -47,6 +65,13 @@ export class TouchableOpacity {
47
65
  accessibilityTap = new EventEmitter();
48
66
  magicTap = new EventEmitter();
49
67
  accessibilityEscape = new EventEmitter();
68
+ // This wrapper binds the four gated accessibility events on the component it renders, which
69
+ // Angular forces to be unconditional and which would light that component's gates on every
70
+ // instance. It answers for them instead — see `gate-demand.ts`.
71
+ gateDemandAbove = injectGateDemandAbove();
72
+ wantsGate(name) {
73
+ return gateWanted(this.gateDemandAbove, name, this[name]);
74
+ }
50
75
  activeOpacity;
51
76
  delayPressIn;
52
77
  delayPressOut;
@@ -104,13 +129,20 @@ export class TouchableOpacity {
104
129
  ariaValueText;
105
130
  id;
106
131
  role;
107
- // One Animated.Value per mount, resting at full opacity. Held by IDENTITY as a plain field (an
108
- // engine object, never an @Input / reactive wrap); the <symbiote-animated-view> leaf rasterizes
109
- // it for the first paint and drives it through setNativeProps every frame.
132
+ // One Animated.Value per mount. Held by IDENTITY as a plain field (an engine object, never an
133
+ // @Input / reactive wrap); the <symbiote-animated-view> leaf rasterizes it for the first paint
134
+ // and drives it through setNativeProps every frame.
135
+ //
136
+ // RN seeds it from _getChildStyleOpacityWithDefault(props.style). Angular writes @Input()s AFTER
137
+ // the field initializers run, so `style` is still undefined here — the real resting value is
138
+ // seeded by the first ngOnChanges below, which still precedes the first template pass.
110
139
  opacity = new Animated.Value(RESTING_OPACITY);
111
140
  // The shared press-scheduling cell (delayPressIn timer + activation clock), persisted on the
112
141
  // instance; the machine's handlers are rebuilt per event over live @Input()s.
113
142
  runtime = createTouchableFeedbackRuntime();
143
+ timers = createTimerScheduler();
144
+ // What the last settle ran for. Undefined until the first ngOnChanges, which is the MOUNT.
145
+ settled;
114
146
  // This component's OWN host — the non-painting anchor `class="..."` at the use site resolves
115
147
  // onto (see anchorHostStyle's doc comment) — NOT the <symbiote-animated-view> leaf one level down.
116
148
  elementRef = inject(ElementRef);
@@ -134,12 +166,42 @@ export class TouchableOpacity {
134
166
  ngDoCheck() {
135
167
  this.anchorStyle.set(anchorHostStyle(this.elementRef));
136
168
  }
169
+ // RN's componentDidUpdate: a changed `disabled` or a changed style opacity re-settles the view,
170
+ // so a Touchable disabled mid-press does not stay stuck at its active opacity. The FIRST call is
171
+ // the mount (ngOnChanges runs before ngOnInit and before the first template pass), so it seeds
172
+ // the Value instead of animating — RN does this on update only, and a fade at mount would animate
173
+ // away from the value the leaf is about to paint. A use site with no bindings gets no ngOnChanges
174
+ // at all, and there the RESTING_OPACITY seed is already the right answer.
175
+ ngOnChanges() {
176
+ const settled = { disabled: this.disabled, resting: this.restingOpacity() };
177
+ if (this.settled === undefined) {
178
+ this.opacity.setValue(settled.resting);
179
+ }
180
+ else if (this.settled.disabled !== settled.disabled ||
181
+ this.settled.resting !== settled.resting) {
182
+ this.setOpacityTo(settled.resting, OPACITY_INACTIVE_DURATION_MS);
183
+ }
184
+ this.settled = settled;
185
+ }
186
+ // RN's componentWillUnmount: stop the animation so a teardown mid-fade leaves no driver running
187
+ // against a node that is gone, and drop any press-out still deferred behind a timer.
188
+ ngOnDestroy() {
189
+ this.timers.cancelAll();
190
+ this.opacity.resetAnimation();
191
+ }
192
+ // RN's _getChildStyleOpacityWithDefault: the fade settles at the opacity the CALLER's style asks
193
+ // for, not at a hard 1 — a Touchable styled `opacity: 0.6` must come back to 0.6.
194
+ restingOpacity() {
195
+ return restingOpacityFromStyle(this.style);
196
+ }
137
197
  setOpacityTo(toValue, duration) {
138
198
  Animated.timing(this.opacity, {
139
199
  toValue,
140
200
  duration,
141
201
  easing: Animated.Easing.inOut(Animated.Easing.quad),
142
- useNativeDriver: false,
202
+ // RN's own (TouchableOpacity.js:242). opacity is natively drivable, so the fade survives a
203
+ // busy JS thread — which is the entire point of press feedback.
204
+ useNativeDriver: true,
143
205
  }).start();
144
206
  }
145
207
  // Built per event so the machine reads live @Input()s (delay/opacity); the runtime persists across
@@ -149,16 +211,18 @@ export class TouchableOpacity {
149
211
  return createTouchableFeedbackHandlers({
150
212
  delayPressIn: this.delayPressIn ?? 0,
151
213
  delayPressOut: this.delayPressOut ?? 0,
152
- minPressDuration: this.minPressDuration ?? DEFAULT_MIN_PRESS_DURATION_MS,
153
- schedule: scheduleTimeout,
214
+ // RN's Touchables override Pressability's own 130ms floor with 0; what holds the active
215
+ // visual there is the fade's own duration, not a press-duration floor.
216
+ minPressDuration: this.minPressDuration ?? TOUCHABLE_MIN_PRESS_DURATION_MS,
217
+ schedule: this.timers.schedule,
154
218
  now: Date.now,
155
219
  }, this.runtime, {
156
220
  activate: (event) => {
157
- this.setOpacityTo(this.activeOpacity ?? DEFAULT_ACTIVE_OPACITY, OPACITY_ACTIVE_DURATION_MS);
221
+ this.setOpacityTo(this.activeOpacity ?? DEFAULT_ACTIVE_OPACITY, OPACITY_ACTIVE_GRANT_DURATION_MS);
158
222
  this.pressIn.emit(event);
159
223
  },
160
224
  deactivate: (event) => {
161
- this.setOpacityTo(RESTING_OPACITY, OPACITY_INACTIVE_DURATION_MS);
225
+ this.setOpacityTo(this.restingOpacity(), OPACITY_INACTIVE_DURATION_MS);
162
226
  this.pressOut.emit(event);
163
227
  },
164
228
  });
@@ -172,8 +236,9 @@ export class TouchableOpacity {
172
236
  this.feedbackHandlers().handlePressOut(event);
173
237
  };
174
238
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: TouchableOpacity, deps: [], target: i0.ɵɵFactoryTarget.Component });
175
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "22.0.8", type: TouchableOpacity, isStandalone: true, selector: "TouchableOpacity", inputs: { activeOpacity: "activeOpacity", delayPressIn: "delayPressIn", delayPressOut: "delayPressOut", minPressDuration: "minPressDuration", style: "style", delayLongPress: "delayLongPress", delayHoverIn: "delayHoverIn", delayHoverOut: "delayHoverOut", disabled: "disabled", cancelable: "cancelable", hitSlop: "hitSlop", pressRetentionOffset: "pressRetentionOffset", unstable_pressDelay: "unstable_pressDelay", android_ripple: "android_ripple", android_disableSound: "android_disableSound", testID: "testID", nativeID: "nativeID", hasTVPreferredFocus: "hasTVPreferredFocus", nextFocusDown: "nextFocusDown", nextFocusForward: "nextFocusForward", nextFocusLeft: "nextFocusLeft", nextFocusRight: "nextFocusRight", nextFocusUp: "nextFocusUp", accessible: "accessible", accessibilityLabel: "accessibilityLabel", accessibilityHint: "accessibilityHint", accessibilityRole: "accessibilityRole", accessibilityState: "accessibilityState", accessibilityValue: "accessibilityValue", accessibilityActions: "accessibilityActions", accessibilityLabelledBy: "accessibilityLabelledBy", importantForAccessibility: "importantForAccessibility", accessibilityLiveRegion: "accessibilityLiveRegion", screenReaderFocusable: "screenReaderFocusable", accessibilityViewIsModal: "accessibilityViewIsModal", accessibilityElementsHidden: "accessibilityElementsHidden", accessibilityIgnoresInvertColors: "accessibilityIgnoresInvertColors", accessibilityLanguage: "accessibilityLanguage", accessibilityRespondsToUserInteraction: "accessibilityRespondsToUserInteraction", accessibilityShowsLargeContentViewer: "accessibilityShowsLargeContentViewer", accessibilityLargeContentTitle: "accessibilityLargeContentTitle", ariaLabel: "ariaLabel", ariaBusy: "ariaBusy", ariaChecked: "ariaChecked", ariaDisabled: "ariaDisabled", ariaExpanded: "ariaExpanded", ariaHidden: "ariaHidden", ariaLabelledBy: "ariaLabelledBy", ariaLive: "ariaLive", ariaSelected: "ariaSelected", ariaModal: "ariaModal", ariaValueMax: "ariaValueMax", ariaValueMin: "ariaValueMin", ariaValueNow: "ariaValueNow", ariaValueText: "ariaValueText", id: "id", role: "role" }, outputs: { press: "press", pressIn: "pressIn", pressOut: "pressOut", pressMove: "pressMove", longPress: "longPress", hoverIn: "hoverIn", hoverOut: "hoverOut", accessibilityAction: "accessibilityAction", accessibilityTap: "accessibilityTap", magicTap: "magicTap", accessibilityEscape: "accessibilityEscape" }, hostDirectives: [{ directive: i1.SymbioteStyleInputDirective, inputs: ["style", "style"] }], ngImport: i0, template: `
239
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "22.0.8", type: TouchableOpacity, isStandalone: true, selector: "TouchableOpacity", inputs: { activeOpacity: "activeOpacity", delayPressIn: "delayPressIn", delayPressOut: "delayPressOut", minPressDuration: "minPressDuration", style: "style", delayLongPress: "delayLongPress", delayHoverIn: "delayHoverIn", delayHoverOut: "delayHoverOut", disabled: "disabled", cancelable: "cancelable", hitSlop: "hitSlop", pressRetentionOffset: "pressRetentionOffset", unstable_pressDelay: "unstable_pressDelay", android_ripple: "android_ripple", android_disableSound: "android_disableSound", testID: "testID", nativeID: "nativeID", hasTVPreferredFocus: "hasTVPreferredFocus", nextFocusDown: "nextFocusDown", nextFocusForward: "nextFocusForward", nextFocusLeft: "nextFocusLeft", nextFocusRight: "nextFocusRight", nextFocusUp: "nextFocusUp", accessible: "accessible", accessibilityLabel: "accessibilityLabel", accessibilityHint: "accessibilityHint", accessibilityRole: "accessibilityRole", accessibilityState: "accessibilityState", accessibilityValue: "accessibilityValue", accessibilityActions: "accessibilityActions", accessibilityLabelledBy: "accessibilityLabelledBy", importantForAccessibility: "importantForAccessibility", accessibilityLiveRegion: "accessibilityLiveRegion", screenReaderFocusable: "screenReaderFocusable", accessibilityViewIsModal: "accessibilityViewIsModal", accessibilityElementsHidden: "accessibilityElementsHidden", accessibilityIgnoresInvertColors: "accessibilityIgnoresInvertColors", accessibilityLanguage: "accessibilityLanguage", accessibilityRespondsToUserInteraction: "accessibilityRespondsToUserInteraction", accessibilityShowsLargeContentViewer: "accessibilityShowsLargeContentViewer", accessibilityLargeContentTitle: "accessibilityLargeContentTitle", ariaLabel: "ariaLabel", ariaBusy: "ariaBusy", ariaChecked: "ariaChecked", ariaDisabled: "ariaDisabled", ariaExpanded: "ariaExpanded", ariaHidden: "ariaHidden", ariaLabelledBy: "ariaLabelledBy", ariaLive: "ariaLive", ariaSelected: "ariaSelected", ariaModal: "ariaModal", ariaValueMax: "ariaValueMax", ariaValueMin: "ariaValueMin", ariaValueNow: "ariaValueNow", ariaValueText: "ariaValueText", id: "id", role: "role" }, outputs: { press: "press", pressIn: "pressIn", pressOut: "pressOut", pressMove: "pressMove", longPress: "longPress", hoverIn: "hoverIn", hoverOut: "hoverOut", accessibilityAction: "accessibilityAction", accessibilityTap: "accessibilityTap", magicTap: "magicTap", accessibilityEscape: "accessibilityEscape" }, usesOnChanges: true, hostDirectives: [{ directive: i1.SymbioteStyleInputDirective, inputs: ["style", "style"] }], ngImport: i0, template: `
176
240
  <Pressable
241
+ [__minPressDuration]="0"
177
242
  (press)="press.emit($event)"
178
243
  (pressIn)="handlePressIn($event)"
179
244
  (pressOut)="handlePressOut($event)"
@@ -214,8 +279,12 @@ export class TouchableOpacity {
214
279
  [accessibilityElementsHidden]="accessibilityElementsHidden"
215
280
  [accessibilityIgnoresInvertColors]="accessibilityIgnoresInvertColors"
216
281
  [accessibilityLanguage]="accessibilityLanguage"
217
- [accessibilityRespondsToUserInteraction]="accessibilityRespondsToUserInteraction"
218
- [accessibilityShowsLargeContentViewer]="accessibilityShowsLargeContentViewer"
282
+ [accessibilityRespondsToUserInteraction]="
283
+ accessibilityRespondsToUserInteraction
284
+ "
285
+ [accessibilityShowsLargeContentViewer]="
286
+ accessibilityShowsLargeContentViewer
287
+ "
219
288
  [accessibilityLargeContentTitle]="accessibilityLargeContentTitle"
220
289
  (accessibilityAction)="accessibilityAction.emit($event)"
221
290
  (accessibilityTap)="accessibilityTap.emit($event)"
@@ -242,19 +311,23 @@ export class TouchableOpacity {
242
311
  <ng-content></ng-content>
243
312
  </symbiote-animated-view>
244
313
  </Pressable>
245
- `, isInline: true, dependencies: [{ kind: "component", type: Pressable, selector: "Pressable, symbiote-pressable", inputs: ["delayLongPress", "disabled", "cancelable", "hitSlop", "pressRetentionOffset", "unstable_pressDelay", "android_ripple", "android_disableSound", "delayHoverIn", "delayHoverOut", "testID", "nativeID", "hasTVPreferredFocus", "nextFocusDown", "nextFocusForward", "nextFocusLeft", "nextFocusRight", "nextFocusUp", "style", "accessible", "accessibilityLabel", "accessibilityHint", "accessibilityRole", "accessibilityState", "accessibilityValue", "accessibilityActions", "accessibilityLabelledBy", "importantForAccessibility", "accessibilityLiveRegion", "screenReaderFocusable", "accessibilityViewIsModal", "accessibilityElementsHidden", "accessibilityIgnoresInvertColors", "accessibilityLanguage", "accessibilityRespondsToUserInteraction", "accessibilityShowsLargeContentViewer", "accessibilityLargeContentTitle", "ariaLabel", "ariaBusy", "ariaChecked", "ariaDisabled", "ariaExpanded", "ariaHidden", "ariaLabelledBy", "ariaLive", "ariaSelected", "ariaModal", "ariaValueMax", "ariaValueMin", "ariaValueNow", "ariaValueText", "id", "role"], outputs: ["press", "pressIn", "pressOut", "pressMove", "longPress", "hoverIn", "hoverOut", "accessibilityAction", "accessibilityTap", "magicTap", "accessibilityEscape"] }, { kind: "component", type: AnimatedView, selector: "AnimatedView, symbiote-animated-view", inputs: ["style", "animatedProps", "passthroughAnimatedPropExplicitValues"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
314
+ `, isInline: true, dependencies: [{ kind: "component", type: Pressable, selector: "Pressable", inputs: ["delayLongPress", "disabled", "cancelable", "hitSlop", "pressRetentionOffset", "unstable_pressDelay", "__minPressDuration", "android_ripple", "android_disableSound", "delayHoverIn", "delayHoverOut", "testID", "nativeID", "hasTVPreferredFocus", "nextFocusDown", "nextFocusForward", "nextFocusLeft", "nextFocusRight", "nextFocusUp", "style", "accessible", "accessibilityLabel", "accessibilityHint", "accessibilityRole", "accessibilityState", "accessibilityValue", "accessibilityActions", "accessibilityLabelledBy", "importantForAccessibility", "accessibilityLiveRegion", "screenReaderFocusable", "accessibilityViewIsModal", "accessibilityElementsHidden", "accessibilityIgnoresInvertColors", "accessibilityLanguage", "accessibilityRespondsToUserInteraction", "accessibilityShowsLargeContentViewer", "accessibilityLargeContentTitle", "ariaLabel", "ariaBusy", "ariaChecked", "ariaDisabled", "ariaExpanded", "ariaHidden", "ariaLabelledBy", "ariaLive", "ariaSelected", "ariaModal", "ariaValueMax", "ariaValueMin", "ariaValueNow", "ariaValueText", "id", "role"], outputs: ["press", "pressIn", "pressOut", "pressMove", "longPress", "hoverIn", "hoverOut", "accessibilityAction", "accessibilityTap", "magicTap", "accessibilityEscape"] }, { kind: "component", type: AnimatedView, selector: "AnimatedView, symbiote-animated-view", inputs: ["style", "animatedProps", "passthroughAnimatedPropExplicitValues"] }], viewProviders: [provideGateDemand(() => TouchableOpacity)], changeDetection: i0.ChangeDetectionStrategy.OnPush });
246
315
  }
247
316
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: TouchableOpacity, decorators: [{
248
317
  type: Component,
249
318
  args: [{
250
319
  selector: 'TouchableOpacity',
251
320
  standalone: true,
252
- hostDirectives: [{ directive: SymbioteStyleInputDirective, inputs: ['style'] }],
321
+ viewProviders: [provideGateDemand(() => TouchableOpacity)],
322
+ hostDirectives: [
323
+ { directive: SymbioteStyleInputDirective, inputs: ['style'] },
324
+ ],
253
325
  schemas: [CUSTOM_ELEMENTS_SCHEMA],
254
326
  imports: [Pressable, AnimatedView],
255
327
  changeDetection: ChangeDetectionStrategy.OnPush,
256
328
  template: `
257
329
  <Pressable
330
+ [__minPressDuration]="0"
258
331
  (press)="press.emit($event)"
259
332
  (pressIn)="handlePressIn($event)"
260
333
  (pressOut)="handlePressOut($event)"
@@ -295,8 +368,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImpor
295
368
  [accessibilityElementsHidden]="accessibilityElementsHidden"
296
369
  [accessibilityIgnoresInvertColors]="accessibilityIgnoresInvertColors"
297
370
  [accessibilityLanguage]="accessibilityLanguage"
298
- [accessibilityRespondsToUserInteraction]="accessibilityRespondsToUserInteraction"
299
- [accessibilityShowsLargeContentViewer]="accessibilityShowsLargeContentViewer"
371
+ [accessibilityRespondsToUserInteraction]="
372
+ accessibilityRespondsToUserInteraction
373
+ "
374
+ [accessibilityShowsLargeContentViewer]="
375
+ accessibilityShowsLargeContentViewer
376
+ "
300
377
  [accessibilityLargeContentTitle]="accessibilityLargeContentTitle"
301
378
  (accessibilityAction)="accessibilityAction.emit($event)"
302
379
  (accessibilityTap)="accessibilityTap.emit($event)"
@@ -474,6 +551,16 @@ export class TouchableHighlight {
474
551
  accessibilityTap = new EventEmitter();
475
552
  magicTap = new EventEmitter();
476
553
  accessibilityEscape = new EventEmitter();
554
+ // This wrapper binds the four gated accessibility events on the component it renders, which
555
+ // Angular forces to be unconditional and which would light that component's gates on every
556
+ // instance. It answers for them instead — see `gate-demand.ts`.
557
+ gateDemandAbove = injectGateDemandAbove();
558
+ wantsGate(name) {
559
+ return gateWanted(this.gateDemandAbove, name, this[name]);
560
+ }
561
+ // RN's onShowUnderlay / onHideUnderlay — fired on a real transition only, never on a repeat.
562
+ showUnderlay = new EventEmitter();
563
+ hideUnderlay = new EventEmitter();
477
564
  activeOpacity;
478
565
  underlayColor;
479
566
  delayPressIn;
@@ -535,28 +622,86 @@ export class TouchableHighlight {
535
622
  // This component's OWN host — the non-painting anchor `class="..."` at the use site resolves
536
623
  // onto (see anchorHostStyle's doc comment) — NOT the Pressable one level down.
537
624
  elementRef = inject(ElementRef);
538
- // Pressable accepts a style-as-function and calls it with the live pressed state. Arrow field so
539
- // `this` stays bound when Pressable invokes it; it reads the inputs LIVE at call time. The
540
- // anchor's class-derived style goes first, then the user's explicit style, so an explicit
541
- // [style] still beats the ambient class. When pressed, paint the underlay color + lower the
542
- // child opacity (RN drives this with setState, not Animated, so we mirror that faithfully
543
- // through Pressable's pressed flag, no tween) the overlay always goes last so it wins.
544
- // A computed that RETURNS A NEW ARROW when its dependencies move, not one stable arrow forever.
545
- // The stable-arrow form was silently frozen: Pressable's `style` @Input never reported a change,
546
- // so Pressable's view never refreshed and never re-invoked the arrow - a class or [style]
547
- // toggled after mount never reached the committed view. Reading the anchor signal from inside
548
- // the arrow body instead would have worked by accident, by registering THIS component's signal
549
- // on Pressable's consumer; returning a new reference keeps the dependency where it belongs, in
550
- // an ordinary input change.
551
- pressedStyle = computed(() => {
625
+ // `shown` is NOT Pressable's `pressed`. RN holds the underlay for delayPressOut past the tap so a
626
+ // press too fast to see still flashes, and the pressed flag is already false by then. A SIGNAL,
627
+ // because the hide fires from a timer outside any Angular listener, so under zoneless CD
628
+ // nothing else would mark this view. A signal write both notifies the change-detection scheduler
629
+ // (markAncestorsForTraversal) and dirties this template's own reactive consumer, which is the one
630
+ // thing honored in Targeted mode; markForCheck from a plain field would not be reachable here.
631
+ shown = signal(false, /* @ts-ignore */
632
+ ...(ngDevMode ? [{ debugName: "shown" }] : /* istanbul ignore next */ []));
633
+ underlayRuntime = createHighlightUnderlayRuntime();
634
+ timers = createTimerScheduler();
635
+ // The container style Pressable paints.
636
+ //
637
+ // POINT-7 DECISION both halves stay on the CONTAINER, deliberately. RN's _createExtraStyles
638
+ // keeps them apart: `underlay` (the backgroundColor) on the container, `child` (the lowered
639
+ // opacity) cloned onto the single child. Angular has no cloneElement and no way to reach a
640
+ // projected <ng-content> node, so the only path to the child is a permanent wrapper View — which
641
+ // inserts a node into the flex chain and silently re-parents any `flex` a child declares. The
642
+ // fake Fabric runs no Yoga, so no headless test can measure that damage, only assert the extra
643
+ // node exists; shipping an unmeasurable layout change is worse than the visual approximation.
644
+ // Same call, same reason, as the Solid adapter. resolveHighlightExtraStyles keeps the two styles
645
+ // SEPARATE regardless, so a layout-safe fix (which needs a device check, not a test) stays open.
646
+ //
647
+ // Returns a NEW ARRAY whenever a dependency moves: Pressable's `style` @Input then reports an
648
+ // ordinary change. A stable reference was the earlier bug — Pressable's view never refreshed, so
649
+ // a class or [style] toggled after mount never reached the committed view.
650
+ containerStyle = computed(() => {
552
651
  this.inputsRevision();
553
652
  const base = [this.anchorStyle(), this.style];
554
- const underlayColor = this.underlayColor ?? DEFAULT_UNDERLAY_COLOR;
555
- const childOpacity = this.activeOpacity ?? DEFAULT_HIGHLIGHT_CHILD_OPACITY;
556
- return (state) => highlightPressedStyle(state.pressed, base, underlayColor, childOpacity);
653
+ const extra = resolveHighlightExtraStyles({
654
+ shown: this.shown(),
655
+ hasPressHandler: this.hasPressHandler(),
656
+ underlayColor: this.underlayColor,
657
+ activeOpacity: this.activeOpacity,
658
+ });
659
+ return extra === undefined ? base : [base, extra.underlay, extra.child];
557
660
  }, /* @ts-ignore */
558
- ...(ngDevMode ? [{ debugName: "pressedStyle" }] : /* istanbul ignore next */ []));
559
- // `style`, `underlayColor` and `activeOpacity` are read untracked inside that computed, so the
661
+ ...(ngDevMode ? [{ debugName: "containerStyle" }] : /* istanbul ignore next */ []));
662
+ // RN's _hasPressHandler: a Touchable that handles no press paints no underlay. Angular exposes
663
+ // the press lifecycle as @Output()s, so "a handler is present" is "something is subscribed" — the
664
+ // same `.observed` test Pressable uses to decide whether to arm its long-press timer at all.
665
+ hasPressHandler() {
666
+ return hasTouchablePressHandler({
667
+ onPress: this.press.observed ? this.press : undefined,
668
+ onPressIn: this.pressIn.observed ? this.pressIn : undefined,
669
+ onPressOut: this.pressOut.observed ? this.pressOut : undefined,
670
+ onLongPress: this.longPress.observed ? this.longPress : undefined,
671
+ });
672
+ }
673
+ // Built per event so the machine reads live @Input()s (delayPressOut, the has-handler gate); the
674
+ // runtime persists across calls, which is what lets handlePressOut see the timer handlePress set.
675
+ underlayHandlers() {
676
+ return createHighlightUnderlayHandlers({
677
+ delayPressOut: this.delayPressOut ?? 0,
678
+ hasPressHandler: this.hasPressHandler(),
679
+ schedule: this.timers.schedule,
680
+ }, this.underlayRuntime, {
681
+ setShown: (shown) => this.shown.set(shown),
682
+ onShowUnderlay: () => this.showUnderlay.emit(),
683
+ onHideUnderlay: () => this.hideUnderlay.emit(),
684
+ });
685
+ }
686
+ // Visual first, then the caller's own event — RN's order in _createPressabilityConfig.
687
+ // onLongPress is deliberately NOT intercepted (Pressable emits it straight through); it is only
688
+ // READ, by the has-press-handler gate above.
689
+ handlePressIn(event) {
690
+ this.underlayHandlers().handlePressIn(event);
691
+ this.pressIn.emit(event);
692
+ }
693
+ handlePress(event) {
694
+ this.underlayHandlers().handlePress(event);
695
+ this.press.emit(event);
696
+ }
697
+ handlePressOut(event) {
698
+ this.underlayHandlers().handlePressOut(event);
699
+ this.pressOut.emit(event);
700
+ }
701
+ ngOnDestroy() {
702
+ this.timers.cancelAll();
703
+ }
704
+ // `style`, `underlayColor` and `activeOpacity` are read untracked inside containerStyle, so the
560
705
  // bump is what tells it they moved. See the ngDoCheck note below for the anchor half, which
561
706
  // ngOnChanges cannot cover.
562
707
  inputsRevision = signal(0, /* @ts-ignore */
@@ -575,12 +720,13 @@ export class TouchableHighlight {
575
720
  this.anchorStyle.set(anchorStyleProp(this.elementRef));
576
721
  }
577
722
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: TouchableHighlight, deps: [], target: i0.ɵɵFactoryTarget.Component });
578
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "22.0.8", type: TouchableHighlight, isStandalone: true, selector: "TouchableHighlight", inputs: { activeOpacity: "activeOpacity", underlayColor: "underlayColor", delayPressIn: "delayPressIn", delayPressOut: "delayPressOut", minPressDuration: "minPressDuration", style: "style", delayLongPress: "delayLongPress", delayHoverIn: "delayHoverIn", delayHoverOut: "delayHoverOut", disabled: "disabled", cancelable: "cancelable", hitSlop: "hitSlop", pressRetentionOffset: "pressRetentionOffset", unstable_pressDelay: "unstable_pressDelay", android_ripple: "android_ripple", android_disableSound: "android_disableSound", testID: "testID", nativeID: "nativeID", hasTVPreferredFocus: "hasTVPreferredFocus", nextFocusDown: "nextFocusDown", nextFocusForward: "nextFocusForward", nextFocusLeft: "nextFocusLeft", nextFocusRight: "nextFocusRight", nextFocusUp: "nextFocusUp", accessible: "accessible", accessibilityLabel: "accessibilityLabel", accessibilityHint: "accessibilityHint", accessibilityRole: "accessibilityRole", accessibilityState: "accessibilityState", accessibilityValue: "accessibilityValue", accessibilityActions: "accessibilityActions", accessibilityLabelledBy: "accessibilityLabelledBy", importantForAccessibility: "importantForAccessibility", accessibilityLiveRegion: "accessibilityLiveRegion", screenReaderFocusable: "screenReaderFocusable", accessibilityViewIsModal: "accessibilityViewIsModal", accessibilityElementsHidden: "accessibilityElementsHidden", accessibilityIgnoresInvertColors: "accessibilityIgnoresInvertColors", accessibilityLanguage: "accessibilityLanguage", accessibilityRespondsToUserInteraction: "accessibilityRespondsToUserInteraction", accessibilityShowsLargeContentViewer: "accessibilityShowsLargeContentViewer", accessibilityLargeContentTitle: "accessibilityLargeContentTitle", ariaLabel: "ariaLabel", ariaBusy: "ariaBusy", ariaChecked: "ariaChecked", ariaDisabled: "ariaDisabled", ariaExpanded: "ariaExpanded", ariaHidden: "ariaHidden", ariaLabelledBy: "ariaLabelledBy", ariaLive: "ariaLive", ariaSelected: "ariaSelected", ariaModal: "ariaModal", ariaValueMax: "ariaValueMax", ariaValueMin: "ariaValueMin", ariaValueNow: "ariaValueNow", ariaValueText: "ariaValueText", id: "id", role: "role" }, outputs: { press: "press", pressIn: "pressIn", pressOut: "pressOut", pressMove: "pressMove", longPress: "longPress", hoverIn: "hoverIn", hoverOut: "hoverOut", accessibilityAction: "accessibilityAction", accessibilityTap: "accessibilityTap", magicTap: "magicTap", accessibilityEscape: "accessibilityEscape" }, usesOnChanges: true, hostDirectives: [{ directive: i1.SymbioteStyleInputDirective, inputs: ["style", "style"] }], ngImport: i0, template: `
723
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "22.0.8", type: TouchableHighlight, isStandalone: true, selector: "TouchableHighlight", inputs: { activeOpacity: "activeOpacity", underlayColor: "underlayColor", delayPressIn: "delayPressIn", delayPressOut: "delayPressOut", minPressDuration: "minPressDuration", style: "style", delayLongPress: "delayLongPress", delayHoverIn: "delayHoverIn", delayHoverOut: "delayHoverOut", disabled: "disabled", cancelable: "cancelable", hitSlop: "hitSlop", pressRetentionOffset: "pressRetentionOffset", unstable_pressDelay: "unstable_pressDelay", android_ripple: "android_ripple", android_disableSound: "android_disableSound", testID: "testID", nativeID: "nativeID", hasTVPreferredFocus: "hasTVPreferredFocus", nextFocusDown: "nextFocusDown", nextFocusForward: "nextFocusForward", nextFocusLeft: "nextFocusLeft", nextFocusRight: "nextFocusRight", nextFocusUp: "nextFocusUp", accessible: "accessible", accessibilityLabel: "accessibilityLabel", accessibilityHint: "accessibilityHint", accessibilityRole: "accessibilityRole", accessibilityState: "accessibilityState", accessibilityValue: "accessibilityValue", accessibilityActions: "accessibilityActions", accessibilityLabelledBy: "accessibilityLabelledBy", importantForAccessibility: "importantForAccessibility", accessibilityLiveRegion: "accessibilityLiveRegion", screenReaderFocusable: "screenReaderFocusable", accessibilityViewIsModal: "accessibilityViewIsModal", accessibilityElementsHidden: "accessibilityElementsHidden", accessibilityIgnoresInvertColors: "accessibilityIgnoresInvertColors", accessibilityLanguage: "accessibilityLanguage", accessibilityRespondsToUserInteraction: "accessibilityRespondsToUserInteraction", accessibilityShowsLargeContentViewer: "accessibilityShowsLargeContentViewer", accessibilityLargeContentTitle: "accessibilityLargeContentTitle", ariaLabel: "ariaLabel", ariaBusy: "ariaBusy", ariaChecked: "ariaChecked", ariaDisabled: "ariaDisabled", ariaExpanded: "ariaExpanded", ariaHidden: "ariaHidden", ariaLabelledBy: "ariaLabelledBy", ariaLive: "ariaLive", ariaSelected: "ariaSelected", ariaModal: "ariaModal", ariaValueMax: "ariaValueMax", ariaValueMin: "ariaValueMin", ariaValueNow: "ariaValueNow", ariaValueText: "ariaValueText", id: "id", role: "role" }, outputs: { press: "press", pressIn: "pressIn", pressOut: "pressOut", pressMove: "pressMove", longPress: "longPress", hoverIn: "hoverIn", hoverOut: "hoverOut", accessibilityAction: "accessibilityAction", accessibilityTap: "accessibilityTap", magicTap: "magicTap", accessibilityEscape: "accessibilityEscape", showUnderlay: "showUnderlay", hideUnderlay: "hideUnderlay" }, usesOnChanges: true, hostDirectives: [{ directive: i1.SymbioteStyleInputDirective, inputs: ["style", "style"] }], ngImport: i0, template: `
579
724
  <Pressable
580
- [style]="pressedStyle()"
581
- (press)="press.emit($event)"
582
- (pressIn)="pressIn.emit($event)"
583
- (pressOut)="pressOut.emit($event)"
725
+ [__minPressDuration]="0"
726
+ [style]="containerStyle()"
727
+ (press)="handlePress($event)"
728
+ (pressIn)="handlePressIn($event)"
729
+ (pressOut)="handlePressOut($event)"
584
730
  (pressMove)="pressMove.emit($event)"
585
731
  (longPress)="longPress.emit($event)"
586
732
  (hoverIn)="hoverIn.emit($event)"
@@ -618,8 +764,12 @@ export class TouchableHighlight {
618
764
  [accessibilityElementsHidden]="accessibilityElementsHidden"
619
765
  [accessibilityIgnoresInvertColors]="accessibilityIgnoresInvertColors"
620
766
  [accessibilityLanguage]="accessibilityLanguage"
621
- [accessibilityRespondsToUserInteraction]="accessibilityRespondsToUserInteraction"
622
- [accessibilityShowsLargeContentViewer]="accessibilityShowsLargeContentViewer"
767
+ [accessibilityRespondsToUserInteraction]="
768
+ accessibilityRespondsToUserInteraction
769
+ "
770
+ [accessibilityShowsLargeContentViewer]="
771
+ accessibilityShowsLargeContentViewer
772
+ "
623
773
  [accessibilityLargeContentTitle]="accessibilityLargeContentTitle"
624
774
  (accessibilityAction)="accessibilityAction.emit($event)"
625
775
  (accessibilityTap)="accessibilityTap.emit($event)"
@@ -644,22 +794,26 @@ export class TouchableHighlight {
644
794
  >
645
795
  <ng-content></ng-content>
646
796
  </Pressable>
647
- `, isInline: true, dependencies: [{ kind: "component", type: Pressable, selector: "Pressable, symbiote-pressable", inputs: ["delayLongPress", "disabled", "cancelable", "hitSlop", "pressRetentionOffset", "unstable_pressDelay", "android_ripple", "android_disableSound", "delayHoverIn", "delayHoverOut", "testID", "nativeID", "hasTVPreferredFocus", "nextFocusDown", "nextFocusForward", "nextFocusLeft", "nextFocusRight", "nextFocusUp", "style", "accessible", "accessibilityLabel", "accessibilityHint", "accessibilityRole", "accessibilityState", "accessibilityValue", "accessibilityActions", "accessibilityLabelledBy", "importantForAccessibility", "accessibilityLiveRegion", "screenReaderFocusable", "accessibilityViewIsModal", "accessibilityElementsHidden", "accessibilityIgnoresInvertColors", "accessibilityLanguage", "accessibilityRespondsToUserInteraction", "accessibilityShowsLargeContentViewer", "accessibilityLargeContentTitle", "ariaLabel", "ariaBusy", "ariaChecked", "ariaDisabled", "ariaExpanded", "ariaHidden", "ariaLabelledBy", "ariaLive", "ariaSelected", "ariaModal", "ariaValueMax", "ariaValueMin", "ariaValueNow", "ariaValueText", "id", "role"], outputs: ["press", "pressIn", "pressOut", "pressMove", "longPress", "hoverIn", "hoverOut", "accessibilityAction", "accessibilityTap", "magicTap", "accessibilityEscape"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
797
+ `, isInline: true, dependencies: [{ kind: "component", type: Pressable, selector: "Pressable", inputs: ["delayLongPress", "disabled", "cancelable", "hitSlop", "pressRetentionOffset", "unstable_pressDelay", "__minPressDuration", "android_ripple", "android_disableSound", "delayHoverIn", "delayHoverOut", "testID", "nativeID", "hasTVPreferredFocus", "nextFocusDown", "nextFocusForward", "nextFocusLeft", "nextFocusRight", "nextFocusUp", "style", "accessible", "accessibilityLabel", "accessibilityHint", "accessibilityRole", "accessibilityState", "accessibilityValue", "accessibilityActions", "accessibilityLabelledBy", "importantForAccessibility", "accessibilityLiveRegion", "screenReaderFocusable", "accessibilityViewIsModal", "accessibilityElementsHidden", "accessibilityIgnoresInvertColors", "accessibilityLanguage", "accessibilityRespondsToUserInteraction", "accessibilityShowsLargeContentViewer", "accessibilityLargeContentTitle", "ariaLabel", "ariaBusy", "ariaChecked", "ariaDisabled", "ariaExpanded", "ariaHidden", "ariaLabelledBy", "ariaLive", "ariaSelected", "ariaModal", "ariaValueMax", "ariaValueMin", "ariaValueNow", "ariaValueText", "id", "role"], outputs: ["press", "pressIn", "pressOut", "pressMove", "longPress", "hoverIn", "hoverOut", "accessibilityAction", "accessibilityTap", "magicTap", "accessibilityEscape"] }], viewProviders: [provideGateDemand(() => TouchableHighlight)], changeDetection: i0.ChangeDetectionStrategy.OnPush });
648
798
  }
649
799
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: TouchableHighlight, decorators: [{
650
800
  type: Component,
651
801
  args: [{
652
802
  selector: 'TouchableHighlight',
653
803
  standalone: true,
654
- hostDirectives: [{ directive: SymbioteStyleInputDirective, inputs: ['style'] }],
804
+ viewProviders: [provideGateDemand(() => TouchableHighlight)],
805
+ hostDirectives: [
806
+ { directive: SymbioteStyleInputDirective, inputs: ['style'] },
807
+ ],
655
808
  imports: [Pressable],
656
809
  changeDetection: ChangeDetectionStrategy.OnPush,
657
810
  template: `
658
811
  <Pressable
659
- [style]="pressedStyle()"
660
- (press)="press.emit($event)"
661
- (pressIn)="pressIn.emit($event)"
662
- (pressOut)="pressOut.emit($event)"
812
+ [__minPressDuration]="0"
813
+ [style]="containerStyle()"
814
+ (press)="handlePress($event)"
815
+ (pressIn)="handlePressIn($event)"
816
+ (pressOut)="handlePressOut($event)"
663
817
  (pressMove)="pressMove.emit($event)"
664
818
  (longPress)="longPress.emit($event)"
665
819
  (hoverIn)="hoverIn.emit($event)"
@@ -697,8 +851,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImpor
697
851
  [accessibilityElementsHidden]="accessibilityElementsHidden"
698
852
  [accessibilityIgnoresInvertColors]="accessibilityIgnoresInvertColors"
699
853
  [accessibilityLanguage]="accessibilityLanguage"
700
- [accessibilityRespondsToUserInteraction]="accessibilityRespondsToUserInteraction"
701
- [accessibilityShowsLargeContentViewer]="accessibilityShowsLargeContentViewer"
854
+ [accessibilityRespondsToUserInteraction]="
855
+ accessibilityRespondsToUserInteraction
856
+ "
857
+ [accessibilityShowsLargeContentViewer]="
858
+ accessibilityShowsLargeContentViewer
859
+ "
702
860
  [accessibilityLargeContentTitle]="accessibilityLargeContentTitle"
703
861
  (accessibilityAction)="accessibilityAction.emit($event)"
704
862
  (accessibilityTap)="accessibilityTap.emit($event)"
@@ -747,6 +905,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImpor
747
905
  type: Output
748
906
  }], accessibilityEscape: [{
749
907
  type: Output
908
+ }], showUnderlay: [{
909
+ type: Output
910
+ }], hideUnderlay: [{
911
+ type: Output
750
912
  }], activeOpacity: [{
751
913
  type: Input
752
914
  }], underlayColor: [{
@@ -865,9 +1027,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImpor
865
1027
  type: Input
866
1028
  }] } });
867
1029
  export class TouchableWithoutFeedback {
868
- // delayPressIn/delayPressOut/minPressDuration ride the prop type for surface parity with the
869
- // other two, but TouchableWithoutFeedback has no visual feedback, so nothing schedules off them
870
- // (RN's TouchableWithoutFeedback is the same pure passthrough).
1030
+ // RN's TouchableWithoutFeedback builds a FULL Pressability config with delayPressIn /
1031
+ // delayPressOut / minPressDuration: 0 "without feedback" means no VISUAL, not no timing. So the
1032
+ // same shared machine TouchableOpacity uses runs here, with the visual half left empty: the
1033
+ // pressIn/pressOut EMIT is what gets deferred and floored.
871
1034
  press = new EventEmitter();
872
1035
  pressIn = new EventEmitter();
873
1036
  pressOut = new EventEmitter();
@@ -879,6 +1042,13 @@ export class TouchableWithoutFeedback {
879
1042
  accessibilityTap = new EventEmitter();
880
1043
  magicTap = new EventEmitter();
881
1044
  accessibilityEscape = new EventEmitter();
1045
+ // This wrapper binds the four gated accessibility events on the component it renders, which
1046
+ // Angular forces to be unconditional and which would light that component's gates on every
1047
+ // instance. It answers for them instead — see `gate-demand.ts`.
1048
+ gateDemandAbove = injectGateDemandAbove();
1049
+ wantsGate(name) {
1050
+ return gateWanted(this.gateDemandAbove, name, this[name]);
1051
+ }
882
1052
  delayPressIn;
883
1053
  delayPressOut;
884
1054
  minPressDuration;
@@ -938,11 +1108,36 @@ export class TouchableWithoutFeedback {
938
1108
  // This component's OWN host — the non-painting anchor `class="..."` at the use site resolves
939
1109
  // onto (see anchorHostStyle's doc comment) — NOT the Pressable one level down.
940
1110
  elementRef = inject(ElementRef);
1111
+ // The shared press-scheduling cell (delayPressIn timer + activation clock), persisted on the
1112
+ // instance; the machine's handlers are rebuilt per event over live @Input()s.
1113
+ runtime = createTouchableFeedbackRuntime();
1114
+ timers = createTimerScheduler();
941
1115
  // The anchor's class-derived style goes first, then the explicit style, so an explicit [style]
942
1116
  // still beats the ambient class.
943
1117
  get mergedStyle() {
944
1118
  return [this.anchorStyle(), this.style];
945
1119
  }
1120
+ feedbackHandlers() {
1121
+ return createTouchableFeedbackHandlers({
1122
+ delayPressIn: this.delayPressIn ?? 0,
1123
+ delayPressOut: this.delayPressOut ?? 0,
1124
+ minPressDuration: this.minPressDuration ?? TOUCHABLE_MIN_PRESS_DURATION_MS,
1125
+ schedule: this.timers.schedule,
1126
+ now: Date.now,
1127
+ }, this.runtime, {
1128
+ activate: (event) => this.pressIn.emit(event),
1129
+ deactivate: (event) => this.pressOut.emit(event),
1130
+ });
1131
+ }
1132
+ handlePressIn(event) {
1133
+ this.feedbackHandlers().handlePressIn(event);
1134
+ }
1135
+ handlePressOut(event) {
1136
+ this.feedbackHandlers().handlePressOut(event);
1137
+ }
1138
+ ngOnDestroy() {
1139
+ this.timers.cancelAll();
1140
+ }
946
1141
  // The anchor's class-derived style is written by the renderer's addClass/removeClass at the USE
947
1142
  // SITE - it never appears in SimpleChanges, and nothing about it dirties THIS component's view.
948
1143
  // A `class=` present at creation therefore worked, while one toggled later did not: the parent
@@ -959,10 +1154,11 @@ export class TouchableWithoutFeedback {
959
1154
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: TouchableWithoutFeedback, deps: [], target: i0.ɵɵFactoryTarget.Component });
960
1155
  static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "22.0.8", type: TouchableWithoutFeedback, isStandalone: true, selector: "TouchableWithoutFeedback", inputs: { delayPressIn: "delayPressIn", delayPressOut: "delayPressOut", minPressDuration: "minPressDuration", style: "style", delayLongPress: "delayLongPress", delayHoverIn: "delayHoverIn", delayHoverOut: "delayHoverOut", disabled: "disabled", cancelable: "cancelable", hitSlop: "hitSlop", pressRetentionOffset: "pressRetentionOffset", unstable_pressDelay: "unstable_pressDelay", android_ripple: "android_ripple", android_disableSound: "android_disableSound", testID: "testID", nativeID: "nativeID", hasTVPreferredFocus: "hasTVPreferredFocus", nextFocusDown: "nextFocusDown", nextFocusForward: "nextFocusForward", nextFocusLeft: "nextFocusLeft", nextFocusRight: "nextFocusRight", nextFocusUp: "nextFocusUp", accessible: "accessible", accessibilityLabel: "accessibilityLabel", accessibilityHint: "accessibilityHint", accessibilityRole: "accessibilityRole", accessibilityState: "accessibilityState", accessibilityValue: "accessibilityValue", accessibilityActions: "accessibilityActions", accessibilityLabelledBy: "accessibilityLabelledBy", importantForAccessibility: "importantForAccessibility", accessibilityLiveRegion: "accessibilityLiveRegion", screenReaderFocusable: "screenReaderFocusable", accessibilityViewIsModal: "accessibilityViewIsModal", accessibilityElementsHidden: "accessibilityElementsHidden", accessibilityIgnoresInvertColors: "accessibilityIgnoresInvertColors", accessibilityLanguage: "accessibilityLanguage", accessibilityRespondsToUserInteraction: "accessibilityRespondsToUserInteraction", accessibilityShowsLargeContentViewer: "accessibilityShowsLargeContentViewer", accessibilityLargeContentTitle: "accessibilityLargeContentTitle", ariaLabel: "ariaLabel", ariaBusy: "ariaBusy", ariaChecked: "ariaChecked", ariaDisabled: "ariaDisabled", ariaExpanded: "ariaExpanded", ariaHidden: "ariaHidden", ariaLabelledBy: "ariaLabelledBy", ariaLive: "ariaLive", ariaSelected: "ariaSelected", ariaModal: "ariaModal", ariaValueMax: "ariaValueMax", ariaValueMin: "ariaValueMin", ariaValueNow: "ariaValueNow", ariaValueText: "ariaValueText", id: "id", role: "role" }, outputs: { press: "press", pressIn: "pressIn", pressOut: "pressOut", pressMove: "pressMove", longPress: "longPress", hoverIn: "hoverIn", hoverOut: "hoverOut", accessibilityAction: "accessibilityAction", accessibilityTap: "accessibilityTap", magicTap: "magicTap", accessibilityEscape: "accessibilityEscape" }, hostDirectives: [{ directive: i1.SymbioteStyleInputDirective, inputs: ["style", "style"] }], ngImport: i0, template: `
961
1156
  <Pressable
1157
+ [__minPressDuration]="0"
962
1158
  [style]="mergedStyle"
963
1159
  (press)="press.emit($event)"
964
- (pressIn)="pressIn.emit($event)"
965
- (pressOut)="pressOut.emit($event)"
1160
+ (pressIn)="handlePressIn($event)"
1161
+ (pressOut)="handlePressOut($event)"
966
1162
  (pressMove)="pressMove.emit($event)"
967
1163
  (longPress)="longPress.emit($event)"
968
1164
  (hoverIn)="hoverIn.emit($event)"
@@ -1000,8 +1196,12 @@ export class TouchableWithoutFeedback {
1000
1196
  [accessibilityElementsHidden]="accessibilityElementsHidden"
1001
1197
  [accessibilityIgnoresInvertColors]="accessibilityIgnoresInvertColors"
1002
1198
  [accessibilityLanguage]="accessibilityLanguage"
1003
- [accessibilityRespondsToUserInteraction]="accessibilityRespondsToUserInteraction"
1004
- [accessibilityShowsLargeContentViewer]="accessibilityShowsLargeContentViewer"
1199
+ [accessibilityRespondsToUserInteraction]="
1200
+ accessibilityRespondsToUserInteraction
1201
+ "
1202
+ [accessibilityShowsLargeContentViewer]="
1203
+ accessibilityShowsLargeContentViewer
1204
+ "
1005
1205
  [accessibilityLargeContentTitle]="accessibilityLargeContentTitle"
1006
1206
  (accessibilityAction)="accessibilityAction.emit($event)"
1007
1207
  (accessibilityTap)="accessibilityTap.emit($event)"
@@ -1026,22 +1226,26 @@ export class TouchableWithoutFeedback {
1026
1226
  >
1027
1227
  <ng-content></ng-content>
1028
1228
  </Pressable>
1029
- `, isInline: true, dependencies: [{ kind: "component", type: Pressable, selector: "Pressable, symbiote-pressable", inputs: ["delayLongPress", "disabled", "cancelable", "hitSlop", "pressRetentionOffset", "unstable_pressDelay", "android_ripple", "android_disableSound", "delayHoverIn", "delayHoverOut", "testID", "nativeID", "hasTVPreferredFocus", "nextFocusDown", "nextFocusForward", "nextFocusLeft", "nextFocusRight", "nextFocusUp", "style", "accessible", "accessibilityLabel", "accessibilityHint", "accessibilityRole", "accessibilityState", "accessibilityValue", "accessibilityActions", "accessibilityLabelledBy", "importantForAccessibility", "accessibilityLiveRegion", "screenReaderFocusable", "accessibilityViewIsModal", "accessibilityElementsHidden", "accessibilityIgnoresInvertColors", "accessibilityLanguage", "accessibilityRespondsToUserInteraction", "accessibilityShowsLargeContentViewer", "accessibilityLargeContentTitle", "ariaLabel", "ariaBusy", "ariaChecked", "ariaDisabled", "ariaExpanded", "ariaHidden", "ariaLabelledBy", "ariaLive", "ariaSelected", "ariaModal", "ariaValueMax", "ariaValueMin", "ariaValueNow", "ariaValueText", "id", "role"], outputs: ["press", "pressIn", "pressOut", "pressMove", "longPress", "hoverIn", "hoverOut", "accessibilityAction", "accessibilityTap", "magicTap", "accessibilityEscape"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1229
+ `, isInline: true, dependencies: [{ kind: "component", type: Pressable, selector: "Pressable", inputs: ["delayLongPress", "disabled", "cancelable", "hitSlop", "pressRetentionOffset", "unstable_pressDelay", "__minPressDuration", "android_ripple", "android_disableSound", "delayHoverIn", "delayHoverOut", "testID", "nativeID", "hasTVPreferredFocus", "nextFocusDown", "nextFocusForward", "nextFocusLeft", "nextFocusRight", "nextFocusUp", "style", "accessible", "accessibilityLabel", "accessibilityHint", "accessibilityRole", "accessibilityState", "accessibilityValue", "accessibilityActions", "accessibilityLabelledBy", "importantForAccessibility", "accessibilityLiveRegion", "screenReaderFocusable", "accessibilityViewIsModal", "accessibilityElementsHidden", "accessibilityIgnoresInvertColors", "accessibilityLanguage", "accessibilityRespondsToUserInteraction", "accessibilityShowsLargeContentViewer", "accessibilityLargeContentTitle", "ariaLabel", "ariaBusy", "ariaChecked", "ariaDisabled", "ariaExpanded", "ariaHidden", "ariaLabelledBy", "ariaLive", "ariaSelected", "ariaModal", "ariaValueMax", "ariaValueMin", "ariaValueNow", "ariaValueText", "id", "role"], outputs: ["press", "pressIn", "pressOut", "pressMove", "longPress", "hoverIn", "hoverOut", "accessibilityAction", "accessibilityTap", "magicTap", "accessibilityEscape"] }], viewProviders: [provideGateDemand(() => TouchableWithoutFeedback)], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1030
1230
  }
1031
1231
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: TouchableWithoutFeedback, decorators: [{
1032
1232
  type: Component,
1033
1233
  args: [{
1034
1234
  selector: 'TouchableWithoutFeedback',
1035
1235
  standalone: true,
1036
- hostDirectives: [{ directive: SymbioteStyleInputDirective, inputs: ['style'] }],
1236
+ viewProviders: [provideGateDemand(() => TouchableWithoutFeedback)],
1237
+ hostDirectives: [
1238
+ { directive: SymbioteStyleInputDirective, inputs: ['style'] },
1239
+ ],
1037
1240
  imports: [Pressable],
1038
1241
  changeDetection: ChangeDetectionStrategy.OnPush,
1039
1242
  template: `
1040
1243
  <Pressable
1244
+ [__minPressDuration]="0"
1041
1245
  [style]="mergedStyle"
1042
1246
  (press)="press.emit($event)"
1043
- (pressIn)="pressIn.emit($event)"
1044
- (pressOut)="pressOut.emit($event)"
1247
+ (pressIn)="handlePressIn($event)"
1248
+ (pressOut)="handlePressOut($event)"
1045
1249
  (pressMove)="pressMove.emit($event)"
1046
1250
  (longPress)="longPress.emit($event)"
1047
1251
  (hoverIn)="hoverIn.emit($event)"
@@ -1079,8 +1283,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImpor
1079
1283
  [accessibilityElementsHidden]="accessibilityElementsHidden"
1080
1284
  [accessibilityIgnoresInvertColors]="accessibilityIgnoresInvertColors"
1081
1285
  [accessibilityLanguage]="accessibilityLanguage"
1082
- [accessibilityRespondsToUserInteraction]="accessibilityRespondsToUserInteraction"
1083
- [accessibilityShowsLargeContentViewer]="accessibilityShowsLargeContentViewer"
1286
+ [accessibilityRespondsToUserInteraction]="
1287
+ accessibilityRespondsToUserInteraction
1288
+ "
1289
+ [accessibilityShowsLargeContentViewer]="
1290
+ accessibilityShowsLargeContentViewer
1291
+ "
1084
1292
  [accessibilityLargeContentTitle]="accessibilityLargeContentTitle"
1085
1293
  (accessibilityAction)="accessibilityAction.emit($event)"
1086
1294
  (accessibilityTap)="accessibilityTap.emit($event)"