@symbiote-native/angular 3.3.0 → 3.4.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 (179) hide show
  1. package/babel-register-composed.cjs +1 -0
  2. package/build/angular/accessibility-inputs.d.ts +2 -1
  3. package/build/angular/accessibility-inputs.js +4 -1
  4. package/build/angular/accessibility-inputs.js.map +1 -1
  5. package/build/angular/callback-host.d.ts +1 -1
  6. package/build/angular/callback-host.js +57 -9
  7. package/build/angular/callback-host.js.map +1 -1
  8. package/build/angular/components/flat-list/flat-list-handle.d.ts +35 -0
  9. package/build/angular/components/flat-list/flat-list-handle.js +48 -0
  10. package/build/angular/components/flat-list/flat-list-handle.js.map +1 -0
  11. package/build/angular/components/flat-list/flat-list-template.d.ts +1 -1
  12. package/build/angular/components/flat-list/flat-list-template.js +16 -0
  13. package/build/angular/components/flat-list/flat-list-template.js.map +1 -1
  14. package/build/angular/components/flat-list/index.d.ts +6 -30
  15. package/build/angular/components/flat-list/index.js +6 -36
  16. package/build/angular/components/flat-list/index.js.map +1 -1
  17. package/build/angular/components/image-inputs.d.ts +4 -0
  18. package/build/angular/components/image-inputs.js +81 -0
  19. package/build/angular/components/image-inputs.js.map +1 -0
  20. package/build/angular/components/image-props-resolve.d.ts +3 -0
  21. package/build/angular/components/image-props-resolve.js +133 -0
  22. package/build/angular/components/image-props-resolve.js.map +1 -0
  23. package/build/angular/components/image-shared.d.ts +8 -6
  24. package/build/angular/components/image-shared.js +23 -212
  25. package/build/angular/components/image-shared.js.map +1 -1
  26. package/build/angular/components/input-accessory-view-props.d.ts +4 -4
  27. package/build/angular/components/keyboard-avoiding-view/index.d.ts +3 -6
  28. package/build/angular/components/keyboard-avoiding-view/index.js +29 -56
  29. package/build/angular/components/keyboard-avoiding-view/index.js.map +1 -1
  30. package/build/angular/components/layout-conformance-props.d.ts +4 -0
  31. package/build/angular/components/layout-conformance-props.js +2 -0
  32. package/build/angular/components/layout-conformance-props.js.map +1 -0
  33. package/build/angular/components/modal/index.d.ts +6 -5
  34. package/build/angular/components/modal/index.js +17 -2
  35. package/build/angular/components/modal/index.js.map +1 -1
  36. package/build/angular/components/refresh-control-props.d.ts +7 -7
  37. package/build/angular/components/scroll-view-props.d.ts +8 -5
  38. package/build/angular/components/section-list/index.d.ts +17 -8
  39. package/build/angular/components/section-list/index.js +37 -28
  40. package/build/angular/components/section-list/index.js.map +1 -1
  41. package/build/angular/components/touchable-props.d.ts +2 -2
  42. package/build/angular/components/virtualized-list/cell-renderer-context.d.ts +12 -0
  43. package/build/angular/components/virtualized-list/cell-renderer-context.js +16 -0
  44. package/build/angular/components/virtualized-list/cell-renderer-context.js.map +1 -0
  45. package/build/angular/components/virtualized-list/directives.d.ts +26 -6
  46. package/build/angular/components/virtualized-list/directives.js +59 -5
  47. package/build/angular/components/virtualized-list/directives.js.map +1 -1
  48. package/build/angular/components/virtualized-list/index.d.ts +19 -15
  49. package/build/angular/components/virtualized-list/index.js +91 -61
  50. package/build/angular/components/virtualized-list/index.js.map +1 -1
  51. package/build/angular/components/virtualized-list/list-bags.d.ts +5 -1
  52. package/build/angular/components/virtualized-list/list-bags.js +31 -19
  53. package/build/angular/components/virtualized-list/list-bags.js.map +1 -1
  54. package/build/angular/components/virtualized-list/list-effects.d.ts +2 -2
  55. package/build/angular/components/virtualized-list/list-effects.js +17 -27
  56. package/build/angular/components/virtualized-list/list-effects.js.map +1 -1
  57. package/build/angular/components/virtualized-list/list-handle.d.ts +4 -1
  58. package/build/angular/components/virtualized-list/list-handle.js +13 -3
  59. package/build/angular/components/virtualized-list/list-handle.js.map +1 -1
  60. package/build/angular/components/virtualized-list/list-inputs.d.ts +19 -5
  61. package/build/angular/components/virtualized-list/list-inputs.js +47 -4
  62. package/build/angular/components/virtualized-list/list-inputs.js.map +1 -1
  63. package/build/angular/components/virtualized-list/list-props.d.ts +9 -3
  64. package/build/angular/components/virtualized-list/list-rows.d.ts +25 -0
  65. package/build/angular/components/virtualized-list/list-rows.js +25 -0
  66. package/build/angular/components/virtualized-list/list-rows.js.map +1 -0
  67. package/build/angular/components/virtualized-list/list-styles.d.ts +4 -0
  68. package/build/angular/components/virtualized-list/list-styles.js +10 -2
  69. package/build/angular/components/virtualized-list/list-styles.js.map +1 -1
  70. package/build/angular/components/virtualized-list/list-template.d.ts +1 -1
  71. package/build/angular/components/virtualized-list/list-template.js +159 -73
  72. package/build/angular/components/virtualized-list/list-template.js.map +1 -1
  73. package/build/angular/components/virtualized-list/nested-scope.d.ts +6 -0
  74. package/build/angular/components/virtualized-list/nested-scope.js +17 -0
  75. package/build/angular/components/virtualized-list/nested-scope.js.map +1 -0
  76. package/build/angular/components/virtualized-section-list/directives.d.ts +21 -9
  77. package/build/angular/components/virtualized-section-list/directives.js +8 -28
  78. package/build/angular/components/virtualized-section-list/directives.js.map +1 -1
  79. package/build/angular/components/virtualized-section-list/index.d.ts +39 -60
  80. package/build/angular/components/virtualized-section-list/index.js +67 -33
  81. package/build/angular/components/virtualized-section-list/index.js.map +1 -1
  82. package/build/angular/components/virtualized-section-list/section-cell.d.ts +29 -0
  83. package/build/angular/components/virtualized-section-list/section-cell.js +82 -0
  84. package/build/angular/components/virtualized-section-list/section-cell.js.map +1 -0
  85. package/build/angular/components/virtualized-section-list/section-list-props.d.ts +56 -0
  86. package/build/angular/components/virtualized-section-list/section-list-props.js +3 -0
  87. package/build/angular/components/virtualized-section-list/section-list-props.js.map +1 -0
  88. package/build/angular/components/virtualized-section-list/section-list-template.d.ts +1 -1
  89. package/build/angular/components/virtualized-section-list/section-list-template.js +34 -26
  90. package/build/angular/components/virtualized-section-list/section-list-template.js.map +1 -1
  91. package/build/angular/components.d.ts +7 -3
  92. package/build/angular/components.js +2 -1
  93. package/build/angular/components.js.map +1 -1
  94. package/build/angular/element-base.d.ts +17 -1
  95. package/build/angular/element-base.js +33 -1
  96. package/build/angular/element-base.js.map +1 -1
  97. package/build/angular/element-props.d.ts +7 -7
  98. package/build/angular/element-text-input-native.d.ts +27 -0
  99. package/build/angular/element-text-input-native.js +52 -0
  100. package/build/angular/element-text-input-native.js.map +1 -0
  101. package/build/angular/elements-controls.d.ts +8 -2
  102. package/build/angular/elements-controls.js +13 -1
  103. package/build/angular/elements-controls.js.map +1 -1
  104. package/build/angular/elements-layout.d.ts +20 -3
  105. package/build/angular/elements-layout.js +37 -3
  106. package/build/angular/elements-layout.js.map +1 -1
  107. package/build/angular/elements-press.d.ts +10 -3
  108. package/build/angular/elements-press.js +13 -1
  109. package/build/angular/elements-press.js.map +1 -1
  110. package/build/angular/elements.d.ts +3 -3
  111. package/build/angular/elements.js +3 -2
  112. package/build/angular/elements.js.map +1 -1
  113. package/build/angular/index.d.ts +14 -7
  114. package/build/angular/index.js +21 -25
  115. package/build/angular/index.js.map +1 -1
  116. package/build/angular/modules/animated/create-animated-component.d.ts +1 -1
  117. package/build/angular/modules/animated/create-animated-component.js +1 -1
  118. package/build/angular/modules/animated/create-animated-component.js.map +1 -1
  119. package/build/angular/modules/animated/index.d.ts +54 -41
  120. package/build/angular/modules/animated/index.js +2 -26
  121. package/build/angular/modules/animated/index.js.map +1 -1
  122. package/build/angular/modules/app-registry/index.d.ts +3 -3
  123. package/build/angular/modules/app-registry/index.js +2 -2
  124. package/build/angular/modules/app-registry/index.js.map +1 -1
  125. package/build/angular/modules/status-bar/index.d.ts +9 -5
  126. package/build/angular/modules/status-bar/index.js +21 -10
  127. package/build/angular/modules/status-bar/index.js.map +1 -1
  128. package/build/angular/primitives/index.d.ts +4 -0
  129. package/build/angular/primitives/index.js +12 -0
  130. package/build/angular/primitives/index.js.map +1 -1
  131. package/build/angular/services/color-scheme.service.d.ts +1 -1
  132. package/package.json +6 -6
  133. package/src/accessibility-inputs.ts +3 -0
  134. package/src/callback-host.ts +56 -8
  135. package/src/components/flat-list/flat-list-handle.ts +64 -0
  136. package/src/components/flat-list/flat-list-template.ts +16 -0
  137. package/src/components/flat-list/index.ts +6 -48
  138. package/src/components/image-inputs.ts +94 -0
  139. package/src/components/image-props-resolve.ts +172 -0
  140. package/src/components/image-shared.ts +26 -291
  141. package/src/components/input-accessory-view-props.ts +12 -8
  142. package/src/components/keyboard-avoiding-view/index.ts +39 -79
  143. package/src/components/layout-conformance-props.ts +8 -0
  144. package/src/components/modal/index.ts +42 -20
  145. package/src/components/refresh-control-props.ts +29 -25
  146. package/src/components/scroll-view-props.ts +84 -76
  147. package/src/components/section-list/index.ts +34 -37
  148. package/src/components/touchable-props.ts +6 -2
  149. package/src/components/virtualized-list/cell-renderer-context.ts +36 -0
  150. package/src/components/virtualized-list/directives.ts +84 -8
  151. package/src/components/virtualized-list/index.ts +118 -85
  152. package/src/components/virtualized-list/list-bags.ts +38 -19
  153. package/src/components/virtualized-list/list-effects.ts +20 -32
  154. package/src/components/virtualized-list/list-handle.ts +17 -4
  155. package/src/components/virtualized-list/list-inputs.ts +47 -0
  156. package/src/components/virtualized-list/list-props.ts +57 -50
  157. package/src/components/virtualized-list/list-rows.ts +66 -0
  158. package/src/components/virtualized-list/list-styles.ts +30 -1
  159. package/src/components/virtualized-list/list-template.ts +159 -73
  160. package/src/components/virtualized-list/nested-scope.ts +22 -0
  161. package/src/components/virtualized-section-list/directives.ts +41 -40
  162. package/src/components/virtualized-section-list/index.ts +114 -118
  163. package/src/components/virtualized-section-list/section-cell.ts +109 -0
  164. package/src/components/virtualized-section-list/section-list-props.ts +79 -0
  165. package/src/components/virtualized-section-list/section-list-template.ts +34 -26
  166. package/src/components.ts +8 -0
  167. package/src/element-base.ts +17 -0
  168. package/src/element-props.ts +35 -33
  169. package/src/element-text-input-native.ts +31 -0
  170. package/src/elements-controls.ts +9 -1
  171. package/src/elements-layout.ts +27 -0
  172. package/src/elements-press.ts +10 -2
  173. package/src/elements.ts +3 -0
  174. package/src/index.ts +72 -22
  175. package/src/modules/animated/index.ts +2 -47
  176. package/src/modules/app-registry/index.ts +3 -1
  177. package/src/modules/status-bar/index.ts +24 -11
  178. package/src/primitives/index.ts +7 -0
  179. package/src/services/color-scheme.service.ts +1 -1
@@ -1,6 +1,4 @@
1
- // The input surface and prop fold `AnimatedImage` builds on. The primitive is the `<image>` tag
2
- // (`ImageElement`), which folds its source via `registerImageBehavior`; `Animated.Image` stays a
3
- // component and is the only consumer left, one flat file (`symbiote-file-layout`).
1
+ // The input surface and prop fold `Animated.Image` builds on, the `<image>` tag is `ImageElement`
4
2
  import { EventEmitter, computed, signal } from '@angular/core';
5
3
  import {
6
4
  gateWanted,
@@ -9,20 +7,12 @@ import {
9
7
  } from '../gate-demand';
10
8
  import {
11
9
  imageStatics,
12
- renderImage,
13
- resolveAccessibilityProps,
14
10
  type IAccessibilityProps,
15
11
  type IAriaProps,
16
12
  type IImageProps,
17
- type IImageSourceProp,
18
- type IResizeMode,
19
13
  } from '@symbiote-native/components';
20
- import {
21
- isSymbioteEvent,
22
- type IStyleProp,
23
- type ISymbioteEvent,
24
- type IViewStyle,
25
- } from '@symbiote-native/engine';
14
+ import { isSymbioteEvent, type ISymbioteEvent } from '@symbiote-native/engine';
15
+ import { resolveImageProps } from './image-props-resolve';
26
16
 
27
17
  export { setImageSourceResolver } from '@symbiote-native/components';
28
18
  export type {
@@ -33,284 +23,8 @@ export type {
33
23
  IImageSize,
34
24
  IImageCacheStatus,
35
25
  } from '@symbiote-native/components';
36
-
37
- export const IMAGE_INPUTS = [
38
- 'source',
39
- 'defaultSource',
40
- 'loadingIndicatorSource',
41
- 'style',
42
- 'resizeMode',
43
- 'resizeMethod',
44
- 'tintColor',
45
- 'blurRadius',
46
- 'capInsets',
47
- 'fadeDuration',
48
- 'progressiveRenderingEnabled',
49
- 'src',
50
- 'srcSet',
51
- 'alt',
52
- 'width',
53
- 'height',
54
- 'crossOrigin',
55
- 'referrerPolicy',
56
- 'testID',
57
- 'nativeID',
58
- 'accessible',
59
- 'accessibilityLabel',
60
- 'accessibilityHint',
61
- 'accessibilityRole',
62
- 'accessibilityState',
63
- 'accessibilityValue',
64
- 'accessibilityActions',
65
- 'accessibilityLabelledBy',
66
- 'importantForAccessibility',
67
- 'accessibilityLiveRegion',
68
- 'screenReaderFocusable',
69
- 'accessibilityViewIsModal',
70
- 'accessibilityElementsHidden',
71
- 'accessibilityIgnoresInvertColors',
72
- 'accessibilityLanguage',
73
- 'accessibilityRespondsToUserInteraction',
74
- 'accessibilityShowsLargeContentViewer',
75
- 'accessibilityLargeContentTitle',
76
- 'role',
77
- 'ariaLabel: aria-label',
78
- 'ariaLabelledBy: aria-labelledby',
79
- 'ariaLive: aria-live',
80
- 'ariaHidden: aria-hidden',
81
- 'ariaBusy: aria-busy',
82
- 'ariaChecked: aria-checked',
83
- 'ariaDisabled: aria-disabled',
84
- 'ariaExpanded: aria-expanded',
85
- 'ariaSelected: aria-selected',
86
- 'ariaModal: aria-modal',
87
- 'ariaValueMax: aria-valuemax',
88
- 'ariaValueMin: aria-valuemin',
89
- 'ariaValueNow: aria-valuenow',
90
- 'ariaValueText: aria-valuetext',
91
- 'onAccessibilityAction',
92
- 'onAccessibilityTap',
93
- 'onMagicTap',
94
- 'onAccessibilityEscape',
95
- 'onLoadStart',
96
- 'onLoad',
97
- 'onLoadEnd',
98
- 'onError',
99
- 'onProgress',
100
- 'onPartialLoad',
101
- ];
102
-
103
- export const IMAGE_OUTPUTS = [
104
- 'accessibilityAction',
105
- 'accessibilityTap',
106
- 'magicTap',
107
- 'accessibilityEscape',
108
- 'loadStart',
109
- 'load',
110
- 'loadEnd',
111
- 'error',
112
- 'progress',
113
- 'partialLoad',
114
- ];
115
-
116
- type IImagePassthroughProps = Record<string, unknown> &
117
- IAccessibilityProps &
118
- IAriaProps &
119
- Pick<
120
- IImageProps,
121
- | 'resizeMethod'
122
- | 'blurRadius'
123
- | 'capInsets'
124
- | 'fadeDuration'
125
- | 'progressiveRenderingEnabled'
126
- | 'onLoadStart'
127
- | 'onLoad'
128
- | 'onLoadEnd'
129
- | 'onError'
130
- | 'onProgress'
131
- | 'onPartialLoad'
132
- >;
133
-
134
- function asSource(value: unknown): IImageSourceProp | undefined {
135
- if (typeof value === 'number') return value;
136
- if (typeof value === 'object' && value !== null) return value;
137
- return undefined;
138
- }
139
-
140
- function asResizeMode(value: unknown): IResizeMode | undefined {
141
- if (
142
- value === 'cover' ||
143
- value === 'contain' ||
144
- value === 'stretch' ||
145
- value === 'repeat' ||
146
- value === 'center'
147
- ) {
148
- return value;
149
- }
150
- return undefined;
151
- }
152
-
153
- function asString(value: unknown): string | undefined {
154
- return typeof value === 'string' ? value : undefined;
155
- }
156
-
157
- function asNumber(value: unknown): number | undefined {
158
- return typeof value === 'number' ? value : undefined;
159
- }
160
-
161
- function asCrossOrigin(
162
- value: unknown,
163
- ): 'anonymous' | 'use-credentials' | undefined {
164
- return value === 'anonymous' || value === 'use-credentials'
165
- ? value
166
- : undefined;
167
- }
168
-
169
- function asStyle(value: unknown): IStyleProp<IViewStyle> | undefined {
170
- return typeof value === 'object' && value !== null ? value : undefined;
171
- }
172
-
173
- // Narrows a value out of the untyped animated prop bag. A runtime guard rather than a cast: the
174
- // bag is built at runtime from merged animated values, so nothing upstream has proven the shape.
175
- export function isImageEventCallback(
176
- value: unknown,
177
- ): value is (event: ISymbioteEvent) => void {
178
- return typeof value === 'function';
179
- }
180
-
181
- export function resolveImageProps(
182
- input: Record<string, unknown>,
183
- ): Record<string, unknown> {
184
- const passthrough: IImagePassthroughProps = {
185
- resizeMethod: input['resizeMethod'] as IImageProps['resizeMethod'],
186
- blurRadius: asNumber(input['blurRadius']),
187
- capInsets: input['capInsets'] as IImageProps['capInsets'],
188
- fadeDuration: asNumber(input['fadeDuration']),
189
- progressiveRenderingEnabled:
190
- typeof input['progressiveRenderingEnabled'] === 'boolean'
191
- ? input['progressiveRenderingEnabled']
192
- : undefined,
193
- testID: asString(input['testID']),
194
- nativeID: asString(input['nativeID']),
195
- accessible:
196
- typeof input['accessible'] === 'boolean'
197
- ? input['accessible']
198
- : undefined,
199
- accessibilityLabel: asString(input['accessibilityLabel']),
200
- accessibilityHint: asString(input['accessibilityHint']),
201
- accessibilityRole: input[
202
- 'accessibilityRole'
203
- ] as IAccessibilityProps['accessibilityRole'],
204
- accessibilityState: input[
205
- 'accessibilityState'
206
- ] as IAccessibilityProps['accessibilityState'],
207
- accessibilityValue: input[
208
- 'accessibilityValue'
209
- ] as IAccessibilityProps['accessibilityValue'],
210
- accessibilityActions: input[
211
- 'accessibilityActions'
212
- ] as IAccessibilityProps['accessibilityActions'],
213
- accessibilityLabelledBy: input[
214
- 'accessibilityLabelledBy'
215
- ] as IAccessibilityProps['accessibilityLabelledBy'],
216
- importantForAccessibility: input[
217
- 'importantForAccessibility'
218
- ] as IAccessibilityProps['importantForAccessibility'],
219
- accessibilityLiveRegion: input[
220
- 'accessibilityLiveRegion'
221
- ] as IAccessibilityProps['accessibilityLiveRegion'],
222
- screenReaderFocusable:
223
- typeof input['screenReaderFocusable'] === 'boolean'
224
- ? input['screenReaderFocusable']
225
- : undefined,
226
- accessibilityViewIsModal:
227
- typeof input['accessibilityViewIsModal'] === 'boolean'
228
- ? input['accessibilityViewIsModal']
229
- : undefined,
230
- accessibilityElementsHidden:
231
- typeof input['accessibilityElementsHidden'] === 'boolean'
232
- ? input['accessibilityElementsHidden']
233
- : undefined,
234
- accessibilityIgnoresInvertColors:
235
- typeof input['accessibilityIgnoresInvertColors'] === 'boolean'
236
- ? input['accessibilityIgnoresInvertColors']
237
- : undefined,
238
- accessibilityLanguage: asString(input['accessibilityLanguage']),
239
- accessibilityRespondsToUserInteraction:
240
- typeof input['accessibilityRespondsToUserInteraction'] === 'boolean'
241
- ? input['accessibilityRespondsToUserInteraction']
242
- : undefined,
243
- accessibilityShowsLargeContentViewer:
244
- typeof input['accessibilityShowsLargeContentViewer'] === 'boolean'
245
- ? input['accessibilityShowsLargeContentViewer']
246
- : undefined,
247
- accessibilityLargeContentTitle: asString(
248
- input['accessibilityLargeContentTitle'],
249
- ),
250
- role: input['role'] as IAriaProps['role'],
251
- 'aria-label': asString(input['ariaLabel'] ?? input['aria-label']),
252
- 'aria-labelledby': asString(
253
- input['ariaLabelledBy'] ?? input['aria-labelledby'],
254
- ),
255
- 'aria-live': input['ariaLive'] as IAriaProps['aria-live'],
256
- 'aria-hidden':
257
- typeof input['ariaHidden'] === 'boolean'
258
- ? input['ariaHidden']
259
- : undefined,
260
- 'aria-busy':
261
- typeof input['ariaBusy'] === 'boolean' ? input['ariaBusy'] : undefined,
262
- 'aria-checked': input['ariaChecked'] as IAriaProps['aria-checked'],
263
- 'aria-disabled':
264
- typeof input['ariaDisabled'] === 'boolean'
265
- ? input['ariaDisabled']
266
- : undefined,
267
- 'aria-expanded':
268
- typeof input['ariaExpanded'] === 'boolean'
269
- ? input['ariaExpanded']
270
- : undefined,
271
- 'aria-selected':
272
- typeof input['ariaSelected'] === 'boolean'
273
- ? input['ariaSelected']
274
- : undefined,
275
- 'aria-modal':
276
- typeof input['ariaModal'] === 'boolean' ? input['ariaModal'] : undefined,
277
- 'aria-valuemax': asNumber(input['ariaValueMax']),
278
- 'aria-valuemin': asNumber(input['ariaValueMin']),
279
- 'aria-valuenow': asNumber(input['ariaValueNow']),
280
- 'aria-valuetext': asString(input['ariaValueText']),
281
- onAccessibilityAction: input[
282
- 'onAccessibilityAction'
283
- ] as IImageProps['onLoad'],
284
- onAccessibilityTap: input['onAccessibilityTap'] as IImageProps['onLoad'],
285
- onMagicTap: input['onMagicTap'] as IImageProps['onLoad'],
286
- onAccessibilityEscape: input[
287
- 'onAccessibilityEscape'
288
- ] as IImageProps['onLoad'],
289
- onLoadStart: input['onLoadStart'] as IImageProps['onLoadStart'],
290
- onLoad: input['onLoad'] as IImageProps['onLoad'],
291
- onLoadEnd: input['onLoadEnd'] as IImageProps['onLoadEnd'],
292
- onError: input['onError'] as IImageProps['onError'],
293
- onProgress: input['onProgress'] as IImageProps['onProgress'],
294
- onPartialLoad: input['onPartialLoad'] as IImageProps['onPartialLoad'],
295
- };
296
-
297
- return renderImage({
298
- source: asSource(input['source']),
299
- defaultSource: asSource(input['defaultSource']),
300
- loadingIndicatorSource: asSource(input['loadingIndicatorSource']),
301
- style: asStyle(input['style']),
302
- resizeMode: asResizeMode(input['resizeMode']),
303
- tintColor: asString(input['tintColor']),
304
- src: asString(input['src']),
305
- srcSet: asString(input['srcSet']),
306
- alt: asString(input['alt']),
307
- width: asNumber(input['width']),
308
- height: asNumber(input['height']),
309
- crossOrigin: asCrossOrigin(input['crossOrigin']),
310
- referrerPolicy: asString(input['referrerPolicy']),
311
- passthrough: resolveAccessibilityProps(passthrough),
312
- }).props;
313
- }
26
+ export { IMAGE_INPUTS, IMAGE_OUTPUTS } from './image-inputs';
27
+ export { isImageEventCallback, resolveImageProps } from './image-props-resolve';
314
28
 
315
29
  export abstract class ImageBase {
316
30
  static readonly getSize = imageStatics.getSize;
@@ -326,6 +40,7 @@ export abstract class ImageBase {
326
40
  style: unknown;
327
41
  resizeMode: unknown;
328
42
  resizeMethod: IImageProps['resizeMethod'];
43
+ resizeMultiplier: number | undefined;
329
44
  tintColor: unknown;
330
45
  blurRadius: number | undefined;
331
46
  capInsets: IImageProps['capInsets'];
@@ -462,7 +177,16 @@ export abstract class ImageBase {
462
177
  this.partialLoad.emit(event);
463
178
  }
464
179
 
180
+ // Three groups, so no single getter holds every input name at once
465
181
  protected get imageInputProps(): Record<string, unknown> {
182
+ return {
183
+ ...this.sourceInputProps,
184
+ ...this.accessibilityInputProps,
185
+ ...this.handlerInputProps,
186
+ };
187
+ }
188
+
189
+ private get sourceInputProps(): Record<string, unknown> {
466
190
  return {
467
191
  source: this.source,
468
192
  defaultSource: this.defaultSource,
@@ -470,6 +194,7 @@ export abstract class ImageBase {
470
194
  style: this.style,
471
195
  resizeMode: this.resizeMode,
472
196
  resizeMethod: this.resizeMethod,
197
+ resizeMultiplier: this.resizeMultiplier,
473
198
  tintColor: this.tintColor,
474
199
  blurRadius: this.blurRadius,
475
200
  capInsets: this.capInsets,
@@ -482,6 +207,11 @@ export abstract class ImageBase {
482
207
  height: this.height,
483
208
  crossOrigin: this.crossOrigin,
484
209
  referrerPolicy: this.referrerPolicy,
210
+ };
211
+ }
212
+
213
+ private get accessibilityInputProps(): Record<string, unknown> {
214
+ return {
485
215
  testID: this.testID,
486
216
  nativeID: this.nativeID,
487
217
  accessible: this.accessible,
@@ -519,6 +249,11 @@ export abstract class ImageBase {
519
249
  ariaValueMin: this.ariaValueMin,
520
250
  ariaValueNow: this.ariaValueNow,
521
251
  ariaValueText: this.ariaValueText,
252
+ };
253
+ }
254
+
255
+ private get handlerInputProps(): Record<string, unknown> {
256
+ return {
522
257
  onAccessibilityAction: this.gatedAccessibilityHandler(
523
258
  'accessibilityAction',
524
259
  this.onAccessibilityAction,
@@ -9,12 +9,16 @@ import type {
9
9
  IAccessibilityProps,
10
10
  IAriaProps,
11
11
  } from '@symbiote-native/components';
12
- import type { IStyleProp, IViewStyle } from '@symbiote-native/engine';
12
+ import type {
13
+ IColorValue,
14
+ IStyleProp,
15
+ IViewStyle,
16
+ } from '@symbiote-native/engine';
13
17
 
14
- export interface IAngularInputAccessoryViewProps
15
- extends IAccessibilityProps, IAriaProps {
16
- // The id a TextInput's inputAccessoryViewID points at to dock above its keyboard.
17
- nativeID?: string;
18
- backgroundColor?: string;
19
- style?: IStyleProp<IViewStyle>;
20
- }
18
+ export type IAngularInputAccessoryViewProps = IAccessibilityProps &
19
+ IAriaProps & {
20
+ // The id a TextInput's inputAccessoryViewID points at to dock above its keyboard.
21
+ nativeID?: string;
22
+ backgroundColor?: IColorValue;
23
+ style?: IStyleProp<IViewStyle>;
24
+ };
@@ -25,12 +25,8 @@ import {
25
25
  type OnInit,
26
26
  } from '@angular/core';
27
27
  import {
28
- computeInset,
29
- configureKeyboardAvoidingAnimation,
28
+ createKeyboardAvoidingModel,
30
29
  keyboardAvoidingEventNamesFor,
31
- readKeyboardAnimationTiming,
32
- readKeyboardFrame,
33
- readLayoutFrame,
34
30
  readPrefersCrossFadeTransitions,
35
31
  resolveAccessibilityProps,
36
32
  resolveKeyboardAvoidingLayout,
@@ -39,12 +35,10 @@ import {
39
35
  type IAriaProps,
40
36
  type IKeyboardAvoidingBehavior,
41
37
  type IKeyboardAvoidingLayout,
42
- type IMeasuredFrame,
43
38
  } from '@symbiote-native/components';
44
39
  import {
45
40
  Keyboard,
46
41
  Platform,
47
- dlog,
48
42
  isSymbioteEvent,
49
43
  type IEventSubscription,
50
44
  type IStyleProp,
@@ -64,15 +58,15 @@ export type { IKeyboardAvoidingBehavior } from '@symbiote-native/components';
64
58
  // Mirrors React's IKeyboardAvoidingViewProps minus children (Angular takes children via
65
59
  // <ng-content>), declared per-adapter over the shared accessibility base since a framework-specific
66
60
  // children field keeps it from being fully shared across adapters.
67
- export interface IAngularKeyboardAvoidingViewProps
68
- extends IAccessibilityProps, IAriaProps {
69
- behavior?: IKeyboardAvoidingBehavior;
70
- enabled?: boolean;
71
- keyboardVerticalOffset?: number;
72
- contentContainerStyle?: IStyleProp<IViewStyle>;
73
- style?: IStyleProp<IViewStyle>;
74
- onLayout?: (event: ISymbioteEvent) => void;
75
- }
61
+ export type IAngularKeyboardAvoidingViewProps = IAccessibilityProps &
62
+ IAriaProps & {
63
+ behavior?: IKeyboardAvoidingBehavior;
64
+ enabled?: boolean;
65
+ keyboardVerticalOffset?: number;
66
+ contentContainerStyle?: IStyleProp<IViewStyle>;
67
+ style?: IStyleProp<IViewStyle>;
68
+ onLayout?: (event: ISymbioteEvent) => void;
69
+ };
76
70
 
77
71
  // What the component itself takes as plain @Input()s: the full surface minus onLayout and the
78
72
  // accessibility callbacks, which it exposes as real @Output() EventEmitters instead (see the
@@ -133,36 +127,41 @@ export class KeyboardAvoidingView
133
127
  @Input() testID?: string;
134
128
  @Input() nativeID?: string;
135
129
 
136
- // How far the view must move so it no longer overlaps the keyboard. A plain field, not reactive:
137
- // OnPush + zoneless means a keyboard event mutates it and pulls the view via markForCheck.
130
+ // Plain field, the model sets it and `markForCheck` pulls the OnPush view
138
131
  private inset = 0;
139
- // Mutable, not state: changing the measured frame alone shouldn't re-render; it feeds the next
140
- // keyboard event's inset math (React's frameRef / initialHeightRef, Vue's frame / initialHeight).
141
- private frame?: IMeasuredFrame;
142
- private initialHeight?: number;
143
- // The iOS "Prefer Cross-Fade Transitions" setting, read once per mount. Deliberately a plain
144
- // field and NOT markForCheck'd when the promise lands: it is a device setting that cannot change
145
- // mid-session, and it feeds only the NEXT keyboard event's math — never the current render — so
146
- // under zoneless CD there is nothing to repaint at resolve time. The keyboard event that does use
147
- // it already calls markForCheck itself.
132
+ // A device setting that cannot change mid-session, learning it must not repaint
148
133
  private prefersCrossFadeTransitions = false;
149
134
  private subscriptions: IEventSubscription[] = [];
150
135
 
151
136
  private readonly changeDetector = inject(ChangeDetectorRef);
152
- // This component's OWN host — the non-painting anchor `class="..."` at the use site resolves
153
- // onto (see anchorHostStyle's doc comment) — NOT a ViewChild into the inner view (this
154
- // component has none; the wrapper IS the outer template node hostProps binds onto).
137
+ // This component's own host, the anchor that `class` at the use site resolves onto
155
138
  private readonly elementRef = inject(ElementRef);
156
139
 
140
+ // Options are read at event time, т.к. an `@Input` can change under a live subscription
141
+ private readonly model = createKeyboardAvoidingModel({
142
+ options: () => ({
143
+ behavior: this.behavior,
144
+ enabled: this.enabled !== false,
145
+ keyboardVerticalOffset:
146
+ this.keyboardVerticalOffset ?? DEFAULT_VERTICAL_OFFSET,
147
+ }),
148
+ setInset: value => {
149
+ this.inset = value;
150
+ this.changeDetector.markForCheck();
151
+ },
152
+ prefersCrossFade: () => this.prefersCrossFadeTransitions,
153
+ });
154
+
157
155
  ngOnInit(): void {
158
- // TWO events, picked per host, never three: iOS takes the will* pair so the view rides up with
159
- // the keyboard animation, Android the did* pair. The change-frame notification is deliberately
160
- // absent — with an undocked/split/floating iOS keyboard it fires BEFORE the hide, so listening
161
- // to it applies a frame captured mid-dismissal (RN KeyboardAvoidingView.js's own comment).
156
+ // iOS takes the `will*` pair so the view rides up with the keyboard, Android the `did*` pair
162
157
  const events = keyboardAvoidingEventNamesFor(Platform.OS);
163
158
  this.subscriptions = [
164
- Keyboard.addListener(events.show, payload => this.onShow(payload)),
165
- Keyboard.addListener(events.hide, () => this.onHide()),
159
+ Keyboard.addListener(events.show, payload => {
160
+ this.model.keyboardShown(payload);
161
+ // An unchanged inset skips `setInset`, the event still has to carry a new `@Input` down
162
+ this.changeDetector.markForCheck();
163
+ }),
164
+ Keyboard.addListener(events.hide, this.model.keyboardHidden),
166
165
  ];
167
166
  // The core wrapper, not AccessibilityInfo directly: the engine's iOS getter REJECTS on a
168
167
  // native error (RN parity), and nobody awaits this read, so an unwrapped call would surface
@@ -177,47 +176,10 @@ export class KeyboardAvoidingView
177
176
  this.subscriptions = [];
178
177
  }
179
178
 
180
- private onShow(payload: unknown): void {
181
- const keyboard = readKeyboardFrame(payload);
182
- const offset = this.keyboardVerticalOffset ?? DEFAULT_VERTICAL_OFFSET;
183
- const next = computeInset(this.frame, keyboard, offset, {
184
- // Read off the field at event time, not captured when the subscription was built: `behavior`
185
- // is an @Input that can change under a long-lived subscription, and a stale one keeps
186
- // applying the old mode's math (it gates the previous-inset correction below).
187
- behavior: this.behavior,
188
- // The inset CURRENTLY applied (RN's this.state.bottom), read off the field at event time so
189
- // 'height' mode's fixpoint correction sees the live value: that mode SHRINKS the wrapper by
190
- // the inset, so the next onLayout reports a frame shorter by exactly that much.
191
- previousInset: this.inset,
192
- prefersCrossFadeTransitions: this.prefersCrossFadeTransitions,
193
- });
194
- // RN's `_updateBottomIfNecessary` skips the animation when the inset did not change.
195
- if (next !== this.inset)
196
- configureKeyboardAvoidingAnimation(
197
- readKeyboardAnimationTiming(payload),
198
- this.enabled !== false,
199
- );
200
- dlog(`KeyboardAvoidingView show -> inset ${next}`);
201
- this.inset = next;
202
- this.changeDetector.markForCheck();
203
- }
204
-
205
- private onHide(): void {
206
- dlog('KeyboardAvoidingView hide -> inset 0');
207
- this.inset = 0;
208
- this.changeDetector.markForCheck();
209
- }
210
-
211
- // The wrapper's onLayout measures the frame BEFORE forwarding to the caller's onLayout, so the
212
- // next keyboard event's inset math has the view's real position (React/Vue's handleLayout).
179
+ // Measured before the caller's `layout` output fires
213
180
  handleLayout(event: unknown): void {
214
181
  if (!isSymbioteEvent(event)) return;
215
- const measured = readLayoutFrame(event.nativeEvent.layout);
216
- if (measured !== undefined) {
217
- this.frame = measured;
218
- if (this.initialHeight === undefined)
219
- this.initialHeight = measured.height;
220
- }
182
+ this.model.laidOut(event.nativeEvent.layout);
221
183
  this.layout.emit(event);
222
184
  }
223
185
 
@@ -227,14 +189,12 @@ export class KeyboardAvoidingView
227
189
  return this.enabled === false ? 0 : this.inset;
228
190
  }
229
191
 
230
- // The behavior + effective inset → wrapper/inner styles and the nesting decision (the shared core
231
- // of RN's render). Recomputed per CD pass, the Angular twin of React/Vue's per-render call.
232
- // Named `resolvedLayout`, not `layout` — that name is now the onLayout @Output() EventEmitter.
192
+ // Not `layout`, that name is the `onLayout` output
233
193
  private get resolvedLayout(): IKeyboardAvoidingLayout {
234
194
  return resolveKeyboardAvoidingLayout({
235
195
  behavior: this.behavior,
236
196
  effectiveInset: this.effectiveInset,
237
- initialHeight: this.initialHeight,
197
+ initialHeight: this.model.initialHeight(),
238
198
  style: this.style,
239
199
  contentContainerStyle: this.contentContainerStyle,
240
200
  });
@@ -0,0 +1,8 @@
1
+ // The prop surface of `<layout-conformance>`, RN's `experimental_LayoutConformance`, for Angular
2
+ // Children come through `<ng-content>`, so there is no `children` here
3
+ import type { ILayoutConformanceMode } from '@symbiote-native/components';
4
+
5
+ export type IAngularLayoutConformanceProps = {
6
+ // `strict` lays out by the W3C spec even where it breaks compatibility
7
+ mode: ILayoutConformanceMode;
8
+ };