@symbiote-native/angular 0.6.0 → 0.6.2

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 (193) hide show
  1. package/README.md +1 -1
  2. package/babel-register-composed.cjs +11 -3
  3. package/build/angular/anchor-host-registry.d.ts +2 -0
  4. package/build/angular/anchor-host-registry.js +84 -0
  5. package/build/angular/anchor-host-registry.js.map +1 -0
  6. package/build/angular/components/input-accessory-view/index.d.ts +2 -1
  7. package/build/angular/components/input-accessory-view/index.js +28 -39
  8. package/build/angular/components/input-accessory-view/index.js.map +1 -1
  9. package/build/angular/components/scroll-view/projection.js +70 -48
  10. package/build/angular/components/scroll-view/projection.js.map +1 -1
  11. package/build/angular/components/scroll-view/shared.js +28 -25
  12. package/build/angular/components/scroll-view/shared.js.map +1 -1
  13. package/build/angular/components/scroll-view/sticky-header.d.ts +6 -7
  14. package/build/angular/components/scroll-view/sticky-header.js +82 -65
  15. package/build/angular/components/scroll-view/sticky-header.js.map +1 -1
  16. package/build/angular/components/touchable/index.d.ts +2 -5
  17. package/build/angular/components/touchable/index.js +36 -56
  18. package/build/angular/components/touchable/index.js.map +1 -1
  19. package/build/angular/components/virtualized-list/index.d.ts +5 -20
  20. package/build/angular/components/virtualized-list/index.js +145 -275
  21. package/build/angular/components/virtualized-list/index.js.map +1 -1
  22. package/build/angular/components/virtualized-section-list/index.js +2 -4
  23. package/build/angular/components/virtualized-section-list/index.js.map +1 -1
  24. package/build/angular/index.d.ts +2 -1
  25. package/build/angular/index.js +6 -1
  26. package/build/angular/index.js.map +1 -1
  27. package/build/angular/renderer/index.d.ts +0 -1
  28. package/build/angular/renderer/index.js +5 -60
  29. package/build/angular/renderer/index.js.map +1 -1
  30. package/package.json +8 -4
  31. package/src/anchor-host-registry.ts +88 -0
  32. package/src/components/input-accessory-view/index.ts +30 -39
  33. package/src/components/scroll-view/projection.ts +76 -46
  34. package/src/components/scroll-view/shared.ts +27 -19
  35. package/src/components/scroll-view/sticky-header.ts +89 -64
  36. package/src/components/touchable/index.ts +52 -66
  37. package/src/components/virtualized-list/index.ts +157 -368
  38. package/src/components/virtualized-section-list/index.ts +6 -3
  39. package/src/index.ts +6 -1
  40. package/src/renderer/index.ts +5 -63
  41. package/build/bootstrap.d.ts +0 -7
  42. package/build/bootstrap.js +0 -14
  43. package/build/components/activity-indicator/index.android.d.ts +0 -9
  44. package/build/components/activity-indicator/index.android.js +0 -64
  45. package/build/components/activity-indicator/index.d.ts +0 -1
  46. package/build/components/activity-indicator/index.ios.d.ts +0 -5
  47. package/build/components/activity-indicator/index.ios.js +0 -64
  48. package/build/components/activity-indicator/index.js +0 -3
  49. package/build/components/activity-indicator/shared.d.ts +0 -64
  50. package/build/components/activity-indicator/shared.js +0 -424
  51. package/build/components/button.d.ts +0 -60
  52. package/build/components/button.js +0 -456
  53. package/build/components/flat-list/index.d.ts +0 -119
  54. package/build/components/flat-list/index.js +0 -691
  55. package/build/components/image/index.android.d.ts +0 -7
  56. package/build/components/image/index.android.js +0 -88
  57. package/build/components/image/index.d.ts +0 -1
  58. package/build/components/image/index.ios.d.ts +0 -7
  59. package/build/components/image/index.ios.js +0 -88
  60. package/build/components/image/index.js +0 -2
  61. package/build/components/image/shared.d.ts +0 -101
  62. package/build/components/image/shared.js +0 -405
  63. package/build/components/image-background.d.ts +0 -78
  64. package/build/components/image-background.js +0 -583
  65. package/build/components/input-accessory-view/index.d.ts +0 -56
  66. package/build/components/input-accessory-view/index.js +0 -403
  67. package/build/components/keyboard-avoiding-view/index.d.ts +0 -79
  68. package/build/components/keyboard-avoiding-view/index.js +0 -504
  69. package/build/components/modal/index.d.ts +0 -89
  70. package/build/components/modal/index.js +0 -529
  71. package/build/components/pressable/index.d.ts +0 -120
  72. package/build/components/pressable/index.js +0 -639
  73. package/build/components/refresh-control/index.d.ts +0 -83
  74. package/build/components/refresh-control/index.js +0 -509
  75. package/build/components/safe-area-view/index.d.ts +0 -54
  76. package/build/components/safe-area-view/index.js +0 -388
  77. package/build/components/scroll-view/index.android.d.ts +0 -16
  78. package/build/components/scroll-view/index.android.js +0 -228
  79. package/build/components/scroll-view/index.d.ts +0 -3
  80. package/build/components/scroll-view/index.ios.d.ts +0 -6
  81. package/build/components/scroll-view/index.ios.js +0 -113
  82. package/build/components/scroll-view/index.js +0 -5
  83. package/build/components/scroll-view/projection.d.ts +0 -32
  84. package/build/components/scroll-view/projection.js +0 -311
  85. package/build/components/scroll-view/shared.d.ts +0 -225
  86. package/build/components/scroll-view/shared.js +0 -757
  87. package/build/components/scroll-view/sticky-header.d.ts +0 -38
  88. package/build/components/scroll-view/sticky-header.js +0 -257
  89. package/build/components/section-list/index.d.ts +0 -113
  90. package/build/components/section-list/index.js +0 -768
  91. package/build/components/switch/index.android.d.ts +0 -17
  92. package/build/components/switch/index.android.js +0 -107
  93. package/build/components/switch/index.d.ts +0 -1
  94. package/build/components/switch/index.ios.d.ts +0 -16
  95. package/build/components/switch/index.ios.js +0 -106
  96. package/build/components/switch/index.js +0 -3
  97. package/build/components/switch/shared.d.ts +0 -37
  98. package/build/components/switch/shared.js +0 -176
  99. package/build/components/text-input.d.ts +0 -150
  100. package/build/components/text-input.js +0 -821
  101. package/build/components/touchable/index.d.ts +0 -241
  102. package/build/components/touchable/index.js +0 -1672
  103. package/build/components/touchable-native-feedback/index.d.ts +0 -80
  104. package/build/components/touchable-native-feedback/index.js +0 -545
  105. package/build/components/virtualized-list/directives.d.ts +0 -41
  106. package/build/components/virtualized-list/directives.js +0 -249
  107. package/build/components/virtualized-list/index.d.ts +0 -265
  108. package/build/components/virtualized-list/index.js +0 -1343
  109. package/build/components/virtualized-section-list/directives.d.ts +0 -28
  110. package/build/components/virtualized-section-list/directives.js +0 -148
  111. package/build/components/virtualized-section-list/index.d.ts +0 -175
  112. package/build/components/virtualized-section-list/index.js +0 -854
  113. package/build/components.d.ts +0 -39
  114. package/build/components.js +0 -37
  115. package/build/create-portal/index.d.ts +0 -17
  116. package/build/create-portal/index.js +0 -128
  117. package/build/create-tunnel/index.d.ts +0 -29
  118. package/build/create-tunnel/index.js +0 -181
  119. package/build/descriptor-to-angular/index.d.ts +0 -19
  120. package/build/descriptor-to-angular/index.js +0 -186
  121. package/build/host-instance/index.d.ts +0 -2
  122. package/build/host-instance/index.js +0 -36
  123. package/build/index.d.ts +0 -21
  124. package/build/index.js +0 -40
  125. package/build/modules/animated/animated-leaf-binder/index.d.ts +0 -14
  126. package/build/modules/animated/animated-leaf-binder/index.js +0 -90
  127. package/build/modules/animated/animated-leaf-binder.d.ts +0 -14
  128. package/build/modules/animated/animated-leaf-binder.js +0 -90
  129. package/build/modules/animated/create-animated-component.d.ts +0 -48
  130. package/build/modules/animated/create-animated-component.js +0 -425
  131. package/build/modules/animated/index.d.ts +0 -51
  132. package/build/modules/animated/index.js +0 -58
  133. package/build/modules/app-registry/index.d.ts +0 -7
  134. package/build/modules/app-registry/index.js +0 -22
  135. package/build/modules/status-bar/index.d.ts +0 -17
  136. package/build/modules/status-bar/index.js +0 -121
  137. package/build/primitives/index.d.ts +0 -32
  138. package/build/primitives/index.js +0 -386
  139. package/build/primitives/shared.d.ts +0 -83
  140. package/build/primitives/shared.js +0 -230
  141. package/build/render/index.d.ts +0 -11
  142. package/build/render/index.js +0 -170
  143. package/build/renderer/index.d.ts +0 -38
  144. package/build/renderer/index.js +0 -355
  145. package/build/services/color-scheme.service.d.ts +0 -13
  146. package/build/services/color-scheme.service.js +0 -72
  147. package/build/services/index.d.ts +0 -2
  148. package/build/services/index.js +0 -2
  149. package/build/services/window-dimensions.service.d.ts +0 -13
  150. package/build/services/window-dimensions.service.js +0 -83
  151. package/src/__tests__/responder-change-detection.test.ts +0 -102
  152. package/src/__tests__/responder-nested-cd.test.ts +0 -113
  153. package/src/angular-gaps.test.ts +0 -142
  154. package/src/angular-imports.test.ts +0 -100
  155. package/src/components/activity-indicator/activity-indicator-class-style.test.ts +0 -44
  156. package/src/components/activity-indicator/activity-indicator.test.ts +0 -131
  157. package/src/components/flat-list/column-wrapper-style-class.test.ts +0 -116
  158. package/src/components/flat-list/flat-list-array-style.test.ts +0 -131
  159. package/src/components/flat-list/flat-list-class-style.test.ts +0 -74
  160. package/src/components/flat-list/flat-list-scroll-containment.test.ts +0 -107
  161. package/src/components/flat-list/flat-list.test.ts +0 -99
  162. package/src/components/image/image-class-style.test.ts +0 -46
  163. package/src/components/image-background-class-style.test.ts +0 -48
  164. package/src/components/image-background-style-class.test.ts +0 -79
  165. package/src/components/input-accessory-view/input-accessory-view.test.ts +0 -43
  166. package/src/components/keyboard-avoiding-view/keyboard-avoiding-view.test.ts +0 -54
  167. package/src/components/modal/modal.test.ts +0 -43
  168. package/src/components/pressable/pressable.test.ts +0 -85
  169. package/src/components/refresh-control/refresh-control.test.ts +0 -41
  170. package/src/components/safe-area-view/safe-area-view.test.ts +0 -43
  171. package/src/components/scroll-view/android-scroll-view-axis-projection.test.ts +0 -123
  172. package/src/components/scroll-view/content-container-style-class.test.ts +0 -75
  173. package/src/components/scroll-view/scroll-view-class-style.test.ts +0 -134
  174. package/src/components/scroll-view/scroll-view-projection.test.ts +0 -194
  175. package/src/components/switch/android-switch-class.test.ts +0 -42
  176. package/src/components/switch/switch.test.ts +0 -92
  177. package/src/components/text-input-class-style.test.ts +0 -54
  178. package/src/components/touchable/touchable.test.ts +0 -102
  179. package/src/components/touchable-native-feedback/touchable-native-feedback.test.ts +0 -49
  180. package/src/components/virtualized-list/virtualized-list-class-style.test.ts +0 -76
  181. package/src/components/virtualized-section-list/virtualized-section-list-class-style.test.ts +0 -60
  182. package/src/create-portal/create-portal.test.ts +0 -90
  183. package/src/create-tunnel/create-tunnel.test.ts +0 -120
  184. package/src/descriptor-to-angular/descriptor-outlet.test.ts +0 -94
  185. package/src/host-instance/host-instance.test.ts +0 -49
  186. package/src/modules/animated/animated-leaf-binder/animated-leaf-binder.test.ts +0 -116
  187. package/src/modules/animated/animated-leaf-binder.test.ts +0 -116
  188. package/src/modules/animated/animated-scroll-view.test.ts +0 -102
  189. package/src/modules/app-registry/app-registry.test.ts +0 -106
  190. package/src/modules/status-bar/status-bar.test.ts +0 -50
  191. package/src/render/render.test.ts +0 -147
  192. package/src/renderer/renderer.test.ts +0 -202
  193. package/src/services/services.test.ts +0 -163
@@ -1,194 +0,0 @@
1
- import '@angular/compiler';
2
- import { Component, CUSTOM_ELEMENTS_SCHEMA, signal } from '@angular/core';
3
- import { afterEach, beforeEach, describe, expect, it } from 'vitest';
4
- import { installFabric } from '@symbiote-native/test-utils';
5
- import { mount, unmount } from '../../render';
6
- import { RefreshControl } from '../refresh-control';
7
- import { ScrollView as AndroidScrollView } from './index.android';
8
- import { ScrollView } from './index.ios';
9
-
10
- const ROOT_TAG = 918;
11
- const fabric = installFabric();
12
- const tick = (): Promise<void> => new Promise(resolve => setTimeout(resolve, 0));
13
-
14
- class StickyProjectionApp {}
15
- Component({
16
- selector: 'symbiote-scroll-sticky-projection-test',
17
- standalone: true,
18
- imports: [ScrollView],
19
- schemas: [CUSTOM_ELEMENTS_SCHEMA],
20
- template: `
21
- <ScrollView [stickyHeaderIndices]="[1]">
22
- <symbiote-view testID="before"></symbiote-view>
23
- <symbiote-view testID="sticky"></symbiote-view>
24
- <symbiote-view testID="after"></symbiote-view>
25
- </ScrollView>
26
- `,
27
- })(StickyProjectionApp);
28
-
29
- class CustomStickyHeader {
30
- static instantiated = false;
31
-
32
- constructor() {
33
- CustomStickyHeader.instantiated = true;
34
- }
35
- }
36
- Component({
37
- selector: 'CustomStickyHeader',
38
- standalone: true,
39
- schemas: [CUSTOM_ELEMENTS_SCHEMA],
40
- template: `
41
- <symbiote-view testID="custom-sticky-wrapper">
42
- <ng-content></ng-content>
43
- </symbiote-view>
44
- `,
45
- })(CustomStickyHeader);
46
-
47
- class CustomStickyProjectionApp {
48
- CustomStickyHeader = CustomStickyHeader;
49
- }
50
- Component({
51
- selector: 'symbiote-scroll-custom-sticky-projection-test',
52
- standalone: true,
53
- imports: [ScrollView],
54
- schemas: [CUSTOM_ELEMENTS_SCHEMA],
55
- template: `
56
- <ScrollView [stickyHeaderIndices]="[0]" [StickyHeaderComponent]="CustomStickyHeader">
57
- <symbiote-view testID="sticky"></symbiote-view>
58
- <symbiote-view testID="after"></symbiote-view>
59
- </ScrollView>
60
- `,
61
- })(CustomStickyProjectionApp);
62
-
63
- class IOSRefreshProjectionApp {
64
- static refreshes = 0;
65
-
66
- readonly refreshing = signal(false);
67
-
68
- refresh = (): void => {
69
- this.refreshing.set(true);
70
- setTimeout(() => {
71
- this.refreshing.set(false);
72
- IOSRefreshProjectionApp.refreshes += 1;
73
- }, 0);
74
- };
75
- }
76
- Component({
77
- selector: 'symbiote-scroll-ios-refresh-projection-test',
78
- standalone: true,
79
- imports: [ScrollView, RefreshControl],
80
- schemas: [CUSTOM_ELEMENTS_SCHEMA],
81
- template: `
82
- <ScrollView>
83
- <RefreshControl [refreshing]="refreshing()" (refresh)="refresh()" />
84
- <symbiote-view testID="content"></symbiote-view>
85
- </ScrollView>
86
- `,
87
- })(IOSRefreshProjectionApp);
88
-
89
- class AndroidRefreshProjectionApp {
90
- static refreshes = 0;
91
-
92
- refresh = (): void => {
93
- AndroidRefreshProjectionApp.refreshes += 1;
94
- };
95
- }
96
- Component({
97
- selector: 'symbiote-scroll-android-refresh-projection-test',
98
- standalone: true,
99
- imports: [AndroidScrollView, RefreshControl],
100
- schemas: [CUSTOM_ELEMENTS_SCHEMA],
101
- template: `
102
- <ScrollView [style]="{ marginTop: 4, backgroundColor: 'red' }">
103
- <RefreshControl [refreshing]="true" (refresh)="refresh()" />
104
- <symbiote-view testID="content"></symbiote-view>
105
- </ScrollView>
106
- `,
107
- })(AndroidRefreshProjectionApp);
108
-
109
- beforeEach(() => {
110
- fabric.reset();
111
- CustomStickyHeader.instantiated = false;
112
- IOSRefreshProjectionApp.refreshes = 0;
113
- AndroidRefreshProjectionApp.refreshes = 0;
114
- });
115
- afterEach(() => unmount(ROOT_TAG));
116
-
117
- describe('Angular ScrollView projection parity', () => {
118
- it('auto-wraps projected children selected by stickyHeaderIndices', async () => {
119
- mount(ROOT_TAG, StickyProjectionApp);
120
- await tick();
121
-
122
- const root = fabric.appRoot();
123
- expect(fabric.serialize(root.children)).toBe(
124
- 'RCTScrollView(RCTScrollContentView(RCTViewRCTView(RCTView)RCTView))',
125
- );
126
-
127
- const stickyWrapper = fabric.find(
128
- node =>
129
- node.props.collapsable === false &&
130
- node.children.some(child => child.props.testID === 'sticky'),
131
- );
132
- expect(stickyWrapper?.props).toMatchObject({ collapsable: false, onLayout: true });
133
- });
134
-
135
- it('keeps auto StickyHeaderComponent projection on the built-in AOT-safe wrapper', async () => {
136
- mount(ROOT_TAG, CustomStickyProjectionApp);
137
- await tick();
138
-
139
- expect(CustomStickyHeader.instantiated).toBe(false);
140
- expect(fabric.find(node => node.props.testID === 'custom-sticky-wrapper')).toBeUndefined();
141
-
142
- const stickyWrapper = fabric.find(
143
- node =>
144
- node.props.collapsable === false &&
145
- node.children.some(child => child.props.testID === 'sticky'),
146
- );
147
- expect(stickyWrapper?.props).toMatchObject({ collapsable: false, onLayout: true });
148
- });
149
-
150
- it('renders iOS RefreshControl before content and syncs the controlled native spinner', async () => {
151
- mount(ROOT_TAG, IOSRefreshProjectionApp);
152
- await tick();
153
-
154
- const root = fabric.appRoot();
155
- expect(fabric.serialize(root.children)).toBe(
156
- 'RCTScrollView(PullToRefreshViewRCTScrollContentView(RCTView))',
157
- );
158
-
159
- const refresh = root.children[0]?.children[0];
160
- expect(refresh?.viewName).toBe('PullToRefreshView');
161
- fabric.fireEvent(refresh?.instanceHandle, 'topRefresh');
162
- await tick();
163
- await tick();
164
-
165
- expect(IOSRefreshProjectionApp.refreshes).toBe(1);
166
- expect(fabric.commands.at(-1)).toMatchObject({
167
- commandName: 'setNativeRefreshing',
168
- args: [false],
169
- });
170
- expect(fabric.commands.at(-1)?.node.tag).toBe(refresh?.tag);
171
- });
172
-
173
- it('wraps an Android projected RefreshControl around the scroll view', async () => {
174
- mount(ROOT_TAG, AndroidRefreshProjectionApp);
175
- await tick();
176
-
177
- const root = fabric.appRoot();
178
- expect(fabric.serialize(root.children)).toBe(
179
- 'PullToRefreshView(RCTScrollView(RCTScrollContentView(RCTView)))',
180
- );
181
-
182
- const refresh = root.children[0];
183
- expect(refresh?.props).toMatchObject({ refreshing: true, marginTop: 4 });
184
- fabric.fireEvent(refresh?.instanceHandle, 'topRefresh');
185
- await tick();
186
-
187
- expect(AndroidRefreshProjectionApp.refreshes).toBe(1);
188
- expect(refresh?.children[0]?.props).toMatchObject({
189
- backgroundColor: 'red',
190
- nestedScrollEnabled: true,
191
- });
192
- expect(fabric.find(node => node.props.testID === 'content')).toBeDefined();
193
- });
194
- });
@@ -1,42 +0,0 @@
1
- // Android-specific twin of the class= regression covered for iOS in switch.test.ts. Switch's
2
- // hostProps getter is overridden per-platform component (index.ios.ts / index.android.ts), each
3
- // injecting its OWN ElementRef, so the fix needs its own coverage against the Android build too.
4
- import '@angular/compiler';
5
- import { Component } from '@angular/core';
6
- import { afterEach, beforeEach, describe, expect, it } from 'vitest';
7
- import { clearGlobalStyles, registerStyles } from '@symbiote-native/engine';
8
- import { installFabric } from '@symbiote-native/test-utils';
9
-
10
- import { mount, unmount } from '../../render';
11
- import { Switch } from './index.android';
12
-
13
- const ROOT_TAG = 942;
14
- const fabric = installFabric();
15
-
16
- beforeEach(() => {
17
- fabric.reset();
18
- });
19
- afterEach(() => {
20
- unmount(ROOT_TAG);
21
- clearGlobalStyles();
22
- });
23
-
24
- @Component({
25
- selector: 'symbiote-android-switch-class-host',
26
- standalone: true,
27
- imports: [Switch],
28
- template: `<Switch [testID]="'switch-with-class'" class="card"></Switch>`,
29
- })
30
- class AndroidSwitchClassHost {}
31
-
32
- describe('Switch (android)', () => {
33
- it('resolves a class= on the Switch use site onto the real committed view, not the anchor', async () => {
34
- registerStyles({ card: { backgroundColor: 'red' } });
35
-
36
- mount(ROOT_TAG, AndroidSwitchClassHost);
37
- await new Promise<void>(resolve => setTimeout(resolve, 0));
38
-
39
- const node = fabric.find(n => n.props.testID === 'switch-with-class');
40
- expect(node?.props.backgroundColor).toBe('red');
41
- });
42
- });
@@ -1,92 +0,0 @@
1
- import '@angular/compiler';
2
- import { Component } from '@angular/core';
3
- import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
4
- import { clearGlobalStyles, registerStyles } from '@symbiote-native/engine';
5
- import { installFabric } from '@symbiote-native/test-utils';
6
-
7
- import { mount, unmount } from '../../render';
8
- import { Switch } from './index';
9
-
10
- const ROOT_TAG = 902;
11
- const fabric = installFabric();
12
-
13
- let capturedHost: SwitchHost | undefined;
14
-
15
- @Component({
16
- selector: 'symbiote-switch-host',
17
- standalone: true,
18
- imports: [Switch],
19
- template: `
20
- <Switch [value]="value" (valueChange)="onValueChange($event)" (change)="onChange($event)">
21
- </Switch>
22
- `,
23
- })
24
- class SwitchHost {
25
- value = false;
26
- onValueChange = vi.fn((next: boolean) => {
27
- this.value = next;
28
- });
29
- onChange = vi.fn();
30
-
31
- constructor() {
32
- // Captures the live component instance so the test can drive its signals after mount.
33
- // eslint-disable-next-line @typescript-eslint/no-this-alias
34
- capturedHost = this;
35
- }
36
- }
37
-
38
- beforeEach(() => {
39
- capturedHost = undefined;
40
- fabric.reset();
41
- });
42
- afterEach(() => {
43
- unmount(ROOT_TAG);
44
- clearGlobalStyles();
45
- });
46
-
47
- describe('Switch', () => {
48
- it('commits a controlled Switch with the resolved iOS color props', async () => {
49
- mount(ROOT_TAG, SwitchHost);
50
- await new Promise<void>(resolve => setTimeout(resolve, 0));
51
-
52
- const node = fabric.find(n => n.viewName === 'Switch');
53
- expect(node, 'Switch node committed').toBeDefined();
54
- expect(node?.props).toMatchObject({
55
- value: false,
56
- });
57
- });
58
-
59
- it('fires onValueChange and onChange when native reports a change', async () => {
60
- mount(ROOT_TAG, SwitchHost);
61
- await new Promise<void>(resolve => setTimeout(resolve, 0));
62
-
63
- const node = fabric.find(n => n.viewName === 'Switch');
64
- expect(node).toBeDefined();
65
-
66
- fabric.fireEvent(node?.instanceHandle, 'topChange', { value: true, eventCount: 1 });
67
- await new Promise<void>(resolve => setTimeout(resolve, 0));
68
-
69
- const host = capturedHost;
70
- expect(host?.onValueChange).toHaveBeenCalledWith(true);
71
- expect(host?.onChange).toHaveBeenCalled();
72
- expect(host?.value).toBe(true);
73
- });
74
-
75
- it('resolves a class= on the Switch use site onto the real committed view, not the anchor', async () => {
76
- registerStyles({ card: { backgroundColor: 'red' } });
77
-
78
- mount(ROOT_TAG, SwitchClassHost);
79
- await new Promise<void>(resolve => setTimeout(resolve, 0));
80
-
81
- const node = fabric.find(n => n.props.testID === 'switch-with-class');
82
- expect(node?.props.backgroundColor).toBe('red');
83
- });
84
- });
85
-
86
- @Component({
87
- selector: 'symbiote-switch-class-host',
88
- standalone: true,
89
- imports: [Switch],
90
- template: `<Switch [testID]="'switch-with-class'" class="card"></Switch>`,
91
- })
92
- class SwitchClassHost {}
@@ -1,54 +0,0 @@
1
- // Regression test for the anchor/class bug: TextInput is its own
2
- // ANCHOR_HOST_COMPONENTS entry — a class= on <TextInput> resolves onto TextInput's OWN anchor and
3
- // needs its OWN anchorHostStyle merge (see text-input.ts's buildPassthrough), for BOTH the
4
- // single-line and multiline host it renders through (`@if`/`@else` picks one at runtime). Mirrors
5
- // pressable.test.ts's "resolves a class=" case.
6
- import '@angular/compiler';
7
- import { Component } from '@angular/core';
8
- import { afterEach, beforeEach, describe, expect, it } from 'vitest';
9
- import { clearGlobalStyles, registerStyles } from '@symbiote-native/engine';
10
- import { installFabric } from '@symbiote-native/test-utils';
11
-
12
- import { mount, unmount } from '../render';
13
- import { TextInput } from './text-input';
14
-
15
- const ROOT_TAG = 917;
16
- const fabric = installFabric();
17
-
18
- @Component({
19
- selector: 'symbiote-text-input-class-host',
20
- standalone: true,
21
- imports: [TextInput],
22
- template: `
23
- <TextInput [testID]="'single-line'" class="card" />
24
- <TextInput [testID]="'multiline'" [multiline]="true" class="card" />
25
- `,
26
- })
27
- class TextInputClassHost {}
28
-
29
- beforeEach(() => {
30
- fabric.reset();
31
- registerStyles({ card: { backgroundColor: 'red' } });
32
- });
33
- afterEach(() => {
34
- unmount(ROOT_TAG);
35
- clearGlobalStyles();
36
- });
37
-
38
- describe('TextInput anchor class= resolution', () => {
39
- it('resolves a class= on the TextInput use site onto the real committed single-line host', async () => {
40
- mount(ROOT_TAG, TextInputClassHost);
41
- await new Promise<void>(resolve => setTimeout(resolve, 0));
42
-
43
- const node = fabric.find(n => n.props.testID === 'single-line');
44
- expect(node?.props.backgroundColor).toBe('red');
45
- });
46
-
47
- it('resolves a class= on the TextInput use site onto the real committed multiline host', async () => {
48
- mount(ROOT_TAG, TextInputClassHost);
49
- await new Promise<void>(resolve => setTimeout(resolve, 0));
50
-
51
- const node = fabric.find(n => n.props.testID === 'multiline');
52
- expect(node?.props.backgroundColor).toBe('red');
53
- });
54
- });
@@ -1,102 +0,0 @@
1
- // Regression coverage for the anchor-vs-real-content class bug (see pressable.test.ts for the
2
- // full writeup): a `class="..."` written on a composed component's OWN use site always resolves
3
- // through Angular's addClass/removeClass onto that component's non-painting ANCHOR host, never
4
- // onto the real committed Fabric view one (or more) levels down. Each Touchable forwards its own
5
- // anchor's resolved style into whatever it commits, mirroring Pressable's fix.
6
- import '@angular/compiler';
7
- import { Component } from '@angular/core';
8
- import { afterEach, beforeEach, describe, expect, it } from 'vitest';
9
- import { clearGlobalStyles, registerStyles } from '@symbiote-native/engine';
10
- import { installFabric } from '@symbiote-native/test-utils';
11
-
12
- import { mount, unmount } from '../../render';
13
- import { TouchableHighlight, TouchableOpacity, TouchableWithoutFeedback } from './index';
14
-
15
- const ROOT_TAG = 940;
16
- const fabric = installFabric();
17
-
18
- beforeEach(() => {
19
- fabric.reset();
20
- });
21
- afterEach(() => {
22
- unmount(ROOT_TAG);
23
- clearGlobalStyles();
24
- });
25
-
26
- @Component({
27
- selector: 'symbiote-touchable-opacity-host',
28
- standalone: true,
29
- imports: [TouchableOpacity],
30
- template: `
31
- <TouchableOpacity [testID]="'opacity'" class="card">
32
- <symbiote-text>Press</symbiote-text>
33
- </TouchableOpacity>
34
- `,
35
- })
36
- class TouchableOpacityHost {}
37
-
38
- @Component({
39
- selector: 'symbiote-touchable-highlight-host',
40
- standalone: true,
41
- imports: [TouchableHighlight],
42
- template: `
43
- <TouchableHighlight [testID]="'highlight'" class="card">
44
- <symbiote-text>Press</symbiote-text>
45
- </TouchableHighlight>
46
- `,
47
- })
48
- class TouchableHighlightHost {}
49
-
50
- @Component({
51
- selector: 'symbiote-touchable-without-feedback-host',
52
- standalone: true,
53
- imports: [TouchableWithoutFeedback],
54
- template: `
55
- <TouchableWithoutFeedback [testID]="'without-feedback'" class="card">
56
- <symbiote-text>Press</symbiote-text>
57
- </TouchableWithoutFeedback>
58
- `,
59
- })
60
- class TouchableWithoutFeedbackHost {}
61
-
62
- describe('TouchableOpacity', () => {
63
- it('resolves a class= on the TouchableOpacity use site onto the real committed view, not the anchor', async () => {
64
- registerStyles({ card: { backgroundColor: 'red' } });
65
-
66
- mount(ROOT_TAG, TouchableOpacityHost);
67
- await new Promise<void>(resolve => setTimeout(resolve, 0));
68
-
69
- // TouchableOpacity folds its OWN class-derived style into the inner AnimatedView leaf, not
70
- // the outer Pressable — mirroring React's TouchableOpacity (see adapters/react/src/components/
71
- // touchable/index.ts's comment: "className is pulled out here, like style, and applied to the
72
- // inner AnimatedView... it would land on the outer Pressable instead, which is not what a user
73
- // expects"), so the testID-carrying outer view is NOT where the resolved style lands.
74
- expect(fabric.find(n => n.props.testID === 'opacity')).toBeDefined();
75
- const node = fabric.find(n => n.props.backgroundColor === 'red');
76
- expect(node, 'a committed node received the class-derived style').toBeDefined();
77
- });
78
- });
79
-
80
- describe('TouchableHighlight', () => {
81
- it('resolves a class= on the TouchableHighlight use site onto the real committed view, not the anchor', async () => {
82
- registerStyles({ card: { backgroundColor: 'red' } });
83
-
84
- mount(ROOT_TAG, TouchableHighlightHost);
85
- await new Promise<void>(resolve => setTimeout(resolve, 0));
86
-
87
- const node = fabric.find(n => n.props.testID === 'highlight');
88
- expect(node?.props.backgroundColor).toBe('red');
89
- });
90
- });
91
-
92
- describe('TouchableWithoutFeedback', () => {
93
- it('resolves a class= on the TouchableWithoutFeedback use site onto the real committed view, not the anchor', async () => {
94
- registerStyles({ card: { backgroundColor: 'red' } });
95
-
96
- mount(ROOT_TAG, TouchableWithoutFeedbackHost);
97
- await new Promise<void>(resolve => setTimeout(resolve, 0));
98
-
99
- const node = fabric.find(n => n.props.testID === 'without-feedback');
100
- expect(node?.props.backgroundColor).toBe('red');
101
- });
102
- });
@@ -1,49 +0,0 @@
1
- // Regression coverage for the anchor-vs-real-content class bug (see pressable.test.ts for the
2
- // full writeup): a `class="..."` written on TouchableNativeFeedback's OWN use site always resolves
3
- // through Angular's addClass/removeClass onto its non-painting ANCHOR host, never onto the real
4
- // committed feedback <symbiote-view> one level down. TouchableNativeFeedback has no explicit
5
- // `style`/`class`-forwarding @Input() of its own, so the anchor's class-derived style is the
6
- // ONLY style source hostProps.style forwards.
7
- import '@angular/compiler';
8
- import { Component } from '@angular/core';
9
- import { afterEach, beforeEach, describe, expect, it } from 'vitest';
10
- import { clearGlobalStyles, registerStyles } from '@symbiote-native/engine';
11
- import { installFabric } from '@symbiote-native/test-utils';
12
-
13
- import { mount, unmount } from '../../render';
14
- import { TouchableNativeFeedback } from './index';
15
-
16
- const ROOT_TAG = 941;
17
- const fabric = installFabric();
18
-
19
- beforeEach(() => {
20
- fabric.reset();
21
- });
22
- afterEach(() => {
23
- unmount(ROOT_TAG);
24
- clearGlobalStyles();
25
- });
26
-
27
- @Component({
28
- selector: 'symbiote-touchable-native-feedback-host',
29
- standalone: true,
30
- imports: [TouchableNativeFeedback],
31
- template: `
32
- <TouchableNativeFeedback [testID]="'native-feedback'" class="card">
33
- <symbiote-text>Press</symbiote-text>
34
- </TouchableNativeFeedback>
35
- `,
36
- })
37
- class TouchableNativeFeedbackHost {}
38
-
39
- describe('TouchableNativeFeedback', () => {
40
- it('resolves a class= on the TouchableNativeFeedback use site onto the real committed view, not the anchor', async () => {
41
- registerStyles({ card: { backgroundColor: 'red' } });
42
-
43
- mount(ROOT_TAG, TouchableNativeFeedbackHost);
44
- await new Promise<void>(resolve => setTimeout(resolve, 0));
45
-
46
- const node = fabric.find(n => n.props.testID === 'native-feedback');
47
- expect(node?.props.backgroundColor).toBe('red');
48
- });
49
- });
@@ -1,76 +0,0 @@
1
- // Regression test for the anchor/class bug: VirtualizedList is its own
2
- // ANCHOR_HOST_COMPONENTS entry — a class= on <VirtualizedList> resolves onto VirtualizedList's OWN
3
- // anchor and needs its OWN anchorHostStyle merge (see index.ts's recomputeView), it is NOT
4
- // transitively fixed by ScrollView's own fix one level down. Mirrors pressable.test.ts's
5
- // "resolves a class=" case.
6
- import '@angular/compiler';
7
- import { Component } from '@angular/core';
8
- import { afterEach, beforeEach, describe, expect, it } from 'vitest';
9
- import { clearGlobalStyles, registerStyles } from '@symbiote-native/engine';
10
- import { installFabric } from '@symbiote-native/test-utils';
11
-
12
- import { mount, unmount } from '../../render';
13
- import { VirtualizedList } from './index';
14
- import { VListItemDirective } from './directives';
15
-
16
- const ROOT_TAG = 952;
17
- const fabric = installFabric();
18
- const tick = (): Promise<void> => new Promise(resolve => setTimeout(resolve, 0));
19
-
20
- interface IRow {
21
- id: string;
22
- }
23
-
24
- const rows: IRow[] = [{ id: 'a' }, { id: 'b' }];
25
-
26
- @Component({
27
- selector: 'symbiote-virtualized-list-class-host',
28
- standalone: true,
29
- imports: [VirtualizedList, VListItemDirective],
30
- template: `
31
- <VirtualizedList
32
- class="card"
33
- [data]="rows"
34
- [getItem]="getItem"
35
- [getItemCount]="getItemCount"
36
- [getItemLayout]="getItemLayout"
37
- >
38
- <ng-template vListItem let-item>
39
- <symbiote-text [testID]="item.id">{{ item.id }}</symbiote-text>
40
- </ng-template>
41
- </VirtualizedList>
42
- `,
43
- })
44
- class VirtualizedListClassHost {
45
- rows = rows;
46
- getItem = (data: readonly IRow[], index: number): IRow => data[index];
47
- getItemCount = (data: readonly IRow[]): number => data.length;
48
- getItemLayout = (
49
- _data: unknown,
50
- index: number,
51
- ): { length: number; offset: number; index: number } => ({
52
- length: 30,
53
- offset: 30 * index,
54
- index,
55
- });
56
- }
57
-
58
- beforeEach(() => {
59
- fabric.reset();
60
- registerStyles({ card: { backgroundColor: 'red' } });
61
- });
62
- afterEach(() => {
63
- unmount(ROOT_TAG);
64
- clearGlobalStyles();
65
- });
66
-
67
- describe('VirtualizedList anchor class= resolution', () => {
68
- it('resolves a class= on the VirtualizedList use site onto the real committed scroll host', async () => {
69
- mount(ROOT_TAG, VirtualizedListClassHost);
70
- await tick();
71
- await tick();
72
-
73
- const node = fabric.find(n => n.props.backgroundColor === 'red');
74
- expect(node, 'a real Fabric node carries the class-derived style').toBeDefined();
75
- });
76
- });
@@ -1,60 +0,0 @@
1
- // Regression test for the anchor/class bug: VirtualizedSectionList is its
2
- // own ANCHOR_HOST_COMPONENTS entry — a class= on <VirtualizedSectionList> resolves onto its OWN
3
- // anchor and needs its OWN anchorHostStyle merge (see index.ts's resolvedStyle getter), it is NOT
4
- // transitively fixed by VirtualizedList's/ScrollView's own fixes further down. Mirrors
5
- // pressable.test.ts's "resolves a class=" case.
6
- import '@angular/compiler';
7
- import { Component } from '@angular/core';
8
- import { afterEach, beforeEach, describe, expect, it } from 'vitest';
9
- import { clearGlobalStyles, registerStyles } from '@symbiote-native/engine';
10
- import { installFabric } from '@symbiote-native/test-utils';
11
- import type { ISection } from '@symbiote-native/components';
12
-
13
- import { mount, unmount } from '../../render';
14
- import { VirtualizedSectionList, VSectionItemDirective } from './index';
15
-
16
- const ROOT_TAG = 954;
17
- const fabric = installFabric();
18
- const tick = (): Promise<void> => new Promise(resolve => setTimeout(resolve, 0));
19
-
20
- interface IRow {
21
- id: string;
22
- }
23
-
24
- const sections: ISection<IRow>[] = [{ title: 'A', data: [{ id: 'a1' }, { id: 'a2' }] }];
25
-
26
- @Component({
27
- selector: 'symbiote-virtualized-section-list-class-host',
28
- standalone: true,
29
- imports: [VirtualizedSectionList, VSectionItemDirective],
30
- template: `
31
- <VirtualizedSectionList class="card" [sections]="sections">
32
- <ng-template vSectionItem let-item>
33
- <symbiote-text [testID]="item.id">{{ item.id }}</symbiote-text>
34
- </ng-template>
35
- </VirtualizedSectionList>
36
- `,
37
- })
38
- class VirtualizedSectionListClassHost {
39
- sections = sections;
40
- }
41
-
42
- beforeEach(() => {
43
- fabric.reset();
44
- registerStyles({ card: { backgroundColor: 'red' } });
45
- });
46
- afterEach(() => {
47
- unmount(ROOT_TAG);
48
- clearGlobalStyles();
49
- });
50
-
51
- describe('VirtualizedSectionList anchor class= resolution', () => {
52
- it('resolves a class= on the VirtualizedSectionList use site onto the real committed scroll host', async () => {
53
- mount(ROOT_TAG, VirtualizedSectionListClassHost);
54
- await tick();
55
- await tick();
56
-
57
- const node = fabric.find(n => n.props.backgroundColor === 'red');
58
- expect(node, 'a real Fabric node carries the class-derived style').toBeDefined();
59
- });
60
- });