@symbiote-native/angular 0.8.0 → 2.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 (256) hide show
  1. package/README.md +13 -10
  2. package/babel-register-composed.cjs +58 -18
  3. package/bin/symbiote-angular-dev.cjs +16 -4
  4. package/build/angular/anchor-host-registry.js +1 -15
  5. package/build/angular/anchor-host-registry.js.map +1 -1
  6. package/build/angular/change-detection-flush.d.ts +31 -0
  7. package/build/angular/change-detection-flush.js +110 -0
  8. package/build/angular/change-detection-flush.js.map +1 -0
  9. package/build/angular/components/activity-indicator-props.d.ts +2 -0
  10. package/build/angular/components/activity-indicator-props.js +2 -0
  11. package/build/angular/components/activity-indicator-props.js.map +1 -0
  12. package/build/angular/components/button-props.d.ts +2 -0
  13. package/build/angular/components/button-props.js +2 -0
  14. package/build/angular/components/button-props.js.map +1 -0
  15. package/build/angular/components/flat-list/index.d.ts +2 -1
  16. package/build/angular/components/flat-list/index.js +22 -10
  17. package/build/angular/components/flat-list/index.js.map +1 -1
  18. package/build/angular/components/image-background-props.d.ts +6 -0
  19. package/build/angular/components/image-background-props.js +2 -0
  20. package/build/angular/components/image-background-props.js.map +1 -0
  21. package/build/angular/components/{image/shared.d.ts → image-shared.d.ts} +4 -4
  22. package/build/angular/components/{image/shared.js → image-shared.js} +39 -28
  23. package/build/angular/components/image-shared.js.map +1 -0
  24. package/build/angular/components/input-accessory-view-props.d.ts +7 -0
  25. package/build/angular/components/input-accessory-view-props.js +9 -0
  26. package/build/angular/components/input-accessory-view-props.js.map +1 -0
  27. package/build/angular/components/keyboard-avoiding-view/index.d.ts +2 -1
  28. package/build/angular/components/keyboard-avoiding-view/index.js +28 -27
  29. package/build/angular/components/keyboard-avoiding-view/index.js.map +1 -1
  30. package/build/angular/components/modal/index.d.ts +2 -0
  31. package/build/angular/components/modal/index.js +33 -20
  32. package/build/angular/components/modal/index.js.map +1 -1
  33. package/build/angular/components/pressable-props.d.ts +32 -0
  34. package/build/angular/components/pressable-props.js +11 -0
  35. package/build/angular/components/pressable-props.js.map +1 -0
  36. package/build/angular/components/refresh-control-props.d.ts +16 -0
  37. package/build/angular/components/refresh-control-props.js +14 -0
  38. package/build/angular/components/refresh-control-props.js.map +1 -0
  39. package/build/angular/components/safe-area-view-props.d.ts +7 -0
  40. package/build/angular/components/safe-area-view-props.js +11 -0
  41. package/build/angular/components/safe-area-view-props.js.map +1 -0
  42. package/build/angular/components/scroll-view-props.d.ts +76 -0
  43. package/build/angular/components/scroll-view-props.js +18 -0
  44. package/build/angular/components/scroll-view-props.js.map +1 -0
  45. package/build/angular/components/section-list/index.d.ts +3 -0
  46. package/build/angular/components/section-list/index.js +10 -1
  47. package/build/angular/components/section-list/index.js.map +1 -1
  48. package/build/angular/components/text-input-props.d.ts +45 -0
  49. package/build/angular/components/text-input-props.js +18 -0
  50. package/build/angular/components/text-input-props.js.map +1 -0
  51. package/build/angular/components/touchable-native-feedback/touchable-native-feedback-props.d.ts +6 -0
  52. package/build/angular/components/touchable-native-feedback/touchable-native-feedback-props.js +2 -0
  53. package/build/angular/components/touchable-native-feedback/touchable-native-feedback-props.js.map +1 -0
  54. package/build/angular/components/touchable-props.d.ts +14 -0
  55. package/build/angular/components/touchable-props.js +13 -0
  56. package/build/angular/components/touchable-props.js.map +1 -0
  57. package/build/angular/components/touchable-without-feedback/touchable-without-feedback-props.d.ts +3 -0
  58. package/build/angular/components/touchable-without-feedback/touchable-without-feedback-props.js +2 -0
  59. package/build/angular/components/touchable-without-feedback/touchable-without-feedback-props.js.map +1 -0
  60. package/build/angular/components/virtualized-list/index.d.ts +8 -1
  61. package/build/angular/components/virtualized-list/index.js +373 -278
  62. package/build/angular/components/virtualized-list/index.js.map +1 -1
  63. package/build/angular/components/virtualized-section-list/index.d.ts +3 -0
  64. package/build/angular/components/virtualized-section-list/index.js +10 -1
  65. package/build/angular/components/virtualized-section-list/index.js.map +1 -1
  66. package/build/angular/components.d.ts +21 -27
  67. package/build/angular/components.js +13 -15
  68. package/build/angular/components.js.map +1 -1
  69. package/build/angular/create-portal/index.d.ts +11 -2
  70. package/build/angular/create-portal/index.js +37 -11
  71. package/build/angular/create-portal/index.js.map +1 -1
  72. package/build/angular/create-tunnel/index.js +1 -1
  73. package/build/angular/element-props.d.ts +53 -0
  74. package/build/angular/element-props.js +2 -0
  75. package/build/angular/element-props.js.map +1 -0
  76. package/build/angular/elements.d.ts +528 -0
  77. package/build/angular/elements.js +1444 -0
  78. package/build/angular/elements.js.map +1 -0
  79. package/build/angular/gate-demand.d.ts +37 -0
  80. package/build/angular/gate-demand.js +84 -0
  81. package/build/angular/gate-demand.js.map +1 -0
  82. package/build/angular/host-instance/index.js +1 -1
  83. package/build/angular/index.d.ts +5 -2
  84. package/build/angular/index.js +16 -1
  85. package/build/angular/index.js.map +1 -1
  86. package/build/angular/modules/animated/create-animated-component.d.ts +6 -6
  87. package/build/angular/modules/animated/create-animated-component.js +73 -81
  88. package/build/angular/modules/animated/create-animated-component.js.map +1 -1
  89. package/build/angular/modules/animated/index.js +1 -1
  90. package/build/angular/modules/animated/index.js.map +1 -1
  91. package/build/angular/modules/image/index.d.ts +3 -0
  92. package/build/angular/modules/image/index.js +16 -0
  93. package/build/angular/modules/image/index.js.map +1 -0
  94. package/build/angular/primitives/index.d.ts +28 -16
  95. package/build/angular/primitives/index.js +77 -31
  96. package/build/angular/primitives/index.js.map +1 -1
  97. package/build/angular/primitives/shared.d.ts +2 -3
  98. package/build/angular/primitives/shared.js +8 -53
  99. package/build/angular/primitives/shared.js.map +1 -1
  100. package/build/angular/register.d.ts +1 -0
  101. package/build/angular/register.js +16 -0
  102. package/build/angular/register.js.map +1 -0
  103. package/build/angular/render/index.js +4 -2
  104. package/build/angular/render/index.js.map +1 -1
  105. package/build/angular/renderer/index.js +207 -60
  106. package/build/angular/renderer/index.js.map +1 -1
  107. package/build/angular/renderer/value-change.d.ts +2 -0
  108. package/build/angular/renderer/value-change.js +9 -0
  109. package/build/angular/renderer/value-change.js.map +1 -0
  110. package/metro-config.cjs +23 -5
  111. package/metro-css-parser.cjs +2 -1
  112. package/package.json +17 -7
  113. package/src/anchor-host-registry.ts +1 -15
  114. package/src/change-detection-flush.ts +120 -0
  115. package/src/components/activity-indicator-props.ts +21 -0
  116. package/src/components/button-props.ts +26 -0
  117. package/src/components/flat-list/index.ts +12 -4
  118. package/src/components/image-background-props.ts +24 -0
  119. package/src/components/{image/shared.ts → image-shared.ts} +57 -26
  120. package/src/components/input-accessory-view-props.ts +21 -0
  121. package/src/components/keyboard-avoiding-view/index.ts +27 -16
  122. package/src/components/modal/index.ts +32 -11
  123. package/src/components/pressable-props.ts +73 -0
  124. package/src/components/refresh-control-props.ts +43 -0
  125. package/src/components/safe-area-view-props.ts +28 -0
  126. package/src/components/scroll-view-props.ts +109 -0
  127. package/src/components/section-list/index.ts +18 -0
  128. package/src/components/text-input-props.ts +72 -0
  129. package/src/components/touchable-native-feedback/touchable-native-feedback-props.ts +23 -0
  130. package/src/components/touchable-props.ts +30 -0
  131. package/src/components/touchable-without-feedback/touchable-without-feedback-props.ts +21 -0
  132. package/src/components/virtualized-list/index.ts +254 -153
  133. package/src/components/virtualized-section-list/index.ts +18 -0
  134. package/src/components.ts +86 -35
  135. package/src/create-portal/index.ts +39 -9
  136. package/src/create-tunnel/index.ts +1 -1
  137. package/src/diagnostics.ts +1 -1
  138. package/src/element-props.ts +90 -0
  139. package/src/elements.ts +919 -0
  140. package/src/gate-demand.ts +109 -0
  141. package/src/host-instance/index.ts +1 -1
  142. package/src/index.ts +54 -15
  143. package/src/modules/animated/create-animated-component.ts +73 -59
  144. package/src/modules/animated/index.ts +1 -1
  145. package/src/modules/image/index.ts +18 -0
  146. package/src/primitives/index.ts +47 -16
  147. package/src/primitives/shared.ts +11 -44
  148. package/src/register.ts +15 -0
  149. package/src/render/index.ts +4 -2
  150. package/src/renderer/index.ts +239 -80
  151. package/src/renderer/value-change.ts +8 -0
  152. package/build/angular/components/activity-indicator/index.android.d.ts +0 -13
  153. package/build/angular/components/activity-indicator/index.android.js +0 -29
  154. package/build/angular/components/activity-indicator/index.android.js.map +0 -1
  155. package/build/angular/components/activity-indicator/index.d.ts +0 -1
  156. package/build/angular/components/activity-indicator/index.ios.d.ts +0 -9
  157. package/build/angular/components/activity-indicator/index.ios.js +0 -26
  158. package/build/angular/components/activity-indicator/index.ios.js.map +0 -1
  159. package/build/angular/components/activity-indicator/index.js +0 -4
  160. package/build/angular/components/activity-indicator/index.js.map +0 -1
  161. package/build/angular/components/activity-indicator/shared.d.ts +0 -67
  162. package/build/angular/components/activity-indicator/shared.js +0 -260
  163. package/build/angular/components/activity-indicator/shared.js.map +0 -1
  164. package/build/angular/components/button.d.ts +0 -65
  165. package/build/angular/components/button.js +0 -351
  166. package/build/angular/components/button.js.map +0 -1
  167. package/build/angular/components/image/index.android.d.ts +0 -15
  168. package/build/angular/components/image/index.android.js +0 -91
  169. package/build/angular/components/image/index.android.js.map +0 -1
  170. package/build/angular/components/image/index.d.ts +0 -1
  171. package/build/angular/components/image/index.ios.d.ts +0 -15
  172. package/build/angular/components/image/index.ios.js +0 -91
  173. package/build/angular/components/image/index.ios.js.map +0 -1
  174. package/build/angular/components/image/index.js +0 -3
  175. package/build/angular/components/image/index.js.map +0 -1
  176. package/build/angular/components/image/shared.js.map +0 -1
  177. package/build/angular/components/image-background.d.ts +0 -82
  178. package/build/angular/components/image-background.js +0 -434
  179. package/build/angular/components/image-background.js.map +0 -1
  180. package/build/angular/components/input-accessory-view/index.d.ts +0 -65
  181. package/build/angular/components/input-accessory-view/index.js +0 -290
  182. package/build/angular/components/input-accessory-view/index.js.map +0 -1
  183. package/build/angular/components/pressable/index.d.ts +0 -129
  184. package/build/angular/components/pressable/index.js +0 -473
  185. package/build/angular/components/pressable/index.js.map +0 -1
  186. package/build/angular/components/refresh-control/index.d.ts +0 -90
  187. package/build/angular/components/refresh-control/index.js +0 -380
  188. package/build/angular/components/refresh-control/index.js.map +0 -1
  189. package/build/angular/components/safe-area-view/index.d.ts +0 -62
  190. package/build/angular/components/safe-area-view/index.js +0 -287
  191. package/build/angular/components/safe-area-view/index.js.map +0 -1
  192. package/build/angular/components/scroll-view/index.android.d.ts +0 -20
  193. package/build/angular/components/scroll-view/index.android.js +0 -262
  194. package/build/angular/components/scroll-view/index.android.js.map +0 -1
  195. package/build/angular/components/scroll-view/index.d.ts +0 -3
  196. package/build/angular/components/scroll-view/index.ios.d.ts +0 -8
  197. package/build/angular/components/scroll-view/index.ios.js +0 -92
  198. package/build/angular/components/scroll-view/index.ios.js.map +0 -1
  199. package/build/angular/components/scroll-view/index.js +0 -6
  200. package/build/angular/components/scroll-view/index.js.map +0 -1
  201. package/build/angular/components/scroll-view/projection.d.ts +0 -67
  202. package/build/angular/components/scroll-view/projection.js +0 -560
  203. package/build/angular/components/scroll-view/projection.js.map +0 -1
  204. package/build/angular/components/scroll-view/shared.d.ts +0 -239
  205. package/build/angular/components/scroll-view/shared.js +0 -832
  206. package/build/angular/components/scroll-view/shared.js.map +0 -1
  207. package/build/angular/components/scroll-view/sticky-header.d.ts +0 -40
  208. package/build/angular/components/scroll-view/sticky-header.js +0 -224
  209. package/build/angular/components/scroll-view/sticky-header.js.map +0 -1
  210. package/build/angular/components/switch/index.android.d.ts +0 -24
  211. package/build/angular/components/switch/index.android.js +0 -112
  212. package/build/angular/components/switch/index.android.js.map +0 -1
  213. package/build/angular/components/switch/index.d.ts +0 -1
  214. package/build/angular/components/switch/index.ios.d.ts +0 -23
  215. package/build/angular/components/switch/index.ios.js +0 -111
  216. package/build/angular/components/switch/index.ios.js.map +0 -1
  217. package/build/angular/components/switch/index.js +0 -4
  218. package/build/angular/components/switch/index.js.map +0 -1
  219. package/build/angular/components/switch/shared.d.ts +0 -49
  220. package/build/angular/components/switch/shared.js +0 -191
  221. package/build/angular/components/switch/shared.js.map +0 -1
  222. package/build/angular/components/text-input.d.ts +0 -161
  223. package/build/angular/components/text-input.js +0 -659
  224. package/build/angular/components/text-input.js.map +0 -1
  225. package/build/angular/components/touchable/index.d.ts +0 -276
  226. package/build/angular/components/touchable/index.js +0 -1422
  227. package/build/angular/components/touchable/index.js.map +0 -1
  228. package/build/angular/components/touchable-native-feedback/index.d.ts +0 -86
  229. package/build/angular/components/touchable-native-feedback/index.js +0 -407
  230. package/build/angular/components/touchable-native-feedback/index.js.map +0 -1
  231. package/src/components/activity-indicator/index.android.ts +0 -23
  232. package/src/components/activity-indicator/index.ios.ts +0 -21
  233. package/src/components/activity-indicator/index.ts +0 -4
  234. package/src/components/activity-indicator/shared.ts +0 -225
  235. package/src/components/button.ts +0 -220
  236. package/src/components/image/index.android.ts +0 -99
  237. package/src/components/image/index.ios.ts +0 -99
  238. package/src/components/image/index.ts +0 -3
  239. package/src/components/image-background.ts +0 -290
  240. package/src/components/input-accessory-view/index.ts +0 -240
  241. package/src/components/pressable/index.ts +0 -462
  242. package/src/components/refresh-control/index.ts +0 -340
  243. package/src/components/safe-area-view/index.ts +0 -231
  244. package/src/components/scroll-view/index.android.ts +0 -205
  245. package/src/components/scroll-view/index.ios.ts +0 -81
  246. package/src/components/scroll-view/index.ts +0 -7
  247. package/src/components/scroll-view/projection.ts +0 -713
  248. package/src/components/scroll-view/shared.ts +0 -1066
  249. package/src/components/scroll-view/sticky-header.ts +0 -267
  250. package/src/components/switch/index.android.ts +0 -113
  251. package/src/components/switch/index.ios.ts +0 -112
  252. package/src/components/switch/index.ts +0 -4
  253. package/src/components/switch/shared.ts +0 -284
  254. package/src/components/text-input.ts +0 -613
  255. package/src/components/touchable/index.ts +0 -913
  256. package/src/components/touchable-native-feedback/index.ts +0 -317
@@ -1,267 +0,0 @@
1
- // Sticky headers: RN does stickiness PURELY IN JS (ScrollView.js / ScrollViewStickyHeader.js).
2
- // A single `_scrollAnimatedValue` an Animated.event drives from `onScroll` feeds each flagged
3
- // header's translateY through an interpolation that pins it to the top (or bottom, inverted)
4
- // until the next header collides with it — the native Fabric scroll view does NOT honor
5
- // `stickyHeaderIndices` on its own. The interpolation math (computeStickyInterpolation) lives
6
- // framework-agnostic in @symbiote-native/components, shared verbatim with React/Vue; this file
7
- // holds the Angular component shell, layout state, and interpolation build.
8
- //
9
- // This is the public sticky-header WRAPPER for explicit composition. ScrollView also auto-wraps
10
- // projected children named by stickyHeaderIndices through its projection bridge (projection.ts),
11
- // because Angular templates cannot map <ng-content> children directly; that auto path
12
- // intentionally reuses this built-in wrapper rather than instantiating arbitrary component types.
13
-
14
- import {
15
- ChangeDetectionStrategy,
16
- ChangeDetectorRef,
17
- Component,
18
- ElementRef,
19
- EventEmitter,
20
- Input,
21
- Output,
22
- inject,
23
- type OnChanges,
24
- type OnDestroy,
25
- type OnInit,
26
- } from '@angular/core';
27
- import {
28
- type AnimatedInterpolation,
29
- AnimatedValue,
30
- Platform,
31
- dlog,
32
- type ISymbioteEvent,
33
- } from '@symbiote-native/engine';
34
- import {
35
- createInitialStickyState,
36
- readLayoutNumber,
37
- reduceSticky,
38
- STICKY_HEADER_Z_INDEX,
39
- type IStickyAction,
40
- type IStickyEffect,
41
- type IStickyHeaderProps,
42
- type IStickyReducerInputs,
43
- } from '@symbiote-native/components';
44
- import { AnimatedView } from '../../modules/animated';
45
- import { anchorHostStyle } from '../../primitives';
46
-
47
- // A custom sticky wrapper must accept the same shape the built-in does: the IStickyHeaderProps
48
- // fields as inputs + the wrapped child via <ng-content>. Unlike React/Vue, Angular ScrollView cannot
49
- // AOT-safely instantiate an arbitrary component Type while auto-projecting stickyHeaderIndices,
50
- // because that renderer-level bridge only sees committed engine nodes, not a ViewContainerRef with
51
- // Angular projectable nodes. This type remains public for explicit composition: compose your wrapper
52
- // around <ScrollViewStickyHeader>/<symbiote-sticky-header> in the template when custom visuals are
53
- // needed. Auto projection intentionally uses the built-in wrapper.
54
- export type IStickyHeaderComponentType = unknown;
55
-
56
- // One sticky header. Measures its own y/height via onLayout, interpolates the shared scroll offset
57
- // into a translateY that keeps it pinned to the top (or bottom, inverted) until the next header
58
- // collides with it, and drives that translate through the native driver when available so the pin
59
- // tracks scroll on the UI thread (no JS jitter). Ported from ScrollViewStickyHeader.js, including
60
- // the Fabric ShadowTree debounce path. The inputs (scrollAnimatedValue/nextHeaderLayoutY/…) never
61
- // reach the host node: they configure the interpolation; only the resolved transform reaches
62
- // AnimatedView (a scrollAnimatedValue on a host node would crash Android's folly::dynamic).
63
- @Component({
64
- selector: 'ScrollViewStickyHeader, symbiote-sticky-header',
65
- standalone: true,
66
- imports: [AnimatedView],
67
- changeDetection: ChangeDetectionStrategy.OnPush,
68
- template: `
69
- <AnimatedView
70
- [style]="headerStyle"
71
- [animatedProps]="headerAnimatedProps"
72
- [passthroughAnimatedPropExplicitValues]="passthrough"
73
- >
74
- <ng-content></ng-content>
75
- </AnimatedView>
76
- `,
77
- })
78
- export class ScrollViewStickyHeader
79
- implements Omit<IStickyHeaderProps, 'onLayout'>, OnInit, OnChanges, OnDestroy
80
- {
81
- // A fresh fallback AnimatedValue keeps the component working if the parent ever fails to supply
82
- // one (the wrap invariant); held by IDENTITY in a plain field (Angular does not proxy fields).
83
- @Input() scrollAnimatedValue: AnimatedValue = new AnimatedValue(0);
84
- @Input() nextHeaderLayoutY: number | undefined = undefined;
85
- @Input() inverted: boolean | undefined = undefined;
86
- @Input() scrollViewHeight: number | undefined = undefined;
87
- // The parent's layout recorder (RN _onStickyHeaderLayout): records this header's own y so the
88
- // previous header learns its collision point. Called after the header measures.
89
- @Output() readonly layout = new EventEmitter<ISymbioteEvent>();
90
-
91
- // The one folded state cell, mutated in place by reduceSticky. The DECISIONS — zero-swallow gate,
92
- // debounce delay, rebuild ranges — all live there; this component supplies only the Angular
93
- // lifecycle (inputs + manual change detection), the interpolation-node + listener wiring, the
94
- // debounce setTimeout, and the markForCheck re-render.
95
- private readonly state = createInitialStickyState();
96
- // The animated node driving the transform (RN's animatedTranslateY), replaced by the
97
- // rebuild-interpolation effect. When the scroll value is native, this interpolation runs on the UI
98
- // thread: the smooth pin.
99
- private animatedTranslateY: AnimatedInterpolation = new AnimatedValue(
100
- 0,
101
- ).interpolate({
102
- inputRange: [-1, 0],
103
- outputRange: [0, 0],
104
- });
105
- // The current interpolation node + its listener id, held so the next rebuild detaches the old
106
- // listener (an engine call the reducer does not own) and ngOnDestroy cleans up.
107
- private interpolation: AnimatedInterpolation | undefined;
108
- private debounceTimer: ReturnType<typeof setTimeout> | undefined;
109
- private listenerId: string | undefined;
110
-
111
- private readonly changeDetector = inject(ChangeDetectorRef);
112
- // This component's OWN host — the non-painting anchor `class="..."` at the use site resolves
113
- // onto (see anchorHostStyle's doc comment in primitives/shared.ts) — NOT the inner AnimatedView
114
- // one level down.
115
- private readonly elementRef = inject(ElementRef);
116
-
117
- ngOnInit(): void {
118
- this.dispatch({ kind: 'inputs-changed' });
119
- }
120
-
121
- // Rebuild on any layout/collision input change (RN's effect deps: measured, layoutY, layoutHeight,
122
- // scrollViewHeight, nextHeaderLayoutY, inverted). scrollAnimatedValue is stable for one ScrollView.
123
- ngOnChanges(): void {
124
- this.dispatch({ kind: 'inputs-changed' });
125
- }
126
-
127
- ngOnDestroy(): void {
128
- this.teardown();
129
- }
130
-
131
- get headerStyle(): unknown {
132
- // collapsable:false keeps the wrapper a real Yoga node; zIndex paints the pinned header OVER the
133
- // rows scrolling under it. The interpolation node rides inside the transform; AnimatedView's
134
- // reduceProps rasterizes it into a numeric translateY for the committed tree. This component is
135
- // its own ANCHOR_HOST_COMPONENTS entry, so a `class="..."` at its use site resolves onto
136
- // `elementRef`, not the inner AnimatedView — merge it back in (anchorHostStyle's doc comment),
137
- // anchor style first so the fixed transform/zIndex below still wins on conflict.
138
- return [
139
- anchorHostStyle(this.elementRef),
140
- {
141
- transform: [{ translateY: this.animatedTranslateY }],
142
- zIndex: STICKY_HEADER_Z_INDEX,
143
- },
144
- ];
145
- }
146
-
147
- // Stable reference (bound once) so AnimatedView's directive does not re-wire the layout listener
148
- // every change-detection pass.
149
- private readonly onHostLayout = (event: ISymbioteEvent): void =>
150
- this.handleLayout(event);
151
-
152
- // Also a stable reference, not a getter: jsonEqual (commit.ts) can't structurally compare the
153
- // embedded onLayout function, so a fresh object here would read as "props changed" on every
154
- // change-detection pass and force a real Fabric re-clone that cascades up every ancestor to the
155
- // root (see AnimatedComponentBase.reconcile()'s identical warning) — every unrelated press
156
- // anywhere in the app, not just this header's own layout events. Not `private`: the template
157
- // binds it directly (`strictTemplates` requires template-bound members stay accessible).
158
- readonly headerAnimatedProps: Record<string, unknown> = {
159
- onLayout: this.onHostLayout,
160
- collapsable: false,
161
- };
162
-
163
- // The EXPLICIT debounced translateY overrides the committed transform for hit-testing while
164
- // animatedTranslateY does the smooth (native-driven) pin (RN ScrollViewStickyHeader.js).
165
- get passthrough(): {
166
- style: { transform: Array<{ translateY: number }> };
167
- } | null {
168
- return this.state.translateY !== null
169
- ? { style: { transform: [{ translateY: this.state.translateY }] } }
170
- : null;
171
- }
172
-
173
- private inputs(): IStickyReducerInputs {
174
- return {
175
- os: Platform.OS,
176
- inverted: this.inverted,
177
- scrollViewHeight: this.scrollViewHeight,
178
- nextHeaderLayoutY: this.nextHeaderLayoutY,
179
- };
180
- }
181
-
182
- private dispatch(action: IStickyAction): void {
183
- this.runEffects(reduceSticky(this.state, action, this.inputs()).effects);
184
- }
185
-
186
- private runEffects(effects: IStickyEffect[]): void {
187
- for (const effect of effects) {
188
- switch (effect.kind) {
189
- case 'rebuild-interpolation': {
190
- // Detach the old listener, build a fresh interpolation onto the shared scroll value, and
191
- // wire the settled-value listener (symbiote is always Fabric; RN attaches it only there).
192
- if (
193
- this.interpolation !== undefined &&
194
- this.listenerId !== undefined
195
- ) {
196
- this.interpolation.removeListener(this.listenerId);
197
- this.listenerId = undefined;
198
- }
199
- const next = this.scrollAnimatedValue.interpolate({
200
- inputRange: effect.inputRange,
201
- outputRange: effect.outputRange,
202
- });
203
- this.listenerId = next.addListener(this.animatedValueListener);
204
- this.interpolation = next;
205
- this.animatedTranslateY = next;
206
- dlog(
207
- `STICKY[header] interpolation measured=${this.state.measured} y=${this.state.layoutY}`,
208
- );
209
- break;
210
- }
211
- case 'schedule-debounce':
212
- // The animated value updates several times per frame; debounce the settled value into the
213
- // committed transform so hit detection stays current (a Fabric issue, worse on Android).
214
- if (this.debounceTimer !== undefined)
215
- clearTimeout(this.debounceTimer);
216
- this.debounceTimer = setTimeout(() => {
217
- this.debounceTimer = undefined;
218
- this.dispatch({ kind: 'debounce-fired', value: effect.value });
219
- }, effect.delay);
220
- break;
221
- case 'apply-passthrough':
222
- this.changeDetector.markForCheck();
223
- break;
224
- case 'record-header-y':
225
- // The Angular header records through the `layout` EventEmitter (handleLayout below), the
226
- // public recorder contract; the reducer emits no index for it.
227
- break;
228
- }
229
- }
230
- }
231
-
232
- // Record own y/height, mark measured, rebuild the interpolation (all via the reducer), then fire
233
- // the parent's recorder (RN ScrollViewStickyHeader.js._onLayout order). The wrapped child keeps its
234
- // own onLayout binding (projected with its bindings intact), so unlike React/Vue we do not forward.
235
- private handleLayout(event: ISymbioteEvent): void {
236
- const y = readLayoutNumber(event, 'y');
237
- const height = readLayoutNumber(event, 'height');
238
- // Keep the previous value when a field is absent (RN sets state only on a defined read).
239
- this.dispatch({
240
- kind: 'layout',
241
- y: y ?? this.state.layoutY,
242
- height: height ?? this.state.layoutHeight,
243
- });
244
- this.layout.emit(event);
245
- this.changeDetector.markForCheck();
246
- }
247
-
248
- private readonly animatedValueListener = ({
249
- value,
250
- }: {
251
- value: number | string;
252
- }): void => {
253
- if (typeof value === 'number')
254
- this.dispatch({ kind: 'animated-tick', value });
255
- };
256
-
257
- private teardown(): void {
258
- if (this.interpolation !== undefined && this.listenerId !== undefined) {
259
- this.interpolation.removeListener(this.listenerId);
260
- this.listenerId = undefined;
261
- }
262
- if (this.debounceTimer !== undefined) {
263
- clearTimeout(this.debounceTimer);
264
- this.debounceTimer = undefined;
265
- }
266
- }
267
- }
@@ -1,113 +0,0 @@
1
- import {
2
- CUSTOM_ELEMENTS_SCHEMA,
3
- Component,
4
- ElementRef,
5
- forwardRef,
6
- inject,
7
- signal,
8
- type DoCheck,
9
- } from '@angular/core';
10
- import { NG_VALUE_ACCESSOR } from '@angular/forms';
11
- import {
12
- anchorHostStyle,
13
- SwitchHost,
14
- SymbioteHostPropsDirective,
15
- SymbioteStyleInputDirective,
16
- } from '../../primitives';
17
- import { SwitchBase } from './shared';
18
- export type { ISwitchProps, ISwitchTrackColor } from './shared';
19
-
20
- @Component({
21
- selector: 'Switch',
22
- standalone: true,
23
- hostDirectives: [
24
- { directive: SymbioteStyleInputDirective, inputs: ['style'] },
25
- ],
26
- schemas: [CUSTOM_ELEMENTS_SCHEMA],
27
- imports: [SwitchHost, SymbioteHostPropsDirective],
28
- providers: [
29
- {
30
- provide: NG_VALUE_ACCESSOR,
31
- useExisting: forwardRef(() => Switch),
32
- multi: true,
33
- },
34
- ],
35
- inputs: [
36
- 'value',
37
- 'disabled',
38
- 'trackColor',
39
- 'thumbColor',
40
- 'ios_backgroundColor',
41
- 'style',
42
- 'nativeID',
43
- 'testID',
44
- 'accessibilityLabel',
45
- 'accessibilityRole',
46
- 'accessibilityState',
47
- 'accessibilityValue',
48
- 'accessibilityHint',
49
- 'accessible',
50
- 'role',
51
- 'aria-label',
52
- 'aria-disabled',
53
- 'aria-checked',
54
- ],
55
- outputs: ['valueChange', 'change'],
56
- template: `
57
- <symbiote-switch
58
- #nativeSwitch="symbioteHost"
59
- [symbioteHostProps]="hostProps()"
60
- (change)="handleChange($event, nativeSwitch)"
61
- />
62
- `,
63
- })
64
- export class Switch extends SwitchBase implements DoCheck {
65
- // This component's OWN host — the non-painting anchor `class="..."` at the use site resolves
66
- // onto (see anchorHostStyle's doc comment) — NOT the <symbiote-switch> leaf one level down.
67
- private readonly elementRef = inject(ElementRef);
68
-
69
- protected readonly platform = {
70
- snapBackCommand: 'setNativeValue',
71
- trackColorProps: (
72
- value: boolean,
73
- trackColor?: { false?: string; true?: string },
74
- ) => ({
75
- trackColorForFalse: trackColor?.false,
76
- trackColorForTrue: trackColor?.true,
77
- trackTintColor: value ? trackColor?.true : trackColor?.false,
78
- }),
79
- };
80
-
81
- // The anchor's class-derived style is written by the renderer's addClass/removeClass and never
82
- // reaches Angular's input pipeline (a bare `class="x"` never appears in SimpleChanges — see
83
- // anchorHostStyle's doc comment), so SwitchBase's inputsRevision cannot see it. Hence its own
84
- // signal: a plain field read inside a computed() would be untracked and the bag would go stale
85
- // the moment a `[class.x]`/`[ngClass]` toggled.
86
- //
87
- // ngDoCheck is the right cadence: render3's callHooks flushes a node's pre-order hooks at the
88
- // next `ɵɵadvance` past it (or in refreshView's post-template flush), i.e. AFTER the declaring
89
- // template's ɵɵclassProp wrote the class onto this element and BEFORE this component's own view
90
- // refreshes — the exact window a class poll needs. callHooks also runs under
91
- // setActiveConsumer(null), so the write registers no dependency on the caller's view (no NG0600).
92
- // commitClassStyle allocates a fresh style array only when a token actually moved, so signal.set's
93
- // own Object.is check makes an unchanged poll a no-op that dirties nothing.
94
- //
95
- // Known gap, shared with every other component polling this way (Pressable, SafeAreaView,
96
- // TouchableNativeFeedback): `[ngClass]` applies its tokens from NgClass's OWN ngDoCheck, and a
97
- // node's hooks flush in registration order with the component's first, so an [ngClass] flip lands
98
- // one pass after this poll reads it. `class=` and `[class.x]` are written by the declaring
99
- // template's styling instructions and so are always current here.
100
- private readonly anchorStyle = signal<unknown>(undefined);
101
-
102
- ngDoCheck(): void {
103
- this.anchorStyle.set(anchorHostStyle(this.elementRef));
104
- }
105
-
106
- // The anchor's class-derived style goes first, then whatever SwitchBase already resolved
107
- // (its own explicit `style` @Input plus the ios_backgroundColor fold), so an explicit [style]
108
- // still beats the ambient class.
109
- protected override buildHostProps(): Record<string, unknown> {
110
- const props = super.buildHostProps();
111
- return { ...props, style: [this.anchorStyle(), props['style']] };
112
- }
113
- }
@@ -1,112 +0,0 @@
1
- import {
2
- CUSTOM_ELEMENTS_SCHEMA,
3
- Component,
4
- ElementRef,
5
- forwardRef,
6
- inject,
7
- signal,
8
- type DoCheck,
9
- } from '@angular/core';
10
- import { NG_VALUE_ACCESSOR } from '@angular/forms';
11
- import {
12
- anchorHostStyle,
13
- SwitchHost,
14
- SymbioteHostPropsDirective,
15
- SymbioteStyleInputDirective,
16
- } from '../../primitives';
17
- import { SwitchBase } from './shared';
18
- export type { ISwitchProps, ISwitchTrackColor } from './shared';
19
-
20
- @Component({
21
- selector: 'Switch',
22
- standalone: true,
23
- hostDirectives: [
24
- { directive: SymbioteStyleInputDirective, inputs: ['style'] },
25
- ],
26
- schemas: [CUSTOM_ELEMENTS_SCHEMA],
27
- imports: [SwitchHost, SymbioteHostPropsDirective],
28
- providers: [
29
- {
30
- provide: NG_VALUE_ACCESSOR,
31
- useExisting: forwardRef(() => Switch),
32
- multi: true,
33
- },
34
- ],
35
- inputs: [
36
- 'value',
37
- 'disabled',
38
- 'trackColor',
39
- 'thumbColor',
40
- 'ios_backgroundColor',
41
- 'style',
42
- 'nativeID',
43
- 'testID',
44
- 'accessibilityLabel',
45
- 'accessibilityRole',
46
- 'accessibilityState',
47
- 'accessibilityValue',
48
- 'accessibilityHint',
49
- 'accessible',
50
- 'role',
51
- 'aria-label',
52
- 'aria-disabled',
53
- 'aria-checked',
54
- ],
55
- outputs: ['valueChange', 'change'],
56
- template: `
57
- <symbiote-switch
58
- #nativeSwitch="symbioteHost"
59
- [symbioteHostProps]="hostProps()"
60
- (change)="handleChange($event, nativeSwitch)"
61
- />
62
- `,
63
- })
64
- export class Switch extends SwitchBase implements DoCheck {
65
- // This component's OWN host — the non-painting anchor `class="..."` at the use site resolves
66
- // onto (see anchorHostStyle's doc comment) — NOT the <symbiote-switch> leaf one level down.
67
- private readonly elementRef = inject(ElementRef);
68
-
69
- protected readonly platform = {
70
- snapBackCommand: 'setValue',
71
- trackColorProps: (
72
- _value: boolean,
73
- trackColor?: { false?: string; true?: string },
74
- ) => ({
75
- onTintColor: trackColor?.true,
76
- tintColor: trackColor?.false,
77
- }),
78
- };
79
-
80
- // The anchor's class-derived style is written by the renderer's addClass/removeClass and never
81
- // reaches Angular's input pipeline (a bare `class="x"` never appears in SimpleChanges — see
82
- // anchorHostStyle's doc comment), so SwitchBase's inputsRevision cannot see it. Hence its own
83
- // signal: a plain field read inside a computed() would be untracked and the bag would go stale
84
- // the moment a `[class.x]`/`[ngClass]` toggled.
85
- //
86
- // ngDoCheck is the right cadence: render3's callHooks flushes a node's pre-order hooks at the
87
- // next `ɵɵadvance` past it (or in refreshView's post-template flush), i.e. AFTER the declaring
88
- // template's ɵɵclassProp wrote the class onto this element and BEFORE this component's own view
89
- // refreshes — the exact window a class poll needs. callHooks also runs under
90
- // setActiveConsumer(null), so the write registers no dependency on the caller's view (no NG0600).
91
- // commitClassStyle allocates a fresh style array only when a token actually moved, so signal.set's
92
- // own Object.is check makes an unchanged poll a no-op that dirties nothing.
93
- //
94
- // Known gap, shared with every other component polling this way (Pressable, SafeAreaView,
95
- // TouchableNativeFeedback): `[ngClass]` applies its tokens from NgClass's OWN ngDoCheck, and a
96
- // node's hooks flush in registration order with the component's first, so an [ngClass] flip lands
97
- // one pass after this poll reads it. `class=` and `[class.x]` are written by the declaring
98
- // template's styling instructions and so are always current here.
99
- private readonly anchorStyle = signal<unknown>(undefined);
100
-
101
- ngDoCheck(): void {
102
- this.anchorStyle.set(anchorHostStyle(this.elementRef));
103
- }
104
-
105
- // The anchor's class-derived style goes first, then whatever SwitchBase already resolved
106
- // (its own explicit `style` @Input plus the ios_backgroundColor fold), so an explicit [style]
107
- // still beats the ambient class.
108
- protected override buildHostProps(): Record<string, unknown> {
109
- const props = super.buildHostProps();
110
- return { ...props, style: [this.anchorStyle(), props['style']] };
111
- }
112
- }
@@ -1,4 +0,0 @@
1
- // Base/default Switch. Re-exports the iOS build; Metro picks index.ios.ts / index.android.ts
2
- // in platform bundles. The Angular lifecycle reuses the shared Switch reducer + render fold.
3
-
4
- export * from './index.ios';