@symbiote-native/angular 0.6.1 → 0.7.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 (206) hide show
  1. package/README.md +1 -1
  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/components/activity-indicator/index.android.d.ts +2 -1
  6. package/build/angular/components/activity-indicator/index.android.js +6 -3
  7. package/build/angular/components/activity-indicator/index.android.js.map +1 -1
  8. package/build/angular/components/activity-indicator/index.ios.d.ts +2 -1
  9. package/build/angular/components/activity-indicator/index.ios.js +6 -3
  10. package/build/angular/components/activity-indicator/index.ios.js.map +1 -1
  11. package/build/angular/components/activity-indicator/shared.js +3 -3
  12. package/build/angular/components/button.d.ts +4 -2
  13. package/build/angular/components/button.js +28 -17
  14. package/build/angular/components/button.js.map +1 -1
  15. package/build/angular/components/flat-list/index.d.ts +5 -3
  16. package/build/angular/components/flat-list/index.js +35 -38
  17. package/build/angular/components/flat-list/index.js.map +1 -1
  18. package/build/angular/components/image/index.android.d.ts +8 -3
  19. package/build/angular/components/image/index.android.js +39 -9
  20. package/build/angular/components/image/index.android.js.map +1 -1
  21. package/build/angular/components/image/index.ios.d.ts +8 -3
  22. package/build/angular/components/image/index.ios.js +39 -9
  23. package/build/angular/components/image/index.ios.js.map +1 -1
  24. package/build/angular/components/image/shared.d.ts +4 -1
  25. package/build/angular/components/image/shared.js +33 -2
  26. package/build/angular/components/image/shared.js.map +1 -1
  27. package/build/angular/components/image-background.d.ts +2 -1
  28. package/build/angular/components/image-background.js +6 -4
  29. package/build/angular/components/image-background.js.map +1 -1
  30. package/build/angular/components/input-accessory-view/index.d.ts +9 -4
  31. package/build/angular/components/input-accessory-view/index.js +43 -9
  32. package/build/angular/components/input-accessory-view/index.js.map +1 -1
  33. package/build/angular/components/keyboard-avoiding-view/index.d.ts +2 -1
  34. package/build/angular/components/keyboard-avoiding-view/index.js +6 -4
  35. package/build/angular/components/keyboard-avoiding-view/index.js.map +1 -1
  36. package/build/angular/components/modal/index.d.ts +11 -8
  37. package/build/angular/components/modal/index.js +45 -28
  38. package/build/angular/components/modal/index.js.map +1 -1
  39. package/build/angular/components/pressable/index.d.ts +11 -5
  40. package/build/angular/components/pressable/index.js +61 -12
  41. package/build/angular/components/pressable/index.js.map +1 -1
  42. package/build/angular/components/refresh-control/index.d.ts +8 -4
  43. package/build/angular/components/refresh-control/index.js +52 -16
  44. package/build/angular/components/refresh-control/index.js.map +1 -1
  45. package/build/angular/components/safe-area-view/index.d.ts +9 -4
  46. package/build/angular/components/safe-area-view/index.js +46 -9
  47. package/build/angular/components/safe-area-view/index.js.map +1 -1
  48. package/build/angular/components/scroll-view/index.android.d.ts +2 -3
  49. package/build/angular/components/scroll-view/index.android.js +49 -52
  50. package/build/angular/components/scroll-view/index.android.js.map +1 -1
  51. package/build/angular/components/scroll-view/index.ios.d.ts +2 -3
  52. package/build/angular/components/scroll-view/index.ios.js +15 -17
  53. package/build/angular/components/scroll-view/index.ios.js.map +1 -1
  54. package/build/angular/components/scroll-view/projection.d.ts +3 -0
  55. package/build/angular/components/scroll-view/projection.js +68 -7
  56. package/build/angular/components/scroll-view/projection.js.map +1 -1
  57. package/build/angular/components/scroll-view/shared.d.ts +14 -5
  58. package/build/angular/components/scroll-view/shared.js +198 -69
  59. package/build/angular/components/scroll-view/shared.js.map +1 -1
  60. package/build/angular/components/scroll-view/sticky-header.js +14 -19
  61. package/build/angular/components/scroll-view/sticky-header.js.map +1 -1
  62. package/build/angular/components/section-list/index.d.ts +2 -1
  63. package/build/angular/components/section-list/index.js +31 -39
  64. package/build/angular/components/section-list/index.js.map +1 -1
  65. package/build/angular/components/switch/index.android.d.ts +7 -3
  66. package/build/angular/components/switch/index.android.js +38 -10
  67. package/build/angular/components/switch/index.android.js.map +1 -1
  68. package/build/angular/components/switch/index.ios.d.ts +7 -3
  69. package/build/angular/components/switch/index.ios.js +38 -10
  70. package/build/angular/components/switch/index.ios.js.map +1 -1
  71. package/build/angular/components/switch/shared.d.ts +12 -3
  72. package/build/angular/components/switch/shared.js +66 -5
  73. package/build/angular/components/switch/shared.js.map +1 -1
  74. package/build/angular/components/text-input.d.ts +10 -2
  75. package/build/angular/components/text-input.js +46 -6
  76. package/build/angular/components/text-input.js.map +1 -1
  77. package/build/angular/components/touchable/index.d.ts +17 -8
  78. package/build/angular/components/touchable/index.js +78 -19
  79. package/build/angular/components/touchable/index.js.map +1 -1
  80. package/build/angular/components/touchable-native-feedback/index.d.ts +6 -3
  81. package/build/angular/components/touchable-native-feedback/index.js +61 -25
  82. package/build/angular/components/touchable-native-feedback/index.js.map +1 -1
  83. package/build/angular/components/virtualized-list/directives.js +18 -18
  84. package/build/angular/components/virtualized-list/index.d.ts +12 -4
  85. package/build/angular/components/virtualized-list/index.js +163 -68
  86. package/build/angular/components/virtualized-list/index.js.map +1 -1
  87. package/build/angular/components/virtualized-section-list/directives.js +12 -12
  88. package/build/angular/components/virtualized-section-list/index.d.ts +2 -1
  89. package/build/angular/components/virtualized-section-list/index.js +6 -4
  90. package/build/angular/components/virtualized-section-list/index.js.map +1 -1
  91. package/build/angular/components.d.ts +1 -1
  92. package/build/angular/components.js +5 -0
  93. package/build/angular/components.js.map +1 -1
  94. package/build/angular/create-portal/index.js +29 -35
  95. package/build/angular/create-portal/index.js.map +1 -1
  96. package/build/angular/create-tunnel/index.js +19 -22
  97. package/build/angular/create-tunnel/index.js.map +1 -1
  98. package/build/angular/descriptor-to-angular/index.js +3 -3
  99. package/build/angular/index.d.ts +4 -2
  100. package/build/angular/index.js +2 -2
  101. package/build/angular/index.js.map +1 -1
  102. package/build/angular/modules/animated/animated-leaf-binder.d.ts +1 -7
  103. package/build/angular/modules/animated/animated-leaf-binder.js +22 -72
  104. package/build/angular/modules/animated/animated-leaf-binder.js.map +1 -1
  105. package/build/angular/modules/animated/create-animated-component.d.ts +11 -6
  106. package/build/angular/modules/animated/create-animated-component.js +83 -50
  107. package/build/angular/modules/animated/create-animated-component.js.map +1 -1
  108. package/build/angular/modules/app-registry/index.js.map +1 -1
  109. package/build/angular/modules/status-bar/index.js +3 -3
  110. package/build/angular/primitives/index.d.ts +1 -1
  111. package/build/angular/primitives/index.js +46 -46
  112. package/build/angular/primitives/index.js.map +1 -1
  113. package/build/angular/primitives/shared.d.ts +39 -1
  114. package/build/angular/primitives/shared.js +110 -9
  115. package/build/angular/primitives/shared.js.map +1 -1
  116. package/build/angular/render/index.js +23 -35
  117. package/build/angular/render/index.js.map +1 -1
  118. package/build/angular/services/color-scheme.service.js +3 -3
  119. package/build/angular/services/window-dimensions.service.js +3 -3
  120. package/package.json +13 -8
  121. package/src/anchor-host-registry.ts +2 -2
  122. package/src/components/activity-indicator/index.android.ts +2 -0
  123. package/src/components/activity-indicator/index.ios.ts +2 -0
  124. package/src/components/button.ts +28 -14
  125. package/src/components/flat-list/index.ts +34 -36
  126. package/src/components/image/index.android.ts +50 -6
  127. package/src/components/image/index.ios.ts +50 -6
  128. package/src/components/image/shared.ts +34 -2
  129. package/src/components/image-background.ts +2 -1
  130. package/src/components/input-accessory-view/index.ts +42 -4
  131. package/src/components/keyboard-avoiding-view/index.ts +7 -1
  132. package/src/components/modal/index.ts +51 -26
  133. package/src/components/pressable/index.ts +67 -8
  134. package/src/components/refresh-control/index.ts +54 -12
  135. package/src/components/safe-area-view/index.ts +50 -5
  136. package/src/components/scroll-view/index.android.ts +34 -41
  137. package/src/components/scroll-view/index.ios.ts +10 -21
  138. package/src/components/scroll-view/projection.ts +79 -7
  139. package/src/components/scroll-view/shared.ts +223 -68
  140. package/src/components/scroll-view/sticky-header.ts +11 -16
  141. package/src/components/section-list/index.ts +27 -36
  142. package/src/components/switch/index.android.ts +48 -7
  143. package/src/components/switch/index.ios.ts +48 -7
  144. package/src/components/switch/shared.ts +79 -3
  145. package/src/components/text-input.ts +52 -2
  146. package/src/components/touchable/index.ts +76 -16
  147. package/src/components/touchable-native-feedback/index.ts +62 -21
  148. package/src/components/virtualized-list/index.ts +137 -44
  149. package/src/components/virtualized-section-list/index.ts +2 -1
  150. package/src/components.ts +5 -0
  151. package/src/create-portal/index.ts +23 -29
  152. package/src/create-tunnel/index.ts +13 -16
  153. package/src/index.ts +30 -1
  154. package/src/modules/animated/animated-leaf-binder.ts +28 -77
  155. package/src/modules/animated/create-animated-component.ts +75 -36
  156. package/src/modules/app-registry/index.ts +6 -8
  157. package/src/primitives/index.ts +1 -0
  158. package/src/primitives/shared.ts +102 -3
  159. package/src/render/index.ts +23 -35
  160. package/build/angular/modules/animated/animated-leaf-binder/index.d.ts +0 -14
  161. package/build/angular/modules/animated/animated-leaf-binder/index.js +0 -91
  162. package/build/angular/modules/animated/animated-leaf-binder/index.js.map +0 -1
  163. package/src/__tests__/responder-change-detection.test.ts +0 -102
  164. package/src/__tests__/responder-nested-cd.test.ts +0 -113
  165. package/src/angular-gaps.test.ts +0 -142
  166. package/src/angular-imports.test.ts +0 -100
  167. package/src/components/activity-indicator/activity-indicator-class-style.test.ts +0 -44
  168. package/src/components/activity-indicator/activity-indicator.test.ts +0 -131
  169. package/src/components/flat-list/column-wrapper-style-class.test.ts +0 -116
  170. package/src/components/flat-list/flat-list-array-style.test.ts +0 -131
  171. package/src/components/flat-list/flat-list-class-style.test.ts +0 -74
  172. package/src/components/flat-list/flat-list-scroll-containment.test.ts +0 -107
  173. package/src/components/flat-list/flat-list.test.ts +0 -99
  174. package/src/components/image/image-class-style.test.ts +0 -46
  175. package/src/components/image-background-class-style.test.ts +0 -48
  176. package/src/components/image-background-style-class.test.ts +0 -79
  177. package/src/components/input-accessory-view/input-accessory-view.test.ts +0 -43
  178. package/src/components/keyboard-avoiding-view/keyboard-avoiding-view.test.ts +0 -54
  179. package/src/components/modal/modal.test.ts +0 -43
  180. package/src/components/pressable/pressable.test.ts +0 -85
  181. package/src/components/refresh-control/refresh-control.test.ts +0 -41
  182. package/src/components/safe-area-view/safe-area-view.test.ts +0 -43
  183. package/src/components/scroll-view/android-scroll-view-axis-projection.test.ts +0 -123
  184. package/src/components/scroll-view/content-container-style-class.test.ts +0 -75
  185. package/src/components/scroll-view/scroll-view-class-style.test.ts +0 -134
  186. package/src/components/scroll-view/scroll-view-projection.test.ts +0 -194
  187. package/src/components/switch/android-switch-class.test.ts +0 -42
  188. package/src/components/switch/switch.test.ts +0 -92
  189. package/src/components/text-input-class-style.test.ts +0 -54
  190. package/src/components/touchable/touchable.test.ts +0 -102
  191. package/src/components/touchable-native-feedback/touchable-native-feedback.test.ts +0 -49
  192. package/src/components/virtualized-list/virtualized-list-class-style.test.ts +0 -76
  193. package/src/components/virtualized-section-list/virtualized-section-list-class-style.test.ts +0 -60
  194. package/src/create-portal/create-portal.test.ts +0 -90
  195. package/src/create-tunnel/create-tunnel.test.ts +0 -120
  196. package/src/descriptor-to-angular/descriptor-outlet.test.ts +0 -94
  197. package/src/host-instance/host-instance.test.ts +0 -49
  198. package/src/modules/animated/animated-leaf-binder/animated-leaf-binder.test.ts +0 -116
  199. package/src/modules/animated/animated-leaf-binder/index.ts +0 -101
  200. package/src/modules/animated/animated-leaf-binder.test.ts +0 -116
  201. package/src/modules/animated/animated-scroll-view.test.ts +0 -102
  202. package/src/modules/app-registry/app-registry.test.ts +0 -106
  203. package/src/modules/status-bar/status-bar.test.ts +0 -50
  204. package/src/render/render.test.ts +0 -147
  205. package/src/renderer/renderer.test.ts +0 -203
  206. package/src/services/services.test.ts +0 -163
@@ -1,46 +0,0 @@
1
- // Regression test for the anchor/class bug: Image is its own
2
- // ANCHOR_HOST_COMPONENTS entry — a class= on <Image> resolves onto Image's OWN anchor and needs
3
- // its OWN anchorHostStyle merge (see index.ios.ts/index.android.ts's imageProps override), not
4
- // transitively fixed by anything else. Mirrors pressable.test.ts's "resolves a class=" case.
5
- import '@angular/compiler';
6
- import { Component } from '@angular/core';
7
- import { afterEach, beforeEach, describe, expect, it } from 'vitest';
8
- import { clearGlobalStyles, registerStyles } from '@symbiote-native/engine';
9
- import { installFabric } from '@symbiote-native/test-utils';
10
-
11
- import { mount, unmount } from '../../render';
12
- import { Image } from './index';
13
-
14
- const ROOT_TAG = 915;
15
- const fabric = installFabric();
16
-
17
- @Component({
18
- selector: 'symbiote-image-class-host',
19
- standalone: true,
20
- imports: [Image],
21
- template: `<Image
22
- [testID]="'photo'"
23
- class="card"
24
- [source]="{ uri: 'https://example.com/a.png' }"
25
- />`,
26
- })
27
- class ImageClassHost {}
28
-
29
- beforeEach(() => {
30
- fabric.reset();
31
- registerStyles({ card: { backgroundColor: 'red' } });
32
- });
33
- afterEach(() => {
34
- unmount(ROOT_TAG);
35
- clearGlobalStyles();
36
- });
37
-
38
- describe('Image anchor class= resolution', () => {
39
- it('resolves a class= on the Image use site onto the real committed view, not the anchor', async () => {
40
- mount(ROOT_TAG, ImageClassHost);
41
- await new Promise<void>(resolve => setTimeout(resolve, 0));
42
-
43
- const node = fabric.find(n => n.props.testID === 'photo');
44
- expect(node?.props.backgroundColor).toBe('red');
45
- });
46
- });
@@ -1,48 +0,0 @@
1
- // Regression test for the anchor/class bug: ImageBackground is its own
2
- // ANCHOR_HOST_COMPONENTS entry, separate from the Image it composes internally — a class= on
3
- // <ImageBackground> resolves onto ImageBackground's OWN anchor and needs its OWN anchorHostStyle
4
- // merge onto its wrapper View (see image-background.ts's wrapperStyle getter), NOT onto its
5
- // `imageStyle` (a separate, deliberately untouched prop — see the file's header comment).
6
- // Mirrors pressable.test.ts's "resolves a class=" case.
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 { ImageBackground } from './image-background';
15
-
16
- const ROOT_TAG = 916;
17
- const fabric = installFabric();
18
-
19
- @Component({
20
- selector: 'symbiote-image-background-class-host',
21
- standalone: true,
22
- imports: [ImageBackground],
23
- template: `
24
- <ImageBackground class="card" [source]="{ uri: 'https://example.com/a.png' }">
25
- <symbiote-text>on top</symbiote-text>
26
- </ImageBackground>
27
- `,
28
- })
29
- class ImageBackgroundClassHost {}
30
-
31
- beforeEach(() => {
32
- fabric.reset();
33
- registerStyles({ card: { backgroundColor: 'red' } });
34
- });
35
- afterEach(() => {
36
- unmount(ROOT_TAG);
37
- clearGlobalStyles();
38
- });
39
-
40
- describe('ImageBackground anchor class= resolution', () => {
41
- it('resolves a class= on the ImageBackground use site onto the real committed wrapper View', async () => {
42
- mount(ROOT_TAG, ImageBackgroundClassHost);
43
- await new Promise<void>(resolve => setTimeout(resolve, 0));
44
-
45
- const node = fabric.find(n => n.props.backgroundColor === 'red');
46
- expect(node, 'a real Fabric node carries the class-derived style').toBeDefined();
47
- });
48
- });
@@ -1,79 +0,0 @@
1
- // Regression guard: imageStyle previously accepted ONLY a JS style object/array. It now also
2
- // resolves a class-name string through the shared style registry, same as the `class` prop fix on
3
- // the WRAPPER view (see image-background-class-style.test.ts) — and must land on the INNER image,
4
- // never the wrapper, exactly like that prior fix. Mirrors the Vue twin
5
- // (image-background-style-class.test.ts).
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, type IFakeNode } from '@symbiote-native/test-utils';
11
-
12
- import { mount, unmount } from '../render';
13
- import { ImageBackground } from './image-background';
14
-
15
- const ROOT_TAG = 917;
16
- const fabric = installFabric();
17
- const tick = (): Promise<void> => new Promise(resolve => setTimeout(resolve, 0));
18
-
19
- function committedImage(): IFakeNode {
20
- const node = fabric.find(n => n.viewName === 'RCTImageView');
21
- expect(node, 'the inner image was committed').toBeDefined();
22
- if (node === undefined) throw new Error('unreachable: image missing');
23
- return node;
24
- }
25
-
26
- function committedWrapper(): IFakeNode {
27
- const node = fabric.find(n => n.viewName === 'RCTView');
28
- expect(node, 'the wrapper view was committed').toBeDefined();
29
- if (node === undefined) throw new Error('unreachable: wrapper missing');
30
- return node;
31
- }
32
-
33
- @Component({
34
- selector: 'symbiote-image-background-style-class-host',
35
- standalone: true,
36
- imports: [ImageBackground],
37
- template: `<ImageBackground
38
- [source]="{ uri: 'https://example.com/a.png' }"
39
- [imageStyle]="'tinted'"
40
- />`,
41
- })
42
- class ImageBackgroundStyleClassHost {}
43
-
44
- @Component({
45
- selector: 'symbiote-image-background-style-object-host',
46
- standalone: true,
47
- imports: [ImageBackground],
48
- template: `<ImageBackground
49
- [source]="{ uri: 'https://example.com/a.png' }"
50
- [imageStyle]="{ opacity: 0.25 }"
51
- />`,
52
- })
53
- class ImageBackgroundStyleObjectHost {}
54
-
55
- beforeEach(() => {
56
- fabric.reset();
57
- registerStyles({ tinted: { opacity: 0.5 } });
58
- });
59
- afterEach(() => {
60
- unmount(ROOT_TAG);
61
- clearGlobalStyles();
62
- });
63
-
64
- describe('ImageBackground imageStyle class-name support', () => {
65
- it('resolves a class-name string onto the inner image, not the wrapper', async () => {
66
- mount(ROOT_TAG, ImageBackgroundStyleClassHost);
67
- await tick();
68
-
69
- expect(committedImage().props.opacity).toBe(0.5);
70
- expect(committedWrapper().props.opacity).toBeUndefined();
71
- });
72
-
73
- it('still accepts an ordinary style object unchanged', async () => {
74
- mount(ROOT_TAG, ImageBackgroundStyleObjectHost);
75
- await tick();
76
-
77
- expect(committedImage().props.opacity).toBe(0.25);
78
- });
79
- });
@@ -1,43 +0,0 @@
1
- import '@angular/compiler';
2
- import { Component } from '@angular/core';
3
- import { afterEach, beforeEach, describe, expect, it } 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 { InputAccessoryView } from './index';
9
-
10
- const ROOT_TAG = 913;
11
- const fabric = installFabric();
12
-
13
- @Component({
14
- selector: 'symbiote-iav-host',
15
- standalone: true,
16
- imports: [InputAccessoryView],
17
- template: `
18
- <InputAccessoryView [testID]="'iav'" class="toolbar">
19
- <symbiote-text>Hello</symbiote-text>
20
- </InputAccessoryView>
21
- `,
22
- })
23
- class InputAccessoryViewHostFixture {}
24
-
25
- beforeEach(() => {
26
- fabric.reset();
27
- });
28
- afterEach(() => {
29
- unmount(ROOT_TAG);
30
- clearGlobalStyles();
31
- });
32
-
33
- describe('InputAccessoryView', () => {
34
- it('resolves a class= on the InputAccessoryView use site onto the real committed view, not the anchor', async () => {
35
- registerStyles({ toolbar: { backgroundColor: 'orange' } });
36
-
37
- mount(ROOT_TAG, InputAccessoryViewHostFixture);
38
- await new Promise<void>(resolve => setTimeout(resolve, 0));
39
-
40
- const node = fabric.find(n => n.props.testID === 'iav');
41
- expect(node?.props.backgroundColor).toBe('orange');
42
- });
43
- });
@@ -1,54 +0,0 @@
1
- import '@angular/compiler';
2
- import { Component } from '@angular/core';
3
- import { afterEach, beforeEach, describe, expect, it } 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 { KeyboardAvoidingView } from './index';
9
-
10
- const ROOT_TAG = 911;
11
- const fabric = installFabric();
12
-
13
- // KeyboardAvoidingView's ngOnInit subscribes to the Keyboard module, which installs the
14
- // bridgeless device-event hub on first use — needs a fake RN$registerCallableModule so
15
- // installDeviceEventHub() doesn't throw (core/engine/src/native-events.ts). No native event is
16
- // actually emitted in this test, only the subscribe/unsubscribe lifecycle runs.
17
- Object.assign(globalThis, {
18
- RN$registerCallableModule: (
19
- _name: string,
20
- _factory: () => { emit: (eventType: string, ...args: unknown[]) => void },
21
- ): void => {},
22
- });
23
-
24
- @Component({
25
- selector: 'symbiote-kav-host',
26
- standalone: true,
27
- imports: [KeyboardAvoidingView],
28
- template: `
29
- <KeyboardAvoidingView [testID]="'kav'" class="panel">
30
- <symbiote-text>Hello</symbiote-text>
31
- </KeyboardAvoidingView>
32
- `,
33
- })
34
- class KeyboardAvoidingViewHostFixture {}
35
-
36
- beforeEach(() => {
37
- fabric.reset();
38
- });
39
- afterEach(() => {
40
- unmount(ROOT_TAG);
41
- clearGlobalStyles();
42
- });
43
-
44
- describe('KeyboardAvoidingView', () => {
45
- it('resolves a class= on the KeyboardAvoidingView use site onto the real committed view, not the anchor', async () => {
46
- registerStyles({ panel: { backgroundColor: 'teal' } });
47
-
48
- mount(ROOT_TAG, KeyboardAvoidingViewHostFixture);
49
- await new Promise<void>(resolve => setTimeout(resolve, 0));
50
-
51
- const node = fabric.find(n => n.props.testID === 'kav');
52
- expect(node?.props.backgroundColor).toBe('teal');
53
- });
54
- });
@@ -1,43 +0,0 @@
1
- import '@angular/compiler';
2
- import { Component } from '@angular/core';
3
- import { afterEach, beforeEach, describe, expect, it } 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 { Modal } from './index';
9
-
10
- const ROOT_TAG = 912;
11
- const fabric = installFabric();
12
-
13
- @Component({
14
- selector: 'symbiote-modal-host',
15
- standalone: true,
16
- imports: [Modal],
17
- template: `
18
- <Modal [visible]="true" [testID]="'modal'" class="sheet">
19
- <symbiote-text>Hello</symbiote-text>
20
- </Modal>
21
- `,
22
- })
23
- class ModalHostFixture {}
24
-
25
- beforeEach(() => {
26
- fabric.reset();
27
- });
28
- afterEach(() => {
29
- unmount(ROOT_TAG);
30
- clearGlobalStyles();
31
- });
32
-
33
- describe('Modal', () => {
34
- it('resolves a class= on the Modal use site onto the real committed view, not the anchor', async () => {
35
- registerStyles({ sheet: { backgroundColor: 'purple' } });
36
-
37
- mount(ROOT_TAG, ModalHostFixture);
38
- await new Promise<void>(resolve => setTimeout(resolve, 0));
39
-
40
- const node = fabric.find(n => n.props.testID === 'modal');
41
- expect(node?.props.backgroundColor).toBe('purple');
42
- });
43
- });
@@ -1,85 +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 { Pressable } from './index';
9
-
10
- const ROOT_TAG = 903;
11
- const fabric = installFabric();
12
-
13
- let capturedHost: PressableHost | undefined;
14
-
15
- @Component({
16
- selector: 'symbiote-pressable-host',
17
- standalone: true,
18
- imports: [Pressable],
19
- template: `
20
- <Pressable
21
- [testID]="'pressable'"
22
- class="card"
23
- (press)="onPress($event)"
24
- (pressIn)="onPressIn($event)"
25
- (pressOut)="onPressOut($event)"
26
- >
27
- <symbiote-text>Press me</symbiote-text>
28
- </Pressable>
29
- `,
30
- })
31
- class PressableHost {
32
- onPress = vi.fn();
33
- onPressIn = vi.fn();
34
- onPressOut = vi.fn();
35
-
36
- constructor() {
37
- // Captures the live component instance so the test can drive its signals after mount.
38
- // eslint-disable-next-line @typescript-eslint/no-this-alias
39
- capturedHost = this;
40
- }
41
- }
42
-
43
- beforeEach(() => {
44
- capturedHost = undefined;
45
- fabric.reset();
46
- });
47
- afterEach(() => {
48
- unmount(ROOT_TAG);
49
- clearGlobalStyles();
50
- });
51
-
52
- describe('Pressable', () => {
53
- it('synthesizes a press from a touch sequence and fires the lifecycle handlers', async () => {
54
- mount(ROOT_TAG, PressableHost);
55
- await new Promise<void>(resolve => setTimeout(resolve, 0));
56
-
57
- const node = fabric.find(n => n.props.testID === 'pressable');
58
- expect(node, 'Pressable view committed').toBeDefined();
59
-
60
- const now = Date.now();
61
- const touch = { identifier: 1, pageX: 10, pageY: 10, timestamp: now };
62
- const nativeEvent = { touches: [touch], changedTouches: [touch] };
63
-
64
- fabric.fireEvent(node?.instanceHandle, 'topTouchStart', nativeEvent);
65
- await new Promise<void>(resolve => setTimeout(resolve, 0));
66
-
67
- expect(capturedHost?.onPressIn).toHaveBeenCalledOnce();
68
-
69
- fabric.fireEvent(node?.instanceHandle, 'topTouchEnd', nativeEvent);
70
- await new Promise<void>(resolve => setTimeout(resolve, 0));
71
-
72
- expect(capturedHost?.onPress).toHaveBeenCalledOnce();
73
- expect(capturedHost?.onPressOut).toHaveBeenCalledOnce();
74
- });
75
-
76
- it('resolves a class= on the Pressable use site onto the real committed view, not the anchor', async () => {
77
- registerStyles({ card: { backgroundColor: 'red' } });
78
-
79
- mount(ROOT_TAG, PressableHost);
80
- await new Promise<void>(resolve => setTimeout(resolve, 0));
81
-
82
- const node = fabric.find(n => n.props.testID === 'pressable');
83
- expect(node?.props.backgroundColor).toBe('red');
84
- });
85
- });
@@ -1,41 +0,0 @@
1
- import '@angular/compiler';
2
- import { Component } from '@angular/core';
3
- import { afterEach, beforeEach, describe, expect, it } 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 { RefreshControl } from './index';
9
-
10
- const ROOT_TAG = 914;
11
- const fabric = installFabric();
12
-
13
- @Component({
14
- selector: 'symbiote-refresh-control-host',
15
- standalone: true,
16
- imports: [RefreshControl],
17
- template: `
18
- <RefreshControl [refreshing]="false" [testID]="'refresh'" class="spinner"></RefreshControl>
19
- `,
20
- })
21
- class RefreshControlHostFixture {}
22
-
23
- beforeEach(() => {
24
- fabric.reset();
25
- });
26
- afterEach(() => {
27
- unmount(ROOT_TAG);
28
- clearGlobalStyles();
29
- });
30
-
31
- describe('RefreshControl', () => {
32
- it('resolves a class= on the RefreshControl use site onto the real committed view, not the anchor', async () => {
33
- registerStyles({ spinner: { backgroundColor: 'green' } });
34
-
35
- mount(ROOT_TAG, RefreshControlHostFixture);
36
- await new Promise<void>(resolve => setTimeout(resolve, 0));
37
-
38
- const node = fabric.find(n => n.props.testID === 'refresh');
39
- expect(node?.props.backgroundColor).toBe('green');
40
- });
41
- });
@@ -1,43 +0,0 @@
1
- import '@angular/compiler';
2
- import { Component } from '@angular/core';
3
- import { afterEach, beforeEach, describe, expect, it } 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 { SafeAreaView } from './index';
9
-
10
- const ROOT_TAG = 910;
11
- const fabric = installFabric();
12
-
13
- @Component({
14
- selector: 'symbiote-safe-area-view-host',
15
- standalone: true,
16
- imports: [SafeAreaView],
17
- template: `
18
- <SafeAreaView [testID]="'safe-area'" class="screen">
19
- <symbiote-text>Hello</symbiote-text>
20
- </SafeAreaView>
21
- `,
22
- })
23
- class SafeAreaViewHostFixture {}
24
-
25
- beforeEach(() => {
26
- fabric.reset();
27
- });
28
- afterEach(() => {
29
- unmount(ROOT_TAG);
30
- clearGlobalStyles();
31
- });
32
-
33
- describe('SafeAreaView', () => {
34
- it('resolves a class= on the SafeAreaView use site onto the real committed view, not the anchor', async () => {
35
- registerStyles({ screen: { backgroundColor: 'navy' } });
36
-
37
- mount(ROOT_TAG, SafeAreaViewHostFixture);
38
- await new Promise<void>(resolve => setTimeout(resolve, 0));
39
-
40
- const node = fabric.find(n => n.props.testID === 'safe-area');
41
- expect(node?.props.backgroundColor).toBe('navy');
42
- });
43
- });
@@ -1,123 +0,0 @@
1
- // Regression test for an Android content-projection bug:
2
- // ScrollView on Android picks a different native content view per axis (RCTView vs
3
- // AndroidHorizontalScrollContentView), which used to require a separate <ng-content> per
4
- // axis x refresh-control combination — and Angular only reliably projects into a component's
5
- // LAST-declared <ng-content> when 2+ distinct declarations exist. Fixed by routing all four
6
- // branches through a single shared <ng-template>/<ng-content> via a local template-outlet
7
- // directive (see index.android.ts). Covers all four static combinations plus a runtime axis
8
- // flip, which the projection.ts records/reconcile path must survive without dropping children.
9
- import '@angular/compiler';
10
- import { Component, CUSTOM_ELEMENTS_SCHEMA, signal } from '@angular/core';
11
- import { afterEach, beforeEach, describe, expect, it } from 'vitest';
12
- import { installFabric } from '@symbiote-native/test-utils';
13
- import { mount, unmount } from '../../render';
14
- import { RefreshControl } from '../refresh-control';
15
- import { ScrollView } from './index.android';
16
-
17
- const ROOT_TAG = 919;
18
- const fabric = installFabric();
19
- const tick = (): Promise<void> => new Promise(resolve => setTimeout(resolve, 0));
20
-
21
- function expectCellsProjected(): void {
22
- expect(fabric.find(node => node.props.testID === 'a')).toBeDefined();
23
- expect(fabric.find(node => node.props.testID === 'b')).toBeDefined();
24
- }
25
-
26
- class HorizontalNoRefreshApp {}
27
- Component({
28
- selector: 'axis-projection-horizontal-no-refresh',
29
- standalone: true,
30
- imports: [ScrollView],
31
- schemas: [CUSTOM_ELEMENTS_SCHEMA],
32
- template: `
33
- <ScrollView [horizontal]="true">
34
- <symbiote-view testID="a"></symbiote-view>
35
- <symbiote-view testID="b"></symbiote-view>
36
- </ScrollView>
37
- `,
38
- })(HorizontalNoRefreshApp);
39
-
40
- class HorizontalRefreshApp {
41
- refresh = (): void => {};
42
- }
43
- Component({
44
- selector: 'axis-projection-horizontal-refresh',
45
- standalone: true,
46
- imports: [ScrollView, RefreshControl],
47
- schemas: [CUSTOM_ELEMENTS_SCHEMA],
48
- template: `
49
- <ScrollView [horizontal]="true">
50
- <RefreshControl [refreshing]="true" (refresh)="refresh()" />
51
- <symbiote-view testID="a"></symbiote-view>
52
- <symbiote-view testID="b"></symbiote-view>
53
- </ScrollView>
54
- `,
55
- })(HorizontalRefreshApp);
56
-
57
- class VerticalNoRefreshApp {}
58
- Component({
59
- selector: 'axis-projection-vertical-no-refresh',
60
- standalone: true,
61
- imports: [ScrollView],
62
- schemas: [CUSTOM_ELEMENTS_SCHEMA],
63
- template: `
64
- <ScrollView>
65
- <symbiote-view testID="a"></symbiote-view>
66
- <symbiote-view testID="b"></symbiote-view>
67
- </ScrollView>
68
- `,
69
- })(VerticalNoRefreshApp);
70
-
71
- class AxisSwitchApp {
72
- static readonly horizontal = signal(false);
73
- get isHorizontal(): boolean {
74
- return AxisSwitchApp.horizontal();
75
- }
76
- }
77
- Component({
78
- selector: 'axis-projection-axis-switch',
79
- standalone: true,
80
- imports: [ScrollView],
81
- schemas: [CUSTOM_ELEMENTS_SCHEMA],
82
- template: `
83
- <ScrollView [horizontal]="isHorizontal">
84
- <symbiote-view testID="a"></symbiote-view>
85
- <symbiote-view testID="b"></symbiote-view>
86
- </ScrollView>
87
- `,
88
- })(AxisSwitchApp);
89
-
90
- beforeEach(() => fabric.reset());
91
- afterEach(() => unmount(ROOT_TAG));
92
-
93
- describe('Android ScrollView projects content across every axis x refresh combination', () => {
94
- it('horizontal, no refresh control', async () => {
95
- mount(ROOT_TAG, HorizontalNoRefreshApp);
96
- await tick();
97
- expectCellsProjected();
98
- });
99
-
100
- it('horizontal, with a projected refresh control', async () => {
101
- mount(ROOT_TAG, HorizontalRefreshApp);
102
- await tick();
103
- expectCellsProjected();
104
- });
105
-
106
- it('vertical, no refresh control', async () => {
107
- mount(ROOT_TAG, VerticalNoRefreshApp);
108
- await tick();
109
- expectCellsProjected();
110
- });
111
-
112
- it('survives a runtime vertical -> horizontal axis switch', async () => {
113
- AxisSwitchApp.horizontal.set(false);
114
- mount(ROOT_TAG, AxisSwitchApp);
115
- await tick();
116
- expectCellsProjected();
117
-
118
- AxisSwitchApp.horizontal.set(true);
119
- await tick();
120
- await tick();
121
- expectCellsProjected();
122
- });
123
- });
@@ -1,75 +0,0 @@
1
- // Regression guard: contentContainerStyle previously accepted ONLY a JS style object/array. It
2
- // now also resolves a class-name string through the shared style registry, same as `class`/
3
- // `style` (see shared.ts's resolvedContentContainerStyle getter). Mirrors the Vue twin
4
- // (content-container-style-class.test.ts) and scroll-view-class-style.test.ts's style-for-this-
5
- // exact-scenario shape.
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, type IFakeNode } from '@symbiote-native/test-utils';
11
-
12
- import { mount, unmount } from '../../render';
13
- import { ScrollView } from './index.ios';
14
-
15
- const ROOT_TAG = 952;
16
- const fabric = installFabric();
17
- const tick = (): Promise<void> => new Promise(resolve => setTimeout(resolve, 0));
18
-
19
- function committedContentView(): IFakeNode {
20
- const node = fabric.find(n => n.viewName === 'RCTScrollContentView');
21
- expect(node, 'the scroll content view was committed').toBeDefined();
22
- if (node === undefined) throw new Error('unreachable: content view missing');
23
- return node;
24
- }
25
-
26
- @Component({
27
- selector: 'symbiote-scroll-content-style-class-host',
28
- standalone: true,
29
- imports: [ScrollView],
30
- template: `
31
- <ScrollView [contentContainerStyle]="'padded'">
32
- <symbiote-text>content</symbiote-text>
33
- </ScrollView>
34
- `,
35
- })
36
- class ScrollViewContentStyleClassHost {}
37
-
38
- @Component({
39
- selector: 'symbiote-scroll-content-style-object-host',
40
- standalone: true,
41
- imports: [ScrollView],
42
- template: `
43
- <ScrollView [contentContainerStyle]="{ padding: 12 }">
44
- <symbiote-text>content</symbiote-text>
45
- </ScrollView>
46
- `,
47
- })
48
- class ScrollViewContentStyleObjectHost {}
49
-
50
- beforeEach(() => {
51
- fabric.reset();
52
- registerStyles({ padded: { padding: 20 } });
53
- });
54
- afterEach(() => {
55
- unmount(ROOT_TAG);
56
- clearGlobalStyles();
57
- });
58
-
59
- describe('ScrollView contentContainerStyle class-name support', () => {
60
- it('resolves a class-name string onto the content view, not the outer scroll view', async () => {
61
- mount(ROOT_TAG, ScrollViewContentStyleClassHost);
62
- await tick();
63
-
64
- expect(committedContentView().props.padding).toBe(20);
65
- const scrollHost = fabric.find(n => n.viewName === 'RCTScrollView');
66
- expect(scrollHost?.props.padding).toBeUndefined();
67
- });
68
-
69
- it('still accepts an ordinary style object unchanged', async () => {
70
- mount(ROOT_TAG, ScrollViewContentStyleObjectHost);
71
- await tick();
72
-
73
- expect(committedContentView().props.padding).toBe(12);
74
- });
75
- });