@symbiote-native/angular 3.1.3 → 3.3.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 (165) hide show
  1. package/babel-register-composed.cjs +1 -0
  2. package/build/angular/accessibility-events.d.ts +12 -0
  3. package/build/angular/accessibility-events.js +28 -0
  4. package/build/angular/accessibility-events.js.map +1 -0
  5. package/build/angular/accessibility-inputs.d.ts +40 -0
  6. package/build/angular/accessibility-inputs.js +130 -0
  7. package/build/angular/accessibility-inputs.js.map +1 -0
  8. package/build/angular/bootstrap.d.ts +3 -1
  9. package/build/angular/bootstrap.js +4 -1
  10. package/build/angular/bootstrap.js.map +1 -1
  11. package/build/angular/components/checkbox-props.d.ts +2 -0
  12. package/build/angular/components/checkbox-props.js +2 -0
  13. package/build/angular/components/checkbox-props.js.map +1 -0
  14. package/build/angular/components/flat-list/flat-list-template.d.ts +1 -0
  15. package/build/angular/components/flat-list/flat-list-template.js +158 -0
  16. package/build/angular/components/flat-list/flat-list-template.js.map +1 -0
  17. package/build/angular/components/flat-list/index.d.ts +6 -61
  18. package/build/angular/components/flat-list/index.js +26 -463
  19. package/build/angular/components/flat-list/index.js.map +1 -1
  20. package/build/angular/components/keyboard-avoiding-view/index.d.ts +4 -40
  21. package/build/angular/components/keyboard-avoiding-view/index.js +7 -131
  22. package/build/angular/components/keyboard-avoiding-view/index.js.map +1 -1
  23. package/build/angular/components/modal/index.d.ts +5 -41
  24. package/build/angular/components/modal/index.js +8 -133
  25. package/build/angular/components/modal/index.js.map +1 -1
  26. package/build/angular/components/section-list/index.d.ts +4 -51
  27. package/build/angular/components/section-list/index.js +18 -335
  28. package/build/angular/components/section-list/index.js.map +1 -1
  29. package/build/angular/components/virtualized-list/cell-registry.d.ts +35 -0
  30. package/build/angular/components/virtualized-list/cell-registry.js +133 -0
  31. package/build/angular/components/virtualized-list/cell-registry.js.map +1 -0
  32. package/build/angular/components/virtualized-list/index.d.ts +18 -253
  33. package/build/angular/components/virtualized-list/index.js +112 -1178
  34. package/build/angular/components/virtualized-list/index.js.map +1 -1
  35. package/build/angular/components/virtualized-list/list-a11y-forward.d.ts +1 -0
  36. package/build/angular/components/virtualized-list/list-a11y-forward.js +42 -0
  37. package/build/angular/components/virtualized-list/list-a11y-forward.js.map +1 -0
  38. package/build/angular/components/virtualized-list/list-bags.d.ts +32 -0
  39. package/build/angular/components/virtualized-list/list-bags.js +120 -0
  40. package/build/angular/components/virtualized-list/list-bags.js.map +1 -0
  41. package/build/angular/components/virtualized-list/list-effects.d.ts +31 -0
  42. package/build/angular/components/virtualized-list/list-effects.js +83 -0
  43. package/build/angular/components/virtualized-list/list-effects.js.map +1 -0
  44. package/build/angular/components/virtualized-list/list-events.d.ts +17 -0
  45. package/build/angular/components/virtualized-list/list-events.js +34 -0
  46. package/build/angular/components/virtualized-list/list-events.js.map +1 -0
  47. package/build/angular/components/virtualized-list/list-handle.d.ts +35 -0
  48. package/build/angular/components/virtualized-list/list-handle.js +61 -0
  49. package/build/angular/components/virtualized-list/list-handle.js.map +1 -0
  50. package/build/angular/components/virtualized-list/list-inputs.d.ts +78 -0
  51. package/build/angular/components/virtualized-list/list-inputs.js +150 -0
  52. package/build/angular/components/virtualized-list/list-inputs.js.map +1 -0
  53. package/build/angular/components/virtualized-list/list-props.d.ts +58 -0
  54. package/build/angular/components/virtualized-list/list-props.js +3 -0
  55. package/build/angular/components/virtualized-list/list-props.js.map +1 -0
  56. package/build/angular/components/virtualized-list/list-styles.d.ts +23 -0
  57. package/build/angular/components/virtualized-list/list-styles.js +26 -0
  58. package/build/angular/components/virtualized-list/list-styles.js.map +1 -0
  59. package/build/angular/components/virtualized-list/list-template.d.ts +1 -0
  60. package/build/angular/components/virtualized-list/list-template.js +176 -0
  61. package/build/angular/components/virtualized-list/list-template.js.map +1 -0
  62. package/build/angular/components/virtualized-section-list/index.d.ts +13 -70
  63. package/build/angular/components/virtualized-section-list/index.js +22 -455
  64. package/build/angular/components/virtualized-section-list/index.js.map +1 -1
  65. package/build/angular/components/virtualized-section-list/section-list-template.d.ts +1 -0
  66. package/build/angular/components/virtualized-section-list/section-list-template.js +107 -0
  67. package/build/angular/components/virtualized-section-list/section-list-template.js.map +1 -0
  68. package/build/angular/components.d.ts +1 -0
  69. package/build/angular/components.js.map +1 -1
  70. package/build/angular/descriptor-to-angular/descriptor-host.d.ts +8 -0
  71. package/build/angular/descriptor-to-angular/descriptor-host.js +38 -0
  72. package/build/angular/descriptor-to-angular/descriptor-host.js.map +1 -0
  73. package/build/angular/descriptor-to-angular/index.d.ts +1 -0
  74. package/build/angular/descriptor-to-angular/index.js +4 -0
  75. package/build/angular/descriptor-to-angular/index.js.map +1 -1
  76. package/build/angular/element-base.d.ts +153 -0
  77. package/build/angular/element-base.js +272 -0
  78. package/build/angular/element-base.js.map +1 -0
  79. package/build/angular/elements-controls.d.ts +165 -0
  80. package/build/angular/elements-controls.js +382 -0
  81. package/build/angular/elements-controls.js.map +1 -0
  82. package/build/angular/elements-layout.d.ts +122 -0
  83. package/build/angular/elements-layout.js +242 -0
  84. package/build/angular/elements-layout.js.map +1 -0
  85. package/build/angular/elements-press.d.ts +96 -0
  86. package/build/angular/elements-press.js +227 -0
  87. package/build/angular/elements-press.js.map +1 -0
  88. package/build/angular/elements.d.ts +6 -516
  89. package/build/angular/elements.js +8 -1091
  90. package/build/angular/elements.js.map +1 -1
  91. package/build/angular/finalization-registry.d.ts +4 -0
  92. package/build/angular/finalization-registry.js +17 -0
  93. package/build/angular/finalization-registry.js.map +1 -0
  94. package/build/angular/host-instance/index.d.ts +2 -0
  95. package/build/angular/host-instance/index.js +4 -4
  96. package/build/angular/host-instance/index.js.map +1 -1
  97. package/build/angular/index.d.ts +9 -4
  98. package/build/angular/index.js +8 -3
  99. package/build/angular/index.js.map +1 -1
  100. package/build/angular/native-view-base.d.ts +27 -0
  101. package/build/angular/native-view-base.js +69 -0
  102. package/build/angular/native-view-base.js.map +1 -0
  103. package/build/angular/render/index.d.ts +2 -1
  104. package/build/angular/render/index.js +46 -73
  105. package/build/angular/render/index.js.map +1 -1
  106. package/build/angular/services/connect-watched-signal.d.ts +2 -0
  107. package/build/angular/services/connect-watched-signal.js +9 -0
  108. package/build/angular/services/connect-watched-signal.js.map +1 -0
  109. package/build/angular/services/create-event-value-hook.d.ts +3 -0
  110. package/build/angular/services/create-event-value-hook.js +17 -0
  111. package/build/angular/services/create-event-value-hook.js.map +1 -0
  112. package/build/angular/services/create-resource-hook.d.ts +7 -0
  113. package/build/angular/services/create-resource-hook.js +20 -0
  114. package/build/angular/services/create-resource-hook.js.map +1 -0
  115. package/build/angular/services/index.d.ts +5 -0
  116. package/build/angular/services/index.js +5 -0
  117. package/build/angular/services/index.js.map +1 -1
  118. package/build/angular/services/inject-event.d.ts +6 -0
  119. package/build/angular/services/inject-event.js +24 -0
  120. package/build/angular/services/inject-event.js.map +1 -0
  121. package/build/angular/services/permissions-service-base.d.ts +14 -0
  122. package/build/angular/services/permissions-service-base.js +38 -0
  123. package/build/angular/services/permissions-service-base.js.map +1 -0
  124. package/package.json +6 -6
  125. package/src/accessibility-events.ts +13 -0
  126. package/src/accessibility-inputs.ts +89 -0
  127. package/src/bootstrap.ts +6 -2
  128. package/src/components/checkbox-props.ts +12 -0
  129. package/src/components/flat-list/flat-list-template.ts +159 -0
  130. package/src/components/flat-list/index.ts +30 -307
  131. package/src/components/keyboard-avoiding-view/index.ts +4 -78
  132. package/src/components/modal/index.ts +7 -80
  133. package/src/components/section-list/index.ts +21 -172
  134. package/src/components/virtualized-list/cell-registry.ts +199 -0
  135. package/src/components/virtualized-list/index.ts +145 -1181
  136. package/src/components/virtualized-list/list-a11y-forward.ts +42 -0
  137. package/src/components/virtualized-list/list-bags.ts +142 -0
  138. package/src/components/virtualized-list/list-effects.ts +116 -0
  139. package/src/components/virtualized-list/list-events.ts +31 -0
  140. package/src/components/virtualized-list/list-handle.ts +92 -0
  141. package/src/components/virtualized-list/list-inputs.ts +149 -0
  142. package/src/components/virtualized-list/list-props.ts +81 -0
  143. package/src/components/virtualized-list/list-styles.ts +62 -0
  144. package/src/components/virtualized-list/list-template.ts +175 -0
  145. package/src/components/virtualized-section-list/index.ts +40 -351
  146. package/src/components/virtualized-section-list/section-list-template.ts +108 -0
  147. package/src/components.ts +1 -0
  148. package/src/descriptor-to-angular/descriptor-host.ts +27 -0
  149. package/src/descriptor-to-angular/index.ts +5 -0
  150. package/src/element-base.ts +272 -0
  151. package/src/elements-controls.ts +282 -0
  152. package/src/elements-layout.ts +141 -0
  153. package/src/elements-press.ts +145 -0
  154. package/src/elements.ts +73 -788
  155. package/src/finalization-registry.ts +18 -0
  156. package/src/host-instance/index.ts +4 -4
  157. package/src/index.ts +18 -2
  158. package/src/native-view-base.ts +86 -0
  159. package/src/render/index.ts +76 -77
  160. package/src/services/connect-watched-signal.ts +15 -0
  161. package/src/services/create-event-value-hook.ts +24 -0
  162. package/src/services/create-resource-hook.ts +32 -0
  163. package/src/services/index.ts +5 -0
  164. package/src/services/inject-event.ts +52 -0
  165. package/src/services/permissions-service-base.ts +46 -0
@@ -1,2 +1,7 @@
1
1
  export { ColorSchemeService } from './color-scheme.service';
2
2
  export { WindowDimensionsService } from './window-dimensions.service';
3
+ export { createResourceHook } from './create-resource-hook';
4
+ export { createEventValueHook } from './create-event-value-hook';
5
+ export { injectEvent, injectEventListener } from './inject-event';
6
+ export { connectWatchedSignal } from './connect-watched-signal';
7
+ export { PermissionsServiceBase } from './permissions-service-base';
@@ -1,3 +1,8 @@
1
1
  export { ColorSchemeService } from './color-scheme.service';
2
2
  export { WindowDimensionsService } from './window-dimensions.service';
3
+ export { createResourceHook } from './create-resource-hook';
4
+ export { createEventValueHook } from './create-event-value-hook';
5
+ export { injectEvent, injectEventListener } from './inject-event';
6
+ export { connectWatchedSignal } from './connect-watched-signal';
7
+ export { PermissionsServiceBase } from './permissions-service-base';
3
8
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/services/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AAC5D,OAAO,EAAE,uBAAuB,EAAE,MAAM,6BAA6B,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/services/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AAC5D,OAAO,EAAE,uBAAuB,EAAE,MAAM,6BAA6B,CAAC;AACtE,OAAO,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AAC5D,OAAO,EAAE,oBAAoB,EAAE,MAAM,2BAA2B,CAAC;AACjE,OAAO,EAAE,WAAW,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AAClE,OAAO,EAAE,oBAAoB,EAAE,MAAM,0BAA0B,CAAC;AAChE,OAAO,EAAE,sBAAsB,EAAE,MAAM,4BAA4B,CAAC"}
@@ -0,0 +1,6 @@
1
+ import type { Signal } from '@angular/core';
2
+ import type { IEventEmitterOf, IEventName, IEventPayload, IEventsMap } from '@symbiote-native/engine';
3
+ /** Calls the listener for each event, the latest one, and stops with the injection context */
4
+ export declare function injectEventListener<TEventsMap extends IEventsMap, TName extends IEventName<TEventsMap>>(emitter: () => IEventEmitterOf<TEventsMap>, eventName: () => TName, listener: () => TEventsMap[TName]): void;
5
+ /** The payload of the last event, `initialValue` (or `null`) until the first one */
6
+ export declare function injectEvent<TEventsMap extends IEventsMap, TName extends IEventName<TEventsMap>>(emitter: () => IEventEmitterOf<TEventsMap>, eventName: () => TName, initialValue?: IEventPayload<TEventsMap, TName> | null): Signal<IEventPayload<TEventsMap, TName> | null>;
@@ -0,0 +1,24 @@
1
+ // Angular twins of `useEvent` and `useEventListener` of the `expo` package, for any emitter
2
+ import { effect, signal, untracked } from '@angular/core';
3
+ import { bindEventListener } from '@symbiote-native/engine';
4
+ /** Calls the listener for each event, the latest one, and stops with the injection context */
5
+ export function injectEventListener(emitter, eventName, listener) {
6
+ effect(onCleanup => {
7
+ const source = emitter();
8
+ const name = eventName();
9
+ // The listener is read at each event, a new one is not a new subscription
10
+ onCleanup(bindEventListener(source, name, () => untracked(listener)));
11
+ });
12
+ }
13
+ /** The payload of the last event, `initialValue` (or `null`) until the first one */
14
+ export function injectEvent(emitter, eventName, initialValue = null) {
15
+ const event = signal(initialValue, /* @ts-ignore */
16
+ ...(ngDevMode ? [{ debugName: "event" }] : /* istanbul ignore next */ []));
17
+ effect(onCleanup => {
18
+ const source = emitter();
19
+ const name = eventName();
20
+ onCleanup(bindEventListener(source, name, () => (next) => event.set(next)));
21
+ });
22
+ return event.asReadonly();
23
+ }
24
+ //# sourceMappingURL=inject-event.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"inject-event.js","sourceRoot":"","sources":["../../../src/services/inject-event.ts"],"names":[],"mappings":"AAAA,4FAA4F;AAE5F,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAE1D,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAQ5D,8FAA8F;AAC9F,MAAM,UAAU,mBAAmB,CAIjC,OAA0C,EAC1C,SAAsB,EACtB,QAAiC;IAEjC,MAAM,CAAC,SAAS,CAAC,EAAE;QACjB,MAAM,MAAM,GAAG,OAAO,EAAE,CAAC;QACzB,MAAM,IAAI,GAAG,SAAS,EAAE,CAAC;QACzB,0EAA0E;QAC1E,SAAS,CAAC,iBAAiB,CAAC,MAAM,EAAE,IAAI,EAAE,GAAG,EAAE,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;IACxE,CAAC,CAAC,CAAC;AACL,CAAC;AAED,oFAAoF;AACpF,MAAM,UAAU,WAAW,CAIzB,OAA0C,EAC1C,SAAsB,EACtB,eAAwD,IAAI;IAE5D,MAAM,KAAK,GAAG,MAAM,CAA0C,YAAY;8EAAC,CAAC;IAC5E,MAAM,CAAC,SAAS,CAAC,EAAE;QACjB,MAAM,MAAM,GAAG,OAAO,EAAE,CAAC;QACzB,MAAM,IAAI,GAAG,SAAS,EAAE,CAAC;QACzB,SAAS,CACP,iBAAiB,CACf,MAAM,EACN,IAAI,EACJ,GAAG,EAAE,CAAC,CAAC,IAAsC,EAAE,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,CAClE,CACF,CAAC;IACJ,CAAC,CAAC,CAAC;IACH,OAAO,KAAK,CAAC,UAAU,EAAE,CAAC;AAC5B,CAAC"}
@@ -0,0 +1,14 @@
1
+ import { type Signal } from '@angular/core';
2
+ export declare abstract class PermissionsServiceBase<TPermission, TOptions = void> {
3
+ private readonly getMethod;
4
+ private readonly requestMethod;
5
+ private readonly status;
6
+ private readonly fetchError;
7
+ private isAutoFetchStarted;
8
+ readonly error: Signal<Error | null>;
9
+ protected constructor(getMethod: (options?: TOptions) => Promise<TPermission>, requestMethod: (options?: TOptions) => Promise<TPermission>);
10
+ connect(): Signal<TPermission | null>;
11
+ get(options?: TOptions): Promise<TPermission>;
12
+ request(options?: TOptions): Promise<TPermission>;
13
+ private store;
14
+ }
@@ -0,0 +1,38 @@
1
+ import { signal } from '@angular/core';
2
+ // Общая часть сервисов разрешений всех Expo-пакетов, наследник передаёт пару методов
3
+ // Сбой автозапроса попадает в `error`, а не в unhandled rejection: null-статус с непустым `error`
4
+ // значит "запрос упал", а не "ещё не было"
5
+ export class PermissionsServiceBase {
6
+ constructor(getMethod, requestMethod) {
7
+ this.getMethod = getMethod;
8
+ this.requestMethod = requestMethod;
9
+ this.status = signal(null, /* @ts-ignore */
10
+ ...(ngDevMode ? [{ debugName: "status" }] : /* istanbul ignore next */ []));
11
+ this.fetchError = signal(null, /* @ts-ignore */
12
+ ...(ngDevMode ? [{ debugName: "fetchError" }] : /* istanbul ignore next */ []));
13
+ this.isAutoFetchStarted = false;
14
+ this.error = this.fetchError.asReadonly();
15
+ }
16
+ // Защёлка, а не проверка `status() === null`: упавший запрос оставляет null навсегда
17
+ connect() {
18
+ if (!this.isAutoFetchStarted) {
19
+ this.isAutoFetchStarted = true;
20
+ this.get().catch((cause) => {
21
+ this.fetchError.set(cause instanceof Error ? cause : new Error(String(cause)));
22
+ });
23
+ }
24
+ return this.status.asReadonly();
25
+ }
26
+ async get(options) {
27
+ return this.store(await this.getMethod(options));
28
+ }
29
+ async request(options) {
30
+ return this.store(await this.requestMethod(options));
31
+ }
32
+ store(response) {
33
+ this.status.set(response);
34
+ this.fetchError.set(null);
35
+ return response;
36
+ }
37
+ }
38
+ //# sourceMappingURL=permissions-service-base.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"permissions-service-base.js","sourceRoot":"","sources":["../../../src/services/permissions-service-base.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAe,MAAM,eAAe,CAAC;AAEpD,qFAAqF;AACrF,kGAAkG;AAClG,2CAA2C;AAC3C,MAAM,OAAgB,sBAAsB;IAO1C,YACmB,SAAuD,EACvD,aAEQ;QAHR,cAAS,GAAT,SAAS,CAA8C;QACvD,kBAAa,GAAb,aAAa,CAEL;QAVV,WAAM,GAAG,MAAM,CAAqB,IAAI;mFAAC,CAAC;QAC1C,eAAU,GAAG,MAAM,CAAe,IAAI;uFAAC,CAAC;QACjD,uBAAkB,GAAG,KAAK,CAAC;QAE1B,UAAK,GAAyB,IAAI,CAAC,UAAU,CAAC,UAAU,EAAE,CAAC;IAOjE,CAAC;IAEJ,qFAAqF;IACrF,OAAO;QACL,IAAI,CAAC,IAAI,CAAC,kBAAkB,EAAE,CAAC;YAC7B,IAAI,CAAC,kBAAkB,GAAG,IAAI,CAAC;YAC/B,IAAI,CAAC,GAAG,EAAE,CAAC,KAAK,CAAC,CAAC,KAAc,EAAE,EAAE;gBAClC,IAAI,CAAC,UAAU,CAAC,GAAG,CACjB,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAC1D,CAAC;YACJ,CAAC,CAAC,CAAC;QACL,CAAC;QACD,OAAO,IAAI,CAAC,MAAM,CAAC,UAAU,EAAE,CAAC;IAClC,CAAC;IAED,KAAK,CAAC,GAAG,CAAC,OAAkB;QAC1B,OAAO,IAAI,CAAC,KAAK,CAAC,MAAM,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,CAAC;IACnD,CAAC;IAED,KAAK,CAAC,OAAO,CAAC,OAAkB;QAC9B,OAAO,IAAI,CAAC,KAAK,CAAC,MAAM,IAAI,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC,CAAC;IACvD,CAAC;IAEO,KAAK,CAAC,QAAqB;QACjC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;QAC1B,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QAC1B,OAAO,QAAQ,CAAC;IAClB,CAAC;CACF"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@symbiote-native/angular",
3
- "version": "3.1.3",
3
+ "version": "3.3.0",
4
4
  "description": "SymbioteNative's Angular adapter — a Renderer2/RendererFactory2 with DOM-less bootstrap driving real native iOS/Android views through the same engine as the other adapters.",
5
5
  "keywords": [
6
6
  "react-native",
@@ -66,14 +66,14 @@
66
66
  "dependencies": {
67
67
  "@angular/compiler-cli": "~22.0.8",
68
68
  "@react-native/typescript-config": "0.86.0",
69
- "@symbiote-native/components": "3.1.3",
70
- "@symbiote-native/css-parser": "0.5.2"
69
+ "@symbiote-native/components": "3.2.0",
70
+ "@symbiote-native/css-parser": "0.5.4"
71
71
  },
72
72
  "peerDependencies": {
73
73
  "@angular/core": ">=20",
74
74
  "@angular/forms": ">=20",
75
75
  "react-native": ">=0.86",
76
- "@symbiote-native/engine": "^1.4.0"
76
+ "@symbiote-native/engine": "^1.6.0"
77
77
  },
78
78
  "devDependencies": {
79
79
  "@angular/compiler": "~22.0.8",
@@ -83,8 +83,8 @@
83
83
  "@types/babel__core": "^7.20.5",
84
84
  "@types/node": "^26.0.0",
85
85
  "typescript": "~6.0.0",
86
- "@symbiote-native/engine": "1.4.0",
87
- "@symbiote-native/test-utils": "0.4.5"
86
+ "@symbiote-native/engine": "1.6.0",
87
+ "@symbiote-native/test-utils": "0.4.7"
88
88
  },
89
89
  "scripts": {
90
90
  "clean": "rm -rf build",
@@ -0,0 +1,13 @@
1
+ import { Directive, EventEmitter, Output } from '@angular/core';
2
+ import type { ISymbioteEvent } from '@symbiote-native/engine';
3
+ import { AccessibilityInputsBase } from './accessibility-inputs';
4
+
5
+ // The four accessibility callbacks as real Angular events, for components that expose them as
6
+ // outputs rather than inputs
7
+ @Directive()
8
+ export abstract class AccessibilityEventsBase extends AccessibilityInputsBase {
9
+ @Output() readonly accessibilityAction = new EventEmitter<ISymbioteEvent>();
10
+ @Output() readonly accessibilityTap = new EventEmitter<ISymbioteEvent>();
11
+ @Output() readonly magicTap = new EventEmitter<ISymbioteEvent>();
12
+ @Output() readonly accessibilityEscape = new EventEmitter<ISymbioteEvent>();
13
+ }
@@ -0,0 +1,89 @@
1
+ import { Directive, Input } from '@angular/core';
2
+ import type {
3
+ IAccessibilityProps,
4
+ IAccessibilityStateValue,
5
+ IAriaProps,
6
+ } from '@symbiote-native/components';
7
+
8
+ // Inputs are declared statically, so view-shaped components extend this instead of repeating them
9
+ // The `on*` accessibility callbacks stay per component: some take inputs, others outputs
10
+ @Directive()
11
+ export abstract class AccessibilityInputsBase {
12
+ @Input() accessible?: boolean;
13
+ @Input() accessibilityLabel?: string;
14
+ @Input() accessibilityHint?: string;
15
+ @Input() accessibilityRole?: IAccessibilityProps['accessibilityRole'];
16
+ @Input() accessibilityState?: IAccessibilityStateValue;
17
+ @Input() accessibilityValue?: IAccessibilityProps['accessibilityValue'];
18
+ @Input() accessibilityActions?: IAccessibilityProps['accessibilityActions'];
19
+ @Input() accessibilityLabelledBy?: string | string[];
20
+ @Input()
21
+ importantForAccessibility?: IAccessibilityProps['importantForAccessibility'];
22
+ @Input()
23
+ accessibilityLiveRegion?: IAccessibilityProps['accessibilityLiveRegion'];
24
+ @Input() screenReaderFocusable?: boolean;
25
+ @Input() accessibilityViewIsModal?: boolean;
26
+ @Input() accessibilityElementsHidden?: boolean;
27
+ @Input() accessibilityIgnoresInvertColors?: boolean;
28
+ @Input() accessibilityLanguage?: string;
29
+ @Input() accessibilityRespondsToUserInteraction?: boolean;
30
+ @Input() accessibilityShowsLargeContentViewer?: boolean;
31
+ @Input() accessibilityLargeContentTitle?: string;
32
+
33
+ @Input() role?: IAriaProps['role'];
34
+ @Input('aria-label') ariaLabel?: string;
35
+ @Input('aria-labelledby') ariaLabelledBy?: string;
36
+ @Input('aria-live') ariaLive?: IAriaProps['aria-live'];
37
+ @Input('aria-hidden') ariaHidden?: boolean;
38
+ @Input('aria-busy') ariaBusy?: boolean;
39
+ @Input('aria-checked') ariaChecked?: boolean | 'mixed';
40
+ @Input('aria-disabled') ariaDisabled?: boolean;
41
+ @Input('aria-expanded') ariaExpanded?: boolean;
42
+ @Input('aria-selected') ariaSelected?: boolean;
43
+ @Input('aria-modal') ariaModal?: boolean;
44
+ @Input('aria-valuemax') ariaValueMax?: number;
45
+ @Input('aria-valuemin') ariaValueMin?: number;
46
+ @Input('aria-valuenow') ariaValueNow?: number;
47
+ @Input('aria-valuetext') ariaValueText?: string;
48
+
49
+ // The bag the shared fold takes, the aria inputs under their web names
50
+ protected accessibilityInputProps(): IAccessibilityProps & IAriaProps {
51
+ return {
52
+ accessible: this.accessible,
53
+ accessibilityLabel: this.accessibilityLabel,
54
+ accessibilityHint: this.accessibilityHint,
55
+ accessibilityRole: this.accessibilityRole,
56
+ accessibilityState: this.accessibilityState,
57
+ accessibilityValue: this.accessibilityValue,
58
+ accessibilityActions: this.accessibilityActions,
59
+ accessibilityLabelledBy: this.accessibilityLabelledBy,
60
+ importantForAccessibility: this.importantForAccessibility,
61
+ accessibilityLiveRegion: this.accessibilityLiveRegion,
62
+ screenReaderFocusable: this.screenReaderFocusable,
63
+ accessibilityViewIsModal: this.accessibilityViewIsModal,
64
+ accessibilityElementsHidden: this.accessibilityElementsHidden,
65
+ accessibilityIgnoresInvertColors: this.accessibilityIgnoresInvertColors,
66
+ accessibilityLanguage: this.accessibilityLanguage,
67
+ accessibilityRespondsToUserInteraction:
68
+ this.accessibilityRespondsToUserInteraction,
69
+ accessibilityShowsLargeContentViewer:
70
+ this.accessibilityShowsLargeContentViewer,
71
+ accessibilityLargeContentTitle: this.accessibilityLargeContentTitle,
72
+ role: this.role,
73
+ 'aria-label': this.ariaLabel,
74
+ 'aria-labelledby': this.ariaLabelledBy,
75
+ 'aria-live': this.ariaLive,
76
+ 'aria-hidden': this.ariaHidden,
77
+ 'aria-busy': this.ariaBusy,
78
+ 'aria-checked': this.ariaChecked,
79
+ 'aria-disabled': this.ariaDisabled,
80
+ 'aria-expanded': this.ariaExpanded,
81
+ 'aria-selected': this.ariaSelected,
82
+ 'aria-modal': this.ariaModal,
83
+ 'aria-valuemax': this.ariaValueMax,
84
+ 'aria-valuemin': this.ariaValueMin,
85
+ 'aria-valuenow': this.ariaValueNow,
86
+ 'aria-valuetext': this.ariaValueText,
87
+ };
88
+ }
89
+ }
package/src/bootstrap.ts CHANGED
@@ -3,18 +3,21 @@
3
3
  // stay there. No @Component/@Directive decorators here, so unlike the package's main "." entry
4
4
  // this needs no ngc/AOT build step and can stay a plain source reference.
5
5
 
6
+ import './finalization-registry';
6
7
  import { AppRegistry as RNAppRegistry } from 'react-native';
7
- import type { Type } from '@angular/core';
8
+ import type { EnvironmentProviders, Provider, Type } from '@angular/core';
8
9
  import {
9
10
  bootstrapHost,
10
11
  type IBootstrapHostOptions,
11
12
  } from '@symbiote-native/components/bootstrap';
12
13
  import { AppRegistry, setHostRegistrar } from './modules/app-registry';
14
+ import { setRootProviders } from './render';
13
15
 
14
16
  export type { IBootstrapHostOptions } from '@symbiote-native/components/bootstrap';
15
17
 
16
18
  export type IBootstrapApplicationOptions = IBootstrapHostOptions & {
17
19
  appName: string;
20
+ providers?: (Provider | EnvironmentProviders)[];
18
21
  };
19
22
 
20
23
  // Mirrors real Angular's bootstrapApplication(RootComponent, config) idiom.
@@ -22,7 +25,8 @@ export function bootstrapApplication(
22
25
  AppComponent: Type<unknown>,
23
26
  options: IBootstrapApplicationOptions,
24
27
  ): void {
25
- const { appName, ...bootstrapOptions } = options;
28
+ const { appName, providers = [], ...bootstrapOptions } = options;
29
+ setRootProviders(providers);
26
30
  bootstrapHost(bootstrapOptions);
27
31
  setHostRegistrar(RNAppRegistry);
28
32
  AppRegistry.registerComponent(appName, () => AppComponent);
@@ -0,0 +1,12 @@
1
+ // Пропсы `<checkbox>` для Angular, компонента нет, тег матчит `CheckboxElement`
2
+ // Убраны a11y-колбэки (в Angular это outputs) и `onChange`, который upstream тоже никогда не зовёт
3
+ import type { ICheckboxProps as ICoreCheckboxProps } from '@symbiote-native/components';
4
+
5
+ export type ICheckboxProps = Omit<
6
+ ICoreCheckboxProps,
7
+ | 'onChange'
8
+ | 'onAccessibilityAction'
9
+ | 'onAccessibilityTap'
10
+ | 'onMagicTap'
11
+ | 'onAccessibilityEscape'
12
+ >;
@@ -0,0 +1,159 @@
1
+ // A content query does not resolve across a second `<ng-content>` hop, so both branches re-stamp
2
+ // the app's templates instead of projecting them (see `flat-list.test.ts`)
3
+
4
+ import { LIST_ACCESSIBILITY_FORWARD } from '../virtualized-list/list-a11y-forward';
5
+
6
+ export const FLAT_LIST_TEMPLATE = `
7
+ @if (isMultiColumn) {
8
+ <VirtualizedList
9
+ [data]="rows"
10
+ [getItem]="getRow"
11
+ [getItemCount]="getRowCount"
12
+ [keyExtractor]="rowKey"
13
+ [getItemLayout]="getItemLayout"
14
+ [horizontal]="horizontal"
15
+ [inverted]="inverted"
16
+ [extraData]="extraData"
17
+ (endReached)="endReached.emit($event)"
18
+ [onEndReachedThreshold]="onEndReachedThreshold"
19
+ (startReached)="startReached.emit($event)"
20
+ [onStartReachedThreshold]="onStartReachedThreshold"
21
+ (refresh)="refresh.emit()"
22
+ [refreshRequested]="refresh.observed"
23
+ [refreshing]="refreshing"
24
+ [progressViewOffset]="progressViewOffset"
25
+ (viewableItemsChanged)="rowViewableItemsChanged($event)"
26
+ [viewabilityConfig]="viewabilityConfig"
27
+ [viewabilityConfigCallbackPairs]="rowViewabilityPairs"
28
+ (scrollToIndexFailed)="scrollToIndexFailed.emit($event)"
29
+ [initialNumToRender]="initialNumToRender"
30
+ [initialScrollIndex]="initialScrollIndex"
31
+ [maxToRenderPerBatch]="maxToRenderPerBatch"
32
+ [updateCellsBatchingPeriod]="updateCellsBatchingPeriod"
33
+ [windowSize]="windowSize"
34
+ [stickyHeaderIndices]="stickyHeaderIndices"
35
+ [maintainVisibleContentPosition]="maintainVisibleContentPosition"
36
+ [onScroll]="onScroll"
37
+ [onScrollBeginDrag]="onScrollBeginDrag"
38
+ [onScrollEndDrag]="onScrollEndDrag"
39
+ [onMomentumScrollBegin]="onMomentumScrollBegin"
40
+ [onMomentumScrollEnd]="onMomentumScrollEnd"
41
+ [scrollEventThrottle]="scrollEventThrottle"
42
+ [keyboardShouldPersistTaps]="keyboardShouldPersistTaps"
43
+ [keyboardDismissMode]="keyboardDismissMode"
44
+ [removeClippedSubviews]="resolvedRemoveClippedSubviews"
45
+ [nestedScrollEnabled]="nestedScrollEnabled"
46
+ [testID]="testID"
47
+ [nativeID]="nativeID"
48
+ [style]="resolvedStyle"
49
+ [contentContainerStyle]="contentContainerStyle"
50
+ ${LIST_ACCESSIBILITY_FORWARD}
51
+ >
52
+ <ng-template vListItem let-row let-separators="separators">
53
+ <view [style]="rowStyle">
54
+ @for (cell of rowCells(row, separators); track cell.key) {
55
+ <view [style]="columnCellStyle">
56
+ <ng-container
57
+ [vListOutlet]="itemDir?.templateRef"
58
+ [vListOutletContext]="cell.context"
59
+ ></ng-container>
60
+ </view>
61
+ }
62
+ </view>
63
+ </ng-template>
64
+ @if (headerDir !== undefined) {
65
+ <ng-template vListHeader>
66
+ <ng-container [vListOutlet]="headerDir.templateRef"></ng-container>
67
+ </ng-template>
68
+ }
69
+ @if (footerDir !== undefined) {
70
+ <ng-template vListFooter>
71
+ <ng-container [vListOutlet]="footerDir.templateRef"></ng-container>
72
+ </ng-template>
73
+ }
74
+ @if (emptyDir !== undefined) {
75
+ <ng-template vListEmpty>
76
+ <ng-container [vListOutlet]="emptyDir.templateRef"></ng-container>
77
+ </ng-template>
78
+ }
79
+ @if (separatorDir !== undefined) {
80
+ <ng-template
81
+ vListSeparator
82
+ let-highlighted="highlighted"
83
+ let-leadingItem="leadingItem"
84
+ let-trailingItem="trailingItem"
85
+ >
86
+ <ng-container
87
+ [vListOutlet]="separatorDir.templateRef"
88
+ [vListOutletContext]="
89
+ rowSeparatorContext(highlighted, leadingItem, trailingItem)
90
+ "
91
+ ></ng-container>
92
+ </ng-template>
93
+ }
94
+ </VirtualizedList>
95
+ } @else {
96
+ <VirtualizedList
97
+ [data]="data"
98
+ [getItem]="getFlatItem"
99
+ [getItemCount]="getFlatCount"
100
+ [keyExtractor]="keyExtractor"
101
+ [getItemLayout]="getItemLayout"
102
+ [horizontal]="horizontal"
103
+ [inverted]="inverted"
104
+ [extraData]="extraData"
105
+ (endReached)="endReached.emit($event)"
106
+ [onEndReachedThreshold]="onEndReachedThreshold"
107
+ (startReached)="startReached.emit($event)"
108
+ [onStartReachedThreshold]="onStartReachedThreshold"
109
+ (refresh)="refresh.emit()"
110
+ [refreshRequested]="refresh.observed"
111
+ [refreshing]="refreshing"
112
+ [progressViewOffset]="progressViewOffset"
113
+ (viewableItemsChanged)="viewableItemsChanged.emit($event)"
114
+ [viewabilityConfig]="viewabilityConfig"
115
+ [viewabilityConfigCallbackPairs]="viewabilityConfigCallbackPairs"
116
+ (scrollToIndexFailed)="scrollToIndexFailed.emit($event)"
117
+ [initialNumToRender]="initialNumToRender"
118
+ [initialScrollIndex]="initialScrollIndex"
119
+ [maxToRenderPerBatch]="maxToRenderPerBatch"
120
+ [updateCellsBatchingPeriod]="updateCellsBatchingPeriod"
121
+ [windowSize]="windowSize"
122
+ [stickyHeaderIndices]="stickyHeaderIndices"
123
+ [maintainVisibleContentPosition]="maintainVisibleContentPosition"
124
+ [onScroll]="onScroll"
125
+ [onScrollBeginDrag]="onScrollBeginDrag"
126
+ [onScrollEndDrag]="onScrollEndDrag"
127
+ [onMomentumScrollBegin]="onMomentumScrollBegin"
128
+ [onMomentumScrollEnd]="onMomentumScrollEnd"
129
+ [scrollEventThrottle]="scrollEventThrottle"
130
+ [keyboardShouldPersistTaps]="keyboardShouldPersistTaps"
131
+ [keyboardDismissMode]="keyboardDismissMode"
132
+ [removeClippedSubviews]="resolvedRemoveClippedSubviews"
133
+ [nestedScrollEnabled]="nestedScrollEnabled"
134
+ [testID]="testID"
135
+ [nativeID]="nativeID"
136
+ [style]="resolvedStyle"
137
+ [contentContainerStyle]="contentContainerStyle"
138
+ [itemTemplate]="itemDir?.templateRef"
139
+ [itemSeparatorTemplate]="separatorDir?.templateRef"
140
+ ${LIST_ACCESSIBILITY_FORWARD}
141
+ >
142
+ @if (headerDir !== undefined) {
143
+ <ng-template vListHeader>
144
+ <ng-container [vListOutlet]="headerDir.templateRef"></ng-container>
145
+ </ng-template>
146
+ }
147
+ @if (footerDir !== undefined) {
148
+ <ng-template vListFooter>
149
+ <ng-container [vListOutlet]="footerDir.templateRef"></ng-container>
150
+ </ng-template>
151
+ }
152
+ @if (emptyDir !== undefined) {
153
+ <ng-template vListEmpty>
154
+ <ng-container [vListOutlet]="emptyDir.templateRef"></ng-container>
155
+ </ng-template>
156
+ }
157
+ </VirtualizedList>
158
+ }
159
+ `;