@symbiote-native/angular 0.6.2 → 0.8.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 (191) hide show
  1. package/README.md +3 -3
  2. package/bin/symbiote-angular-dev.cjs +20 -19
  3. package/build/angular/anchor-host-registry.js +2 -2
  4. package/build/angular/anchor-host-registry.js.map +1 -1
  5. package/build/angular/bootstrap.js +1 -1
  6. package/build/angular/bootstrap.js.map +1 -1
  7. package/build/angular/components/activity-indicator/index.android.d.ts +2 -1
  8. package/build/angular/components/activity-indicator/index.android.js +12 -4
  9. package/build/angular/components/activity-indicator/index.android.js.map +1 -1
  10. package/build/angular/components/activity-indicator/index.ios.d.ts +2 -1
  11. package/build/angular/components/activity-indicator/index.ios.js +8 -3
  12. package/build/angular/components/activity-indicator/index.ios.js.map +1 -1
  13. package/build/angular/components/activity-indicator/shared.d.ts +1 -1
  14. package/build/angular/components/activity-indicator/shared.js +4 -4
  15. package/build/angular/components/activity-indicator/shared.js.map +1 -1
  16. package/build/angular/components/button.d.ts +4 -2
  17. package/build/angular/components/button.js +41 -22
  18. package/build/angular/components/button.js.map +1 -1
  19. package/build/angular/components/flat-list/index.d.ts +6 -4
  20. package/build/angular/components/flat-list/index.js +80 -50
  21. package/build/angular/components/flat-list/index.js.map +1 -1
  22. package/build/angular/components/image/index.android.d.ts +8 -3
  23. package/build/angular/components/image/index.android.js +42 -10
  24. package/build/angular/components/image/index.android.js.map +1 -1
  25. package/build/angular/components/image/index.ios.d.ts +8 -3
  26. package/build/angular/components/image/index.ios.js +42 -10
  27. package/build/angular/components/image/index.ios.js.map +1 -1
  28. package/build/angular/components/image/shared.d.ts +4 -1
  29. package/build/angular/components/image/shared.js +51 -8
  30. package/build/angular/components/image/shared.js.map +1 -1
  31. package/build/angular/components/image-background.d.ts +2 -1
  32. package/build/angular/components/image-background.js +26 -10
  33. package/build/angular/components/image-background.js.map +1 -1
  34. package/build/angular/components/input-accessory-view/index.d.ts +9 -4
  35. package/build/angular/components/input-accessory-view/index.js +49 -10
  36. package/build/angular/components/input-accessory-view/index.js.map +1 -1
  37. package/build/angular/components/keyboard-avoiding-view/index.d.ts +3 -1
  38. package/build/angular/components/keyboard-avoiding-view/index.js +44 -12
  39. package/build/angular/components/keyboard-avoiding-view/index.js.map +1 -1
  40. package/build/angular/components/modal/index.d.ts +11 -8
  41. package/build/angular/components/modal/index.js +51 -29
  42. package/build/angular/components/modal/index.js.map +1 -1
  43. package/build/angular/components/pressable/index.d.ts +12 -6
  44. package/build/angular/components/pressable/index.js +66 -13
  45. package/build/angular/components/pressable/index.js.map +1 -1
  46. package/build/angular/components/refresh-control/index.d.ts +8 -4
  47. package/build/angular/components/refresh-control/index.js +54 -16
  48. package/build/angular/components/refresh-control/index.js.map +1 -1
  49. package/build/angular/components/safe-area-view/index.d.ts +9 -4
  50. package/build/angular/components/safe-area-view/index.js +48 -9
  51. package/build/angular/components/safe-area-view/index.js.map +1 -1
  52. package/build/angular/components/scroll-view/index.android.d.ts +2 -3
  53. package/build/angular/components/scroll-view/index.android.js +88 -61
  54. package/build/angular/components/scroll-view/index.android.js.map +1 -1
  55. package/build/angular/components/scroll-view/index.ios.d.ts +2 -3
  56. package/build/angular/components/scroll-view/index.ios.js +24 -18
  57. package/build/angular/components/scroll-view/index.ios.js.map +1 -1
  58. package/build/angular/components/scroll-view/projection.d.ts +35 -0
  59. package/build/angular/components/scroll-view/projection.js +279 -53
  60. package/build/angular/components/scroll-view/projection.js.map +1 -1
  61. package/build/angular/components/scroll-view/shared.d.ts +14 -5
  62. package/build/angular/components/scroll-view/shared.js +225 -75
  63. package/build/angular/components/scroll-view/shared.js.map +1 -1
  64. package/build/angular/components/scroll-view/sticky-header.js +21 -22
  65. package/build/angular/components/scroll-view/sticky-header.js.map +1 -1
  66. package/build/angular/components/section-list/index.d.ts +7 -1
  67. package/build/angular/components/section-list/index.js +91 -54
  68. package/build/angular/components/section-list/index.js.map +1 -1
  69. package/build/angular/components/switch/index.android.d.ts +7 -3
  70. package/build/angular/components/switch/index.android.js +52 -10
  71. package/build/angular/components/switch/index.android.js.map +1 -1
  72. package/build/angular/components/switch/index.ios.d.ts +7 -3
  73. package/build/angular/components/switch/index.ios.js +52 -10
  74. package/build/angular/components/switch/index.ios.js.map +1 -1
  75. package/build/angular/components/switch/shared.d.ts +13 -4
  76. package/build/angular/components/switch/shared.js +71 -7
  77. package/build/angular/components/switch/shared.js.map +1 -1
  78. package/build/angular/components/text-input.d.ts +11 -3
  79. package/build/angular/components/text-input.js +68 -8
  80. package/build/angular/components/text-input.js.map +1 -1
  81. package/build/angular/components/touchable/index.d.ts +40 -9
  82. package/build/angular/components/touchable/index.js +303 -67
  83. package/build/angular/components/touchable/index.js.map +1 -1
  84. package/build/angular/components/touchable-native-feedback/index.d.ts +6 -3
  85. package/build/angular/components/touchable-native-feedback/index.js +63 -27
  86. package/build/angular/components/touchable-native-feedback/index.js.map +1 -1
  87. package/build/angular/components/virtualized-list/directives.js +22 -18
  88. package/build/angular/components/virtualized-list/directives.js.map +1 -1
  89. package/build/angular/components/virtualized-list/index.d.ts +15 -4
  90. package/build/angular/components/virtualized-list/index.js +326 -94
  91. package/build/angular/components/virtualized-list/index.js.map +1 -1
  92. package/build/angular/components/virtualized-section-list/directives.js +12 -12
  93. package/build/angular/components/virtualized-section-list/directives.js.map +1 -1
  94. package/build/angular/components/virtualized-section-list/index.d.ts +19 -1
  95. package/build/angular/components/virtualized-section-list/index.js +93 -22
  96. package/build/angular/components/virtualized-section-list/index.js.map +1 -1
  97. package/build/angular/components.d.ts +2 -2
  98. package/build/angular/components.js +5 -0
  99. package/build/angular/components.js.map +1 -1
  100. package/build/angular/create-portal/index.js +34 -36
  101. package/build/angular/create-portal/index.js.map +1 -1
  102. package/build/angular/create-tunnel/index.js +19 -22
  103. package/build/angular/create-tunnel/index.js.map +1 -1
  104. package/build/angular/descriptor-to-angular/index.js +6 -4
  105. package/build/angular/descriptor-to-angular/index.js.map +1 -1
  106. package/build/angular/diagnostics.d.ts +33 -0
  107. package/build/angular/diagnostics.js +82 -0
  108. package/build/angular/diagnostics.js.map +1 -0
  109. package/build/angular/host-instance/index.js +1 -1
  110. package/build/angular/host-instance/index.js.map +1 -1
  111. package/build/angular/index.d.ts +9 -4
  112. package/build/angular/index.js +17 -3
  113. package/build/angular/index.js.map +1 -1
  114. package/build/angular/modules/animated/animated-leaf-binder.d.ts +1 -7
  115. package/build/angular/modules/animated/animated-leaf-binder.js +22 -72
  116. package/build/angular/modules/animated/animated-leaf-binder.js.map +1 -1
  117. package/build/angular/modules/animated/create-animated-component.d.ts +11 -6
  118. package/build/angular/modules/animated/create-animated-component.js +106 -55
  119. package/build/angular/modules/animated/create-animated-component.js.map +1 -1
  120. package/build/angular/modules/status-bar/index.js +4 -4
  121. package/build/angular/modules/status-bar/index.js.map +1 -1
  122. package/build/angular/primitives/index.d.ts +20 -3
  123. package/build/angular/primitives/index.js +84 -48
  124. package/build/angular/primitives/index.js.map +1 -1
  125. package/build/angular/primitives/shared.d.ts +48 -2
  126. package/build/angular/primitives/shared.js +158 -11
  127. package/build/angular/primitives/shared.js.map +1 -1
  128. package/build/angular/render/index.js +69 -38
  129. package/build/angular/render/index.js.map +1 -1
  130. package/build/angular/renderer/index.d.ts +1 -0
  131. package/build/angular/renderer/index.js +37 -2
  132. package/build/angular/renderer/index.js.map +1 -1
  133. package/build/angular/services/color-scheme.service.js +3 -3
  134. package/build/angular/services/color-scheme.service.js.map +1 -1
  135. package/build/angular/services/window-dimensions.service.js +4 -4
  136. package/build/angular/services/window-dimensions.service.js.map +1 -1
  137. package/package.json +10 -8
  138. package/src/anchor-host-registry.ts +2 -2
  139. package/src/bootstrap.ts +4 -1
  140. package/src/components/activity-indicator/index.android.ts +8 -1
  141. package/src/components/activity-indicator/index.ios.ts +4 -0
  142. package/src/components/activity-indicator/shared.ts +32 -13
  143. package/src/components/button.ts +46 -19
  144. package/src/components/flat-list/index.ts +122 -62
  145. package/src/components/image/index.android.ts +58 -7
  146. package/src/components/image/index.ios.ts +58 -7
  147. package/src/components/image/shared.ts +92 -21
  148. package/src/components/image-background.ts +29 -9
  149. package/src/components/input-accessory-view/index.ts +67 -12
  150. package/src/components/keyboard-avoiding-view/index.ts +61 -15
  151. package/src/components/modal/index.ts +72 -33
  152. package/src/components/pressable/index.ts +117 -28
  153. package/src/components/refresh-control/index.ts +74 -18
  154. package/src/components/safe-area-view/index.ts +64 -10
  155. package/src/components/scroll-view/index.android.ts +62 -47
  156. package/src/components/scroll-view/index.ios.ts +19 -17
  157. package/src/components/scroll-view/projection.ts +363 -64
  158. package/src/components/scroll-view/shared.ts +312 -90
  159. package/src/components/scroll-view/sticky-header.ts +36 -24
  160. package/src/components/section-list/index.ts +86 -53
  161. package/src/components/switch/index.android.ts +60 -8
  162. package/src/components/switch/index.ios.ts +60 -8
  163. package/src/components/switch/shared.ts +93 -6
  164. package/src/components/text-input.ts +95 -13
  165. package/src/components/touchable/index.ts +348 -64
  166. package/src/components/touchable-native-feedback/index.ts +94 -31
  167. package/src/components/virtualized-list/directives.ts +19 -5
  168. package/src/components/virtualized-list/index.ts +380 -85
  169. package/src/components/virtualized-section-list/directives.ts +6 -3
  170. package/src/components/virtualized-section-list/index.ts +146 -33
  171. package/src/components.ts +9 -1
  172. package/src/create-portal/index.ts +31 -31
  173. package/src/create-tunnel/index.ts +16 -17
  174. package/src/descriptor-to-angular/index.ts +29 -8
  175. package/src/diagnostics.ts +138 -0
  176. package/src/host-instance/index.ts +9 -3
  177. package/src/index.ts +61 -3
  178. package/src/modules/animated/animated-leaf-binder.ts +28 -77
  179. package/src/modules/animated/create-animated-component.ts +115 -47
  180. package/src/modules/app-registry/index.ts +9 -9
  181. package/src/modules/status-bar/index.ts +13 -4
  182. package/src/primitives/index.ts +47 -2
  183. package/src/primitives/shared.ts +170 -10
  184. package/src/render/index.ts +77 -39
  185. package/src/renderer/index.ts +76 -14
  186. package/src/services/color-scheme.service.ts +3 -1
  187. package/src/services/window-dimensions.service.ts +11 -4
  188. package/build/angular/modules/animated/animated-leaf-binder/index.d.ts +0 -14
  189. package/build/angular/modules/animated/animated-leaf-binder/index.js +0 -91
  190. package/build/angular/modules/animated/animated-leaf-binder/index.js.map +0 -1
  191. package/src/modules/animated/animated-leaf-binder/index.ts +0 -101
@@ -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"`.
@@ -21,18 +22,35 @@
21
22
  // forwards the Angular Pressable surface verbatim; parity is against that surface, exactly as
22
23
  // React's Touchable parity is against
23
24
  // the React Pressable surface.
24
- import { CUSTOM_ELEMENTS_SCHEMA, ChangeDetectionStrategy, Component, ElementRef, EventEmitter, inject, Input, Output, } 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';
25
+ import { CUSTOM_ELEMENTS_SCHEMA, ChangeDetectionStrategy, Component, computed, ElementRef, EventEmitter, inject, Input, Output, signal, } from '@angular/core';
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 } from '../../primitives';
28
+ import { anchorHostStyle, anchorStyleProp, SymbioteStyleInputDirective, } from '../../primitives';
28
29
  import { Pressable } from '../pressable';
29
30
  import { Animated, AnimatedView } from '../../modules/animated';
30
31
  import * as i0 from "@angular/core";
31
- // The real setTimeout the shared feedback machine schedules its deferred activation/deactivation on
32
- // (core/components has no timer globals). Returns a canceller so an early release flushes the timer.
33
- function scheduleTimeout(callback, ms) {
34
- const id = setTimeout(callback, ms);
35
- return () => clearTimeout(id);
32
+ import * as i1 from "../../primitives/shared";
33
+ function createTimerScheduler() {
34
+ const pending = new Set();
35
+ return {
36
+ schedule(callback, ms) {
37
+ const id = setTimeout(() => {
38
+ pending.delete(cancel);
39
+ callback();
40
+ }, ms);
41
+ const cancel = () => {
42
+ clearTimeout(id);
43
+ pending.delete(cancel);
44
+ };
45
+ pending.add(cancel);
46
+ return cancel;
47
+ },
48
+ cancelAll() {
49
+ for (const cancel of [...pending])
50
+ cancel();
51
+ pending.clear();
52
+ },
53
+ };
36
54
  }
37
55
  export class TouchableOpacity {
38
56
  press = new EventEmitter();
@@ -103,13 +121,20 @@ export class TouchableOpacity {
103
121
  ariaValueText;
104
122
  id;
105
123
  role;
106
- // One Animated.Value per mount, resting at full opacity. Held by IDENTITY as a plain field (an
107
- // engine object, never an @Input / reactive wrap); the <symbiote-animated-view> leaf rasterizes
108
- // it for the first paint and drives it through setNativeProps every frame.
124
+ // One Animated.Value per mount. Held by IDENTITY as a plain field (an engine object, never an
125
+ // @Input / reactive wrap); the <symbiote-animated-view> leaf rasterizes it for the first paint
126
+ // and drives it through setNativeProps every frame.
127
+ //
128
+ // RN seeds it from _getChildStyleOpacityWithDefault(props.style). Angular writes @Input()s AFTER
129
+ // the field initializers run, so `style` is still undefined here — the real resting value is
130
+ // seeded by the first ngOnChanges below, which still precedes the first template pass.
109
131
  opacity = new Animated.Value(RESTING_OPACITY);
110
132
  // The shared press-scheduling cell (delayPressIn timer + activation clock), persisted on the
111
133
  // instance; the machine's handlers are rebuilt per event over live @Input()s.
112
134
  runtime = createTouchableFeedbackRuntime();
135
+ timers = createTimerScheduler();
136
+ // What the last settle ran for. Undefined until the first ngOnChanges, which is the MOUNT.
137
+ settled;
113
138
  // This component's OWN host — the non-painting anchor `class="..."` at the use site resolves
114
139
  // onto (see anchorHostStyle's doc comment) — NOT the <symbiote-animated-view> leaf one level down.
115
140
  elementRef = inject(ElementRef);
@@ -118,14 +143,57 @@ export class TouchableOpacity {
118
143
  // the commit layer flattens). `unknown` because the array mixes a plain style with an
119
144
  // AnimatedNode, exactly the bag AnimatedView's `style` input accepts.
120
145
  get animatedStyle() {
121
- return [anchorHostStyle(this.elementRef), this.style, { opacity: this.opacity }];
146
+ return [this.anchorStyle(), this.style, { opacity: this.opacity }];
147
+ }
148
+ // The anchor's class-derived style is written by the renderer's addClass/removeClass at the USE
149
+ // SITE - it never appears in SimpleChanges, and nothing about it dirties THIS component's view.
150
+ // A `class=` present at creation therefore worked, while one toggled later did not: the parent
151
+ // refreshed, the class landed on the anchor, and this component's own view was never refreshed,
152
+ // so whatever merged the anchor style in was never re-evaluated. Polling it into a signal from
153
+ // ngDoCheck fixes both halves: ngDoCheck runs during the PARENT's refresh even when this view is
154
+ // skipped, and the signal write is what then marks this view for refresh. `signal.set`'s own
155
+ // Object.is makes an unchanged poll a no-op, so there is no loop.
156
+ anchorStyle = signal(undefined, /* @ts-ignore */
157
+ ...(ngDevMode ? [{ debugName: "anchorStyle" }] : /* istanbul ignore next */ []));
158
+ ngDoCheck() {
159
+ this.anchorStyle.set(anchorHostStyle(this.elementRef));
160
+ }
161
+ // RN's componentDidUpdate: a changed `disabled` or a changed style opacity re-settles the view,
162
+ // so a Touchable disabled mid-press does not stay stuck at its active opacity. The FIRST call is
163
+ // the mount (ngOnChanges runs before ngOnInit and before the first template pass), so it seeds
164
+ // the Value instead of animating — RN does this on update only, and a fade at mount would animate
165
+ // away from the value the leaf is about to paint. A use site with no bindings gets no ngOnChanges
166
+ // at all, and there the RESTING_OPACITY seed is already the right answer.
167
+ ngOnChanges() {
168
+ const settled = { disabled: this.disabled, resting: this.restingOpacity() };
169
+ if (this.settled === undefined) {
170
+ this.opacity.setValue(settled.resting);
171
+ }
172
+ else if (this.settled.disabled !== settled.disabled ||
173
+ this.settled.resting !== settled.resting) {
174
+ this.setOpacityTo(settled.resting, OPACITY_INACTIVE_DURATION_MS);
175
+ }
176
+ this.settled = settled;
177
+ }
178
+ // RN's componentWillUnmount: stop the animation so a teardown mid-fade leaves no driver running
179
+ // against a node that is gone, and drop any press-out still deferred behind a timer.
180
+ ngOnDestroy() {
181
+ this.timers.cancelAll();
182
+ this.opacity.resetAnimation();
183
+ }
184
+ // RN's _getChildStyleOpacityWithDefault: the fade settles at the opacity the CALLER's style asks
185
+ // for, not at a hard 1 — a Touchable styled `opacity: 0.6` must come back to 0.6.
186
+ restingOpacity() {
187
+ return restingOpacityFromStyle(this.style);
122
188
  }
123
189
  setOpacityTo(toValue, duration) {
124
190
  Animated.timing(this.opacity, {
125
191
  toValue,
126
192
  duration,
127
193
  easing: Animated.Easing.inOut(Animated.Easing.quad),
128
- useNativeDriver: false,
194
+ // RN's own (TouchableOpacity.js:242). opacity is natively drivable, so the fade survives a
195
+ // busy JS thread — which is the entire point of press feedback.
196
+ useNativeDriver: true,
129
197
  }).start();
130
198
  }
131
199
  // Built per event so the machine reads live @Input()s (delay/opacity); the runtime persists across
@@ -135,16 +203,18 @@ export class TouchableOpacity {
135
203
  return createTouchableFeedbackHandlers({
136
204
  delayPressIn: this.delayPressIn ?? 0,
137
205
  delayPressOut: this.delayPressOut ?? 0,
138
- minPressDuration: this.minPressDuration ?? DEFAULT_MIN_PRESS_DURATION_MS,
139
- schedule: scheduleTimeout,
206
+ // RN's Touchables override Pressability's own 130ms floor with 0; what holds the active
207
+ // visual there is the fade's own duration, not a press-duration floor.
208
+ minPressDuration: this.minPressDuration ?? TOUCHABLE_MIN_PRESS_DURATION_MS,
209
+ schedule: this.timers.schedule,
140
210
  now: Date.now,
141
211
  }, this.runtime, {
142
212
  activate: (event) => {
143
- this.setOpacityTo(this.activeOpacity ?? DEFAULT_ACTIVE_OPACITY, OPACITY_ACTIVE_DURATION_MS);
213
+ this.setOpacityTo(this.activeOpacity ?? DEFAULT_ACTIVE_OPACITY, OPACITY_ACTIVE_GRANT_DURATION_MS);
144
214
  this.pressIn.emit(event);
145
215
  },
146
216
  deactivate: (event) => {
147
- this.setOpacityTo(RESTING_OPACITY, OPACITY_INACTIVE_DURATION_MS);
217
+ this.setOpacityTo(this.restingOpacity(), OPACITY_INACTIVE_DURATION_MS);
148
218
  this.pressOut.emit(event);
149
219
  },
150
220
  });
@@ -157,8 +227,8 @@ export class TouchableOpacity {
157
227
  handlePressOut = (event) => {
158
228
  this.feedbackHandlers().handlePressOut(event);
159
229
  };
160
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: TouchableOpacity, deps: [], target: i0.ɵɵFactoryTarget.Component });
161
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "22.0.5", 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" }, ngImport: i0, template: `
230
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: TouchableOpacity, deps: [], target: i0.ɵɵFactoryTarget.Component });
231
+ 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: `
162
232
  <Pressable
163
233
  (press)="press.emit($event)"
164
234
  (pressIn)="handlePressIn($event)"
@@ -200,8 +270,12 @@ export class TouchableOpacity {
200
270
  [accessibilityElementsHidden]="accessibilityElementsHidden"
201
271
  [accessibilityIgnoresInvertColors]="accessibilityIgnoresInvertColors"
202
272
  [accessibilityLanguage]="accessibilityLanguage"
203
- [accessibilityRespondsToUserInteraction]="accessibilityRespondsToUserInteraction"
204
- [accessibilityShowsLargeContentViewer]="accessibilityShowsLargeContentViewer"
273
+ [accessibilityRespondsToUserInteraction]="
274
+ accessibilityRespondsToUserInteraction
275
+ "
276
+ [accessibilityShowsLargeContentViewer]="
277
+ accessibilityShowsLargeContentViewer
278
+ "
205
279
  [accessibilityLargeContentTitle]="accessibilityLargeContentTitle"
206
280
  (accessibilityAction)="accessibilityAction.emit($event)"
207
281
  (accessibilityTap)="accessibilityTap.emit($event)"
@@ -230,11 +304,14 @@ export class TouchableOpacity {
230
304
  </Pressable>
231
305
  `, 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 });
232
306
  }
233
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: TouchableOpacity, decorators: [{
307
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: TouchableOpacity, decorators: [{
234
308
  type: Component,
235
309
  args: [{
236
310
  selector: 'TouchableOpacity',
237
311
  standalone: true,
312
+ hostDirectives: [
313
+ { directive: SymbioteStyleInputDirective, inputs: ['style'] },
314
+ ],
238
315
  schemas: [CUSTOM_ELEMENTS_SCHEMA],
239
316
  imports: [Pressable, AnimatedView],
240
317
  changeDetection: ChangeDetectionStrategy.OnPush,
@@ -280,8 +357,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.5", ngImpor
280
357
  [accessibilityElementsHidden]="accessibilityElementsHidden"
281
358
  [accessibilityIgnoresInvertColors]="accessibilityIgnoresInvertColors"
282
359
  [accessibilityLanguage]="accessibilityLanguage"
283
- [accessibilityRespondsToUserInteraction]="accessibilityRespondsToUserInteraction"
284
- [accessibilityShowsLargeContentViewer]="accessibilityShowsLargeContentViewer"
360
+ [accessibilityRespondsToUserInteraction]="
361
+ accessibilityRespondsToUserInteraction
362
+ "
363
+ [accessibilityShowsLargeContentViewer]="
364
+ accessibilityShowsLargeContentViewer
365
+ "
285
366
  [accessibilityLargeContentTitle]="accessibilityLargeContentTitle"
286
367
  (accessibilityAction)="accessibilityAction.emit($event)"
287
368
  (accessibilityTap)="accessibilityTap.emit($event)"
@@ -459,6 +540,9 @@ export class TouchableHighlight {
459
540
  accessibilityTap = new EventEmitter();
460
541
  magicTap = new EventEmitter();
461
542
  accessibilityEscape = new EventEmitter();
543
+ // RN's onShowUnderlay / onHideUnderlay — fired on a real transition only, never on a repeat.
544
+ showUnderlay = new EventEmitter();
545
+ hideUnderlay = new EventEmitter();
462
546
  activeOpacity;
463
547
  underlayColor;
464
548
  delayPressIn;
@@ -520,23 +604,110 @@ export class TouchableHighlight {
520
604
  // This component's OWN host — the non-painting anchor `class="..."` at the use site resolves
521
605
  // onto (see anchorHostStyle's doc comment) — NOT the Pressable one level down.
522
606
  elementRef = inject(ElementRef);
523
- // Pressable accepts a style-as-function and calls it with the live pressed state. Arrow field so
524
- // `this` stays bound when Pressable invokes it; it reads the inputs LIVE at call time. The
525
- // anchor's class-derived style goes first, then the user's explicit style, so an explicit
526
- // [style] still beats the ambient class. When pressed, paint the underlay color + lower the
527
- // child opacity (RN drives this with setState, not Animated, so we mirror that faithfully
528
- // through Pressable's pressed flag, no tween) the overlay always goes last so it wins.
529
- pressedStyle = (state) => {
530
- const base = [anchorStyleProp(this.elementRef), this.style];
531
- return highlightPressedStyle(state.pressed, base, this.underlayColor ?? DEFAULT_UNDERLAY_COLOR, this.activeOpacity ?? DEFAULT_HIGHLIGHT_CHILD_OPACITY);
532
- };
533
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: TouchableHighlight, deps: [], target: i0.ɵɵFactoryTarget.Component });
534
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "22.0.5", 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" }, ngImport: i0, template: `
607
+ // `shown` is NOT Pressable's `pressed`. RN holds the underlay for delayPressOut past the tap so a
608
+ // press too fast to see still flashes, and the pressed flag is already false by then. A SIGNAL,
609
+ // because the hide fires from a timer outside any Angular listener, so under zoneless CD
610
+ // nothing else would mark this view. A signal write both notifies the change-detection scheduler
611
+ // (markAncestorsForTraversal) and dirties this template's own reactive consumer, which is the one
612
+ // thing honored in Targeted mode; markForCheck from a plain field would not be reachable here.
613
+ shown = signal(false, /* @ts-ignore */
614
+ ...(ngDevMode ? [{ debugName: "shown" }] : /* istanbul ignore next */ []));
615
+ underlayRuntime = createHighlightUnderlayRuntime();
616
+ timers = createTimerScheduler();
617
+ // The container style Pressable paints.
618
+ //
619
+ // POINT-7 DECISION — both halves stay on the CONTAINER, deliberately. RN's _createExtraStyles
620
+ // keeps them apart: `underlay` (the backgroundColor) on the container, `child` (the lowered
621
+ // opacity) cloned onto the single child. Angular has no cloneElement and no way to reach a
622
+ // projected <ng-content> node, so the only path to the child is a permanent wrapper View — which
623
+ // inserts a node into the flex chain and silently re-parents any `flex` a child declares. The
624
+ // fake Fabric runs no Yoga, so no headless test can measure that damage, only assert the extra
625
+ // node exists; shipping an unmeasurable layout change is worse than the visual approximation.
626
+ // Same call, same reason, as the Solid adapter. resolveHighlightExtraStyles keeps the two styles
627
+ // SEPARATE regardless, so a layout-safe fix (which needs a device check, not a test) stays open.
628
+ //
629
+ // Returns a NEW ARRAY whenever a dependency moves: Pressable's `style` @Input then reports an
630
+ // ordinary change. A stable reference was the earlier bug — Pressable's view never refreshed, so
631
+ // a class or [style] toggled after mount never reached the committed view.
632
+ containerStyle = computed(() => {
633
+ this.inputsRevision();
634
+ const base = [this.anchorStyle(), this.style];
635
+ const extra = resolveHighlightExtraStyles({
636
+ shown: this.shown(),
637
+ hasPressHandler: this.hasPressHandler(),
638
+ underlayColor: this.underlayColor,
639
+ activeOpacity: this.activeOpacity,
640
+ });
641
+ return extra === undefined ? base : [base, extra.underlay, extra.child];
642
+ }, /* @ts-ignore */
643
+ ...(ngDevMode ? [{ debugName: "containerStyle" }] : /* istanbul ignore next */ []));
644
+ // RN's _hasPressHandler: a Touchable that handles no press paints no underlay. Angular exposes
645
+ // the press lifecycle as @Output()s, so "a handler is present" is "something is subscribed" — the
646
+ // same `.observed` test Pressable uses to decide whether to arm its long-press timer at all.
647
+ hasPressHandler() {
648
+ return hasTouchablePressHandler({
649
+ onPress: this.press.observed ? this.press : undefined,
650
+ onPressIn: this.pressIn.observed ? this.pressIn : undefined,
651
+ onPressOut: this.pressOut.observed ? this.pressOut : undefined,
652
+ onLongPress: this.longPress.observed ? this.longPress : undefined,
653
+ });
654
+ }
655
+ // Built per event so the machine reads live @Input()s (delayPressOut, the has-handler gate); the
656
+ // runtime persists across calls, which is what lets handlePressOut see the timer handlePress set.
657
+ underlayHandlers() {
658
+ return createHighlightUnderlayHandlers({
659
+ delayPressOut: this.delayPressOut ?? 0,
660
+ hasPressHandler: this.hasPressHandler(),
661
+ schedule: this.timers.schedule,
662
+ }, this.underlayRuntime, {
663
+ setShown: (shown) => this.shown.set(shown),
664
+ onShowUnderlay: () => this.showUnderlay.emit(),
665
+ onHideUnderlay: () => this.hideUnderlay.emit(),
666
+ });
667
+ }
668
+ // Visual first, then the caller's own event — RN's order in _createPressabilityConfig.
669
+ // onLongPress is deliberately NOT intercepted (Pressable emits it straight through); it is only
670
+ // READ, by the has-press-handler gate above.
671
+ handlePressIn(event) {
672
+ this.underlayHandlers().handlePressIn(event);
673
+ this.pressIn.emit(event);
674
+ }
675
+ handlePress(event) {
676
+ this.underlayHandlers().handlePress(event);
677
+ this.press.emit(event);
678
+ }
679
+ handlePressOut(event) {
680
+ this.underlayHandlers().handlePressOut(event);
681
+ this.pressOut.emit(event);
682
+ }
683
+ ngOnDestroy() {
684
+ this.timers.cancelAll();
685
+ }
686
+ // `style`, `underlayColor` and `activeOpacity` are read untracked inside containerStyle, so the
687
+ // bump is what tells it they moved. See the ngDoCheck note below for the anchor half, which
688
+ // ngOnChanges cannot cover.
689
+ inputsRevision = signal(0, /* @ts-ignore */
690
+ ...(ngDevMode ? [{ debugName: "inputsRevision" }] : /* istanbul ignore next */ []));
691
+ anchorStyle = signal(undefined, /* @ts-ignore */
692
+ ...(ngDevMode ? [{ debugName: "anchorStyle" }] : /* istanbul ignore next */ []));
693
+ ngOnChanges() {
694
+ this.inputsRevision.update(revision => revision + 1);
695
+ }
696
+ // The anchor's class-derived style is written by the renderer's addClass/removeClass at the USE
697
+ // SITE - it never appears in SimpleChanges, and nothing about it dirties THIS component's view.
698
+ // ngDoCheck runs during the PARENT's refresh even when this view is skipped, and the signal
699
+ // write is what then marks this view for refresh. `signal.set`'s own Object.is makes an
700
+ // unchanged poll a no-op, so there is no loop.
701
+ ngDoCheck() {
702
+ this.anchorStyle.set(anchorStyleProp(this.elementRef));
703
+ }
704
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: TouchableHighlight, deps: [], target: i0.ɵɵFactoryTarget.Component });
705
+ 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: `
535
706
  <Pressable
536
- [style]="pressedStyle"
537
- (press)="press.emit($event)"
538
- (pressIn)="pressIn.emit($event)"
539
- (pressOut)="pressOut.emit($event)"
707
+ [style]="containerStyle()"
708
+ (press)="handlePress($event)"
709
+ (pressIn)="handlePressIn($event)"
710
+ (pressOut)="handlePressOut($event)"
540
711
  (pressMove)="pressMove.emit($event)"
541
712
  (longPress)="longPress.emit($event)"
542
713
  (hoverIn)="hoverIn.emit($event)"
@@ -574,8 +745,12 @@ export class TouchableHighlight {
574
745
  [accessibilityElementsHidden]="accessibilityElementsHidden"
575
746
  [accessibilityIgnoresInvertColors]="accessibilityIgnoresInvertColors"
576
747
  [accessibilityLanguage]="accessibilityLanguage"
577
- [accessibilityRespondsToUserInteraction]="accessibilityRespondsToUserInteraction"
578
- [accessibilityShowsLargeContentViewer]="accessibilityShowsLargeContentViewer"
748
+ [accessibilityRespondsToUserInteraction]="
749
+ accessibilityRespondsToUserInteraction
750
+ "
751
+ [accessibilityShowsLargeContentViewer]="
752
+ accessibilityShowsLargeContentViewer
753
+ "
579
754
  [accessibilityLargeContentTitle]="accessibilityLargeContentTitle"
580
755
  (accessibilityAction)="accessibilityAction.emit($event)"
581
756
  (accessibilityTap)="accessibilityTap.emit($event)"
@@ -602,19 +777,22 @@ export class TouchableHighlight {
602
777
  </Pressable>
603
778
  `, 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 });
604
779
  }
605
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: TouchableHighlight, decorators: [{
780
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: TouchableHighlight, decorators: [{
606
781
  type: Component,
607
782
  args: [{
608
783
  selector: 'TouchableHighlight',
609
784
  standalone: true,
785
+ hostDirectives: [
786
+ { directive: SymbioteStyleInputDirective, inputs: ['style'] },
787
+ ],
610
788
  imports: [Pressable],
611
789
  changeDetection: ChangeDetectionStrategy.OnPush,
612
790
  template: `
613
791
  <Pressable
614
- [style]="pressedStyle"
615
- (press)="press.emit($event)"
616
- (pressIn)="pressIn.emit($event)"
617
- (pressOut)="pressOut.emit($event)"
792
+ [style]="containerStyle()"
793
+ (press)="handlePress($event)"
794
+ (pressIn)="handlePressIn($event)"
795
+ (pressOut)="handlePressOut($event)"
618
796
  (pressMove)="pressMove.emit($event)"
619
797
  (longPress)="longPress.emit($event)"
620
798
  (hoverIn)="hoverIn.emit($event)"
@@ -652,8 +830,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.5", ngImpor
652
830
  [accessibilityElementsHidden]="accessibilityElementsHidden"
653
831
  [accessibilityIgnoresInvertColors]="accessibilityIgnoresInvertColors"
654
832
  [accessibilityLanguage]="accessibilityLanguage"
655
- [accessibilityRespondsToUserInteraction]="accessibilityRespondsToUserInteraction"
656
- [accessibilityShowsLargeContentViewer]="accessibilityShowsLargeContentViewer"
833
+ [accessibilityRespondsToUserInteraction]="
834
+ accessibilityRespondsToUserInteraction
835
+ "
836
+ [accessibilityShowsLargeContentViewer]="
837
+ accessibilityShowsLargeContentViewer
838
+ "
657
839
  [accessibilityLargeContentTitle]="accessibilityLargeContentTitle"
658
840
  (accessibilityAction)="accessibilityAction.emit($event)"
659
841
  (accessibilityTap)="accessibilityTap.emit($event)"
@@ -702,6 +884,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.5", ngImpor
702
884
  type: Output
703
885
  }], accessibilityEscape: [{
704
886
  type: Output
887
+ }], showUnderlay: [{
888
+ type: Output
889
+ }], hideUnderlay: [{
890
+ type: Output
705
891
  }], activeOpacity: [{
706
892
  type: Input
707
893
  }], underlayColor: [{
@@ -820,9 +1006,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.5", ngImpor
820
1006
  type: Input
821
1007
  }] } });
822
1008
  export class TouchableWithoutFeedback {
823
- // delayPressIn/delayPressOut/minPressDuration ride the prop type for surface parity with the
824
- // other two, but TouchableWithoutFeedback has no visual feedback, so nothing schedules off them
825
- // (RN's TouchableWithoutFeedback is the same pure passthrough).
1009
+ // RN's TouchableWithoutFeedback builds a FULL Pressability config with delayPressIn /
1010
+ // delayPressOut / minPressDuration: 0 "without feedback" means no VISUAL, not no timing. So the
1011
+ // same shared machine TouchableOpacity uses runs here, with the visual half left empty: the
1012
+ // pressIn/pressOut EMIT is what gets deferred and floored.
826
1013
  press = new EventEmitter();
827
1014
  pressIn = new EventEmitter();
828
1015
  pressOut = new EventEmitter();
@@ -893,18 +1080,56 @@ export class TouchableWithoutFeedback {
893
1080
  // This component's OWN host — the non-painting anchor `class="..."` at the use site resolves
894
1081
  // onto (see anchorHostStyle's doc comment) — NOT the Pressable one level down.
895
1082
  elementRef = inject(ElementRef);
1083
+ // The shared press-scheduling cell (delayPressIn timer + activation clock), persisted on the
1084
+ // instance; the machine's handlers are rebuilt per event over live @Input()s.
1085
+ runtime = createTouchableFeedbackRuntime();
1086
+ timers = createTimerScheduler();
896
1087
  // The anchor's class-derived style goes first, then the explicit style, so an explicit [style]
897
1088
  // still beats the ambient class.
898
1089
  get mergedStyle() {
899
- return [anchorStyleProp(this.elementRef), this.style];
1090
+ return [this.anchorStyle(), this.style];
900
1091
  }
901
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: TouchableWithoutFeedback, deps: [], target: i0.ɵɵFactoryTarget.Component });
902
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "22.0.5", 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" }, ngImport: i0, template: `
1092
+ feedbackHandlers() {
1093
+ return createTouchableFeedbackHandlers({
1094
+ delayPressIn: this.delayPressIn ?? 0,
1095
+ delayPressOut: this.delayPressOut ?? 0,
1096
+ minPressDuration: this.minPressDuration ?? TOUCHABLE_MIN_PRESS_DURATION_MS,
1097
+ schedule: this.timers.schedule,
1098
+ now: Date.now,
1099
+ }, this.runtime, {
1100
+ activate: (event) => this.pressIn.emit(event),
1101
+ deactivate: (event) => this.pressOut.emit(event),
1102
+ });
1103
+ }
1104
+ handlePressIn(event) {
1105
+ this.feedbackHandlers().handlePressIn(event);
1106
+ }
1107
+ handlePressOut(event) {
1108
+ this.feedbackHandlers().handlePressOut(event);
1109
+ }
1110
+ ngOnDestroy() {
1111
+ this.timers.cancelAll();
1112
+ }
1113
+ // The anchor's class-derived style is written by the renderer's addClass/removeClass at the USE
1114
+ // SITE - it never appears in SimpleChanges, and nothing about it dirties THIS component's view.
1115
+ // A `class=` present at creation therefore worked, while one toggled later did not: the parent
1116
+ // refreshed, the class landed on the anchor, and this component's own view was never refreshed,
1117
+ // so whatever merged the anchor style in was never re-evaluated. Polling it into a signal from
1118
+ // ngDoCheck fixes both halves: ngDoCheck runs during the PARENT's refresh even when this view is
1119
+ // skipped, and the signal write is what then marks this view for refresh. `signal.set`'s own
1120
+ // Object.is makes an unchanged poll a no-op, so there is no loop.
1121
+ anchorStyle = signal(undefined, /* @ts-ignore */
1122
+ ...(ngDevMode ? [{ debugName: "anchorStyle" }] : /* istanbul ignore next */ []));
1123
+ ngDoCheck() {
1124
+ this.anchorStyle.set(anchorStyleProp(this.elementRef));
1125
+ }
1126
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: TouchableWithoutFeedback, deps: [], target: i0.ɵɵFactoryTarget.Component });
1127
+ 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: `
903
1128
  <Pressable
904
1129
  [style]="mergedStyle"
905
1130
  (press)="press.emit($event)"
906
- (pressIn)="pressIn.emit($event)"
907
- (pressOut)="pressOut.emit($event)"
1131
+ (pressIn)="handlePressIn($event)"
1132
+ (pressOut)="handlePressOut($event)"
908
1133
  (pressMove)="pressMove.emit($event)"
909
1134
  (longPress)="longPress.emit($event)"
910
1135
  (hoverIn)="hoverIn.emit($event)"
@@ -942,8 +1167,12 @@ export class TouchableWithoutFeedback {
942
1167
  [accessibilityElementsHidden]="accessibilityElementsHidden"
943
1168
  [accessibilityIgnoresInvertColors]="accessibilityIgnoresInvertColors"
944
1169
  [accessibilityLanguage]="accessibilityLanguage"
945
- [accessibilityRespondsToUserInteraction]="accessibilityRespondsToUserInteraction"
946
- [accessibilityShowsLargeContentViewer]="accessibilityShowsLargeContentViewer"
1170
+ [accessibilityRespondsToUserInteraction]="
1171
+ accessibilityRespondsToUserInteraction
1172
+ "
1173
+ [accessibilityShowsLargeContentViewer]="
1174
+ accessibilityShowsLargeContentViewer
1175
+ "
947
1176
  [accessibilityLargeContentTitle]="accessibilityLargeContentTitle"
948
1177
  (accessibilityAction)="accessibilityAction.emit($event)"
949
1178
  (accessibilityTap)="accessibilityTap.emit($event)"
@@ -970,19 +1199,22 @@ export class TouchableWithoutFeedback {
970
1199
  </Pressable>
971
1200
  `, 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 });
972
1201
  }
973
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: TouchableWithoutFeedback, decorators: [{
1202
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: TouchableWithoutFeedback, decorators: [{
974
1203
  type: Component,
975
1204
  args: [{
976
1205
  selector: 'TouchableWithoutFeedback',
977
1206
  standalone: true,
1207
+ hostDirectives: [
1208
+ { directive: SymbioteStyleInputDirective, inputs: ['style'] },
1209
+ ],
978
1210
  imports: [Pressable],
979
1211
  changeDetection: ChangeDetectionStrategy.OnPush,
980
1212
  template: `
981
1213
  <Pressable
982
1214
  [style]="mergedStyle"
983
1215
  (press)="press.emit($event)"
984
- (pressIn)="pressIn.emit($event)"
985
- (pressOut)="pressOut.emit($event)"
1216
+ (pressIn)="handlePressIn($event)"
1217
+ (pressOut)="handlePressOut($event)"
986
1218
  (pressMove)="pressMove.emit($event)"
987
1219
  (longPress)="longPress.emit($event)"
988
1220
  (hoverIn)="hoverIn.emit($event)"
@@ -1020,8 +1252,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.5", ngImpor
1020
1252
  [accessibilityElementsHidden]="accessibilityElementsHidden"
1021
1253
  [accessibilityIgnoresInvertColors]="accessibilityIgnoresInvertColors"
1022
1254
  [accessibilityLanguage]="accessibilityLanguage"
1023
- [accessibilityRespondsToUserInteraction]="accessibilityRespondsToUserInteraction"
1024
- [accessibilityShowsLargeContentViewer]="accessibilityShowsLargeContentViewer"
1255
+ [accessibilityRespondsToUserInteraction]="
1256
+ accessibilityRespondsToUserInteraction
1257
+ "
1258
+ [accessibilityShowsLargeContentViewer]="
1259
+ accessibilityShowsLargeContentViewer
1260
+ "
1025
1261
  [accessibilityLargeContentTitle]="accessibilityLargeContentTitle"
1026
1262
  (accessibilityAction)="accessibilityAction.emit($event)"
1027
1263
  (accessibilityTap)="accessibilityTap.emit($event)"