@ng-native/components 0.0.1 → 0.1.1

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 (144) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +78 -1
  3. package/dist/activity-indicator.d.ts +41 -0
  4. package/dist/activity-indicator.js +66 -0
  5. package/dist/activity-indicator.js.map +1 -0
  6. package/dist/animated-style.d.ts +31 -0
  7. package/dist/animated-style.js +102 -0
  8. package/dist/animated-style.js.map +1 -0
  9. package/dist/animated.d.ts +125 -0
  10. package/dist/animated.js +538 -0
  11. package/dist/animated.js.map +1 -0
  12. package/dist/animation.d.ts +40 -0
  13. package/dist/animation.js +20 -0
  14. package/dist/animation.js.map +1 -0
  15. package/dist/animations-web.d.ts +8 -0
  16. package/dist/animations-web.js +31 -0
  17. package/dist/animations-web.js.map +1 -0
  18. package/dist/animations.d.ts +7 -0
  19. package/dist/animations.js +58 -0
  20. package/dist/animations.js.map +1 -0
  21. package/dist/controlled-model.d.ts +33 -0
  22. package/dist/controlled-model.js +47 -0
  23. package/dist/controlled-model.js.map +1 -0
  24. package/dist/easing.d.ts +21 -0
  25. package/dist/easing.js +50 -0
  26. package/dist/easing.js.map +1 -0
  27. package/dist/events.d.ts +169 -0
  28. package/dist/events.js +2 -0
  29. package/dist/events.js.map +1 -0
  30. package/dist/gesture-backend.d.ts +26 -0
  31. package/dist/gesture-backend.js +14 -0
  32. package/dist/gesture-backend.js.map +1 -0
  33. package/dist/gesture-dispatch.d.ts +67 -0
  34. package/dist/gesture-dispatch.js +106 -0
  35. package/dist/gesture-dispatch.js.map +1 -0
  36. package/dist/gestures.d.ts +23 -0
  37. package/dist/gestures.js +164 -0
  38. package/dist/gestures.js.map +1 -0
  39. package/dist/height-index.d.ts +31 -0
  40. package/dist/height-index.js +80 -0
  41. package/dist/height-index.js.map +1 -0
  42. package/dist/image-background.d.ts +32 -0
  43. package/dist/image-background.js +80 -0
  44. package/dist/image-background.js.map +1 -0
  45. package/dist/image.d.ts +79 -0
  46. package/dist/image.js +155 -0
  47. package/dist/image.js.map +1 -0
  48. package/dist/index.d.ts +38 -0
  49. package/dist/index.js +39 -0
  50. package/dist/index.js.map +1 -0
  51. package/dist/input-accessory-view.d.ts +16 -0
  52. package/dist/input-accessory-view.js +29 -0
  53. package/dist/input-accessory-view.js.map +1 -0
  54. package/dist/keyboard-avoiding-view.d.ts +79 -0
  55. package/dist/keyboard-avoiding-view.js +172 -0
  56. package/dist/keyboard-avoiding-view.js.map +1 -0
  57. package/dist/keyboard-dock.d.ts +126 -0
  58. package/dist/keyboard-dock.js +327 -0
  59. package/dist/keyboard-dock.js.map +1 -0
  60. package/dist/keyboard-taps.d.ts +12 -0
  61. package/dist/keyboard-taps.js +51 -0
  62. package/dist/keyboard-taps.js.map +1 -0
  63. package/dist/modal.d.ts +56 -0
  64. package/dist/modal.js +102 -0
  65. package/dist/modal.js.map +1 -0
  66. package/dist/native-gesture.d.ts +21 -0
  67. package/dist/native-gesture.js +56 -0
  68. package/dist/native-gesture.js.map +1 -0
  69. package/dist/native-ref.d.ts +7 -0
  70. package/dist/native-ref.js +13 -0
  71. package/dist/native-ref.js.map +1 -0
  72. package/dist/pressable.d.ts +220 -0
  73. package/dist/pressable.js +484 -0
  74. package/dist/pressable.js.map +1 -0
  75. package/dist/reanimated.d.ts +19 -0
  76. package/dist/reanimated.js +111 -0
  77. package/dist/reanimated.js.map +1 -0
  78. package/dist/refresh-control.d.ts +50 -0
  79. package/dist/refresh-control.js +103 -0
  80. package/dist/refresh-control.js.map +1 -0
  81. package/dist/safe-area-provider.d.ts +11 -0
  82. package/dist/safe-area-provider.js +70 -0
  83. package/dist/safe-area-provider.js.map +1 -0
  84. package/dist/safe-area-view.d.ts +22 -0
  85. package/dist/safe-area-view.js +77 -0
  86. package/dist/safe-area-view.js.map +1 -0
  87. package/dist/safe-area.d.ts +12 -0
  88. package/dist/safe-area.js +27 -0
  89. package/dist/safe-area.js.map +1 -0
  90. package/dist/scroll-view-props.d.ts +89 -0
  91. package/dist/scroll-view-props.js +153 -0
  92. package/dist/scroll-view-props.js.map +1 -0
  93. package/dist/scroll-view.d.ts +95 -0
  94. package/dist/scroll-view.js +181 -0
  95. package/dist/scroll-view.js.map +1 -0
  96. package/dist/section-list.d.ts +146 -0
  97. package/dist/section-list.js +300 -0
  98. package/dist/section-list.js.map +1 -0
  99. package/dist/sticky-headers.d.ts +41 -0
  100. package/dist/sticky-headers.js +118 -0
  101. package/dist/sticky-headers.js.map +1 -0
  102. package/dist/swipe-refresh-layout.d.ts +51 -0
  103. package/dist/swipe-refresh-layout.js +162 -0
  104. package/dist/swipe-refresh-layout.js.map +1 -0
  105. package/dist/switch.d.ts +54 -0
  106. package/dist/switch.js +110 -0
  107. package/dist/switch.js.map +1 -0
  108. package/dist/template-slot.d.ts +18 -0
  109. package/dist/template-slot.js +30 -0
  110. package/dist/template-slot.js.map +1 -0
  111. package/dist/text-input.d.ts +168 -0
  112. package/dist/text-input.js +312 -0
  113. package/dist/text-input.js.map +1 -0
  114. package/dist/text.d.ts +70 -0
  115. package/dist/text.js +111 -0
  116. package/dist/text.js.map +1 -0
  117. package/dist/touchable-opacity.d.ts +36 -0
  118. package/dist/touchable-opacity.js +76 -0
  119. package/dist/touchable-opacity.js.map +1 -0
  120. package/dist/transforms.d.ts +2 -0
  121. package/dist/transforms.js +17 -0
  122. package/dist/transforms.js.map +1 -0
  123. package/dist/view-base.d.ts +332 -0
  124. package/dist/view-base.js +534 -0
  125. package/dist/view-base.js.map +1 -0
  126. package/dist/view.d.ts +12 -0
  127. package/dist/view.js +18 -0
  128. package/dist/view.js.map +1 -0
  129. package/dist/virtual-list.d.ts +530 -0
  130. package/dist/virtual-list.js +1150 -0
  131. package/dist/virtual-list.js.map +1 -0
  132. package/dist/worklet-scroll.d.ts +13 -0
  133. package/dist/worklet-scroll.js +49 -0
  134. package/dist/worklet-scroll.js.map +1 -0
  135. package/dist/worklet-style.d.ts +13 -0
  136. package/dist/worklet-style.js +47 -0
  137. package/dist/worklet-style.js.map +1 -0
  138. package/dist/worklets.d.ts +89 -0
  139. package/dist/worklets.js +42 -0
  140. package/dist/worklets.js.map +1 -0
  141. package/dist/written-props.d.ts +6 -0
  142. package/dist/written-props.js +180 -0
  143. package/dist/written-props.js.map +1 -0
  144. package/package.json +88 -3
@@ -0,0 +1,111 @@
1
+ /**
2
+ * Reanimated, without React: a style computed on the UI thread, bound to one of our nodes.
3
+ *
4
+ * ```ts
5
+ * import { WorkletStyle, sharedValue, workletStyle } from '@ng-native/components/reanimated';
6
+ *
7
+ * protected readonly offset = sharedValue(0);
8
+ * protected readonly slide = workletStyle([this.offset], (offset) => {
9
+ * 'worklet';
10
+ * return { transform: [{ translateX: offset.value }] };
11
+ * });
12
+ * ```
13
+ * ```html
14
+ * <view [workletStyle]="slide">
15
+ * ```
16
+ *
17
+ * Deliberately outside the barrel: everything here reaches React Native's
18
+ * Flow source, which Node cannot parse, and the rest of the package has to stay loadable in the
19
+ * test suite.
20
+ *
21
+ * What makes this work at all is that Reanimated addresses a view by its **shadow node**, not by a
22
+ * React instance. `getShadowNodeWrapperFromRef` digs one out of a fiber; our engine has held the
23
+ * same object since it created the node, so there is nothing to dig for. `startMapper` and
24
+ * `makeMutable` are public, and the whole React half of `useAnimatedStyle` - refs, effects, the
25
+ * animated component wrapper - is what an Angular directive replaces.
26
+ *
27
+ * An app installs `react-native-reanimated` and `react-native-worklets` itself, and gets the
28
+ * worklet Babel plugin from `babel-preset-expo`, which adds it as soon as the package is present.
29
+ * Everything else an animation needs - `withTiming`, `withSpring`, `interpolate`, `Easing` - is
30
+ * imported from `react-native-reanimated` directly: they are plain functions with no React in
31
+ * them, and re-exporting them here would only add a name to keep in step.
32
+ */
33
+ import { Directive } from '@angular/core';
34
+ import { makeMutable, startMapper, stopMapper, } from 'react-native-reanimated';
35
+ import { WorkletScrollBase } from "./worklet-scroll.js";
36
+ import { WorkletStyleBase } from "./worklet-style.js";
37
+ import { WORKLETS } from "./worklets.js";
38
+ import * as i0 from "@angular/core";
39
+ /**
40
+ * `updateProps` is what every animated style in Reanimated goes through, and there is no exported
41
+ * equivalent. It is a worklet, so it is called from ours rather than from here.
42
+ *
43
+ * Two things about the import. It goes through `src/` because that is where the package's own
44
+ * `react-native` field points and Metro prefers that field: the built `lib/` copy would be a
45
+ * second Reanimated in the bundle, with module state of its own. And it is a `require`, so that
46
+ * these sources stay out of our type-checking program, where they fail against settings they were
47
+ * never written for.
48
+ */
49
+ const { updateProps } = require('react-native-reanimated/src/updateProps/index.ts');
50
+ export { workletScroll, workletStyle, } from "./worklets.js";
51
+ /**
52
+ * A value both runtimes can see. Reanimated's own `useSharedValue` is this plus a React ref, and
53
+ * the ref is the half that does not apply here. Typed as Reanimated's own, so it goes to
54
+ * `cancelAnimation` and the rest of the library as one of theirs would.
55
+ */
56
+ export function sharedValue(initial) {
57
+ return makeMutable(initial);
58
+ }
59
+ const backend = {
60
+ bind: (target, style) => {
61
+ // The shape `updateProps` takes: a `{ value }` holder of descriptors, so that the set of
62
+ // views a style drives can change without the worklet being rebuilt. Ours never does - one
63
+ // directive drives one node - so a plain object is enough.
64
+ const descriptors = { value: [{ tag: target.tag, shadowNodeWrapper: target.shadowNode }] };
65
+ const { values, updater } = style;
66
+ const id = startMapper(() => {
67
+ 'worklet';
68
+ updateProps(descriptors, updater(...values));
69
+ }, values);
70
+ return () => stopMapper(id);
71
+ },
72
+ scroll: (target, spec) => {
73
+ const { values, handler } = spec;
74
+ // The same registration a gesture uses, on the name React Native's scroll views emit. The
75
+ // event still reaches our own listeners: Reanimated observes it rather than consuming it.
76
+ const id = registerEventHandler((event) => {
77
+ 'worklet';
78
+ handler(event, ...values);
79
+ }, 'onScroll', target.tag);
80
+ return () => unregisterEventHandler(id);
81
+ },
82
+ };
83
+ /**
84
+ * Not public, and the same call Reanimated's own `WorkletEventHandler` makes. Reached through
85
+ * `src/` for the reason `updateProps` is, and required rather than imported so that those sources
86
+ * stay out of our type-checking program.
87
+ */
88
+ const { registerEventHandler, unregisterEventHandler } = require('react-native-reanimated/src/core.ts');
89
+ export class WorkletStyle extends WorkletStyleBase {
90
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.2.0", ngImport: i0, type: WorkletStyle, deps: null, target: i0.ɵɵFactoryTarget.Directive });
91
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "22.2.0", type: WorkletStyle, isStandalone: true, selector: "[workletStyle]", providers: [{ provide: WORKLETS, useValue: backend }], usesInheritance: true, ngImport: i0 });
92
+ }
93
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.2.0", ngImport: i0, type: WorkletStyle, decorators: [{
94
+ type: Directive,
95
+ args: [{
96
+ selector: '[workletStyle]',
97
+ providers: [{ provide: WORKLETS, useValue: backend }],
98
+ }]
99
+ }] });
100
+ export class WorkletScroll extends WorkletScrollBase {
101
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.2.0", ngImport: i0, type: WorkletScroll, deps: null, target: i0.ɵɵFactoryTarget.Directive });
102
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "22.2.0", type: WorkletScroll, isStandalone: true, selector: "[workletScroll]", providers: [{ provide: WORKLETS, useValue: backend }], usesInheritance: true, ngImport: i0 });
103
+ }
104
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.2.0", ngImport: i0, type: WorkletScroll, decorators: [{
105
+ type: Directive,
106
+ args: [{
107
+ selector: '[workletScroll]',
108
+ providers: [{ provide: WORKLETS, useValue: backend }],
109
+ }]
110
+ }] });
111
+ //# sourceMappingURL=reanimated.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reanimated.js","sourceRoot":"","sources":["../src/reanimated.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,OAAO,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAC1C,OAAO,EACL,WAAW,EACX,WAAW,EACX,UAAU,GAEX,MAAM,yBAAyB,CAAC;AAcjC,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AACxD,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AACtD,OAAO,EAAE,QAAQ,EAAuB,MAAM,eAAe,CAAC;;AAf9D;;;;;;;;;GASG;AACH,MAAM,EAAE,WAAW,EAAE,GAAG,OAAO,CAAC,kDAAkD,CAEjF,CAAC;AAKF,OAAO,EACL,aAAa,EACb,YAAY,GAIb,MAAM,eAAe,CAAC;AAEvB;;;;GAIG;AACH,MAAM,UAAU,WAAW,CAAI,OAAU;IACvC,OAAO,WAAW,CAAC,OAAO,CAAC,CAAC;AAC9B,CAAC;AAED,MAAM,OAAO,GAAmB;IAC9B,IAAI,EAAE,CAAC,MAAM,EAAE,KAAK,EAAE,EAAE;QACtB,yFAAyF;QACzF,2FAA2F;QAC3F,2DAA2D;QAC3D,MAAM,WAAW,GAAG,EAAE,KAAK,EAAE,CAAC,EAAE,GAAG,EAAE,MAAM,CAAC,GAAG,EAAE,iBAAiB,EAAE,MAAM,CAAC,UAAU,EAAE,CAAC,EAAE,CAAC;QAC3F,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,GAAG,KAAK,CAAC;QAClC,MAAM,EAAE,GAAG,WAAW,CAAC,GAAG,EAAE;YAC1B,SAAS,CAAC;YACV,WAAW,CAAC,WAAW,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC;QAC/C,CAAC,EAAE,MAAmB,CAAC,CAAC;QACxB,OAAO,GAAG,EAAE,CAAC,UAAU,CAAC,EAAE,CAAC,CAAC;IAC9B,CAAC;IAED,MAAM,EAAE,CAAC,MAAM,EAAE,IAAI,EAAE,EAAE;QACvB,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,GAAG,IAAI,CAAC;QACjC,0FAA0F;QAC1F,0FAA0F;QAC1F,MAAM,EAAE,GAAG,oBAAoB,CAC7B,CAAC,KAAY,EAAE,EAAE;YACf,SAAS,CAAC;YACV,OAAO,CAAC,KAAK,EAAE,GAAG,MAAM,CAAC,CAAC;QAC5B,CAAC,EACD,UAAU,EACV,MAAM,CAAC,GAAG,CACX,CAAC;QACF,OAAO,GAAG,EAAE,CAAC,sBAAsB,CAAC,EAAE,CAAC,CAAC;IAC1C,CAAC;CACF,CAAC;AAEF;;;;GAIG;AACH,MAAM,EAAE,oBAAoB,EAAE,sBAAsB,EAAE,GACpD,OAAO,CAAC,qCAAqC,CAO5C,CAAC;AAMJ,MAAM,OAAO,YAAa,SAAQ,gBAAgB;uGAArC,YAAY;2FAAZ,YAAY,6DAFZ,CAAC,EAAE,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC;;2FAE1C,YAAY;kBAJxB,SAAS;mBAAC;oBACT,QAAQ,EAAE,gBAAgB;oBAC1B,SAAS,EAAE,CAAC,EAAE,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC;iBACtD;;AAOD,MAAM,OAAO,aAAc,SAAQ,iBAAiB;uGAAvC,aAAa;2FAAb,aAAa,8DAFb,CAAC,EAAE,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC;;2FAE1C,aAAa;kBAJzB,SAAS;mBAAC;oBACT,QAAQ,EAAE,iBAAiB;oBAC3B,SAAS,EAAE,CAAC,EAAE,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC;iBACtD","sourcesContent":["/**\n * Reanimated, without React: a style computed on the UI thread, bound to one of our nodes.\n *\n * ```ts\n * import { WorkletStyle, sharedValue, workletStyle } from '@ng-native/components/reanimated';\n *\n * protected readonly offset = sharedValue(0);\n * protected readonly slide = workletStyle([this.offset], (offset) => {\n * 'worklet';\n * return { transform: [{ translateX: offset.value }] };\n * });\n * ```\n * ```html\n * <view [workletStyle]=\"slide\">\n * ```\n *\n * Deliberately outside the barrel: everything here reaches React Native's\n * Flow source, which Node cannot parse, and the rest of the package has to stay loadable in the\n * test suite.\n *\n * What makes this work at all is that Reanimated addresses a view by its **shadow node**, not by a\n * React instance. `getShadowNodeWrapperFromRef` digs one out of a fiber; our engine has held the\n * same object since it created the node, so there is nothing to dig for. `startMapper` and\n * `makeMutable` are public, and the whole React half of `useAnimatedStyle` - refs, effects, the\n * animated component wrapper - is what an Angular directive replaces.\n *\n * An app installs `react-native-reanimated` and `react-native-worklets` itself, and gets the\n * worklet Babel plugin from `babel-preset-expo`, which adds it as soon as the package is present.\n * Everything else an animation needs - `withTiming`, `withSpring`, `interpolate`, `Easing` - is\n * imported from `react-native-reanimated` directly: they are plain functions with no React in\n * them, and re-exporting them here would only add a name to keep in step.\n */\nimport { Directive } from '@angular/core';\nimport {\n makeMutable,\n startMapper,\n stopMapper,\n type SharedValue as Mutable,\n} from 'react-native-reanimated';\n/**\n * `updateProps` is what every animated style in Reanimated goes through, and there is no exported\n * equivalent. It is a worklet, so it is called from ours rather than from here.\n *\n * Two things about the import. It goes through `src/` because that is where the package's own\n * `react-native` field points and Metro prefers that field: the built `lib/` copy would be a\n * second Reanimated in the bundle, with module state of its own. And it is a `require`, so that\n * these sources stay out of our type-checking program, where they fail against settings they were\n * never written for.\n */\nconst { updateProps } = require('react-native-reanimated/src/updateProps/index.ts') as {\n updateProps(descriptors: object, updates: Record<string, unknown>): void;\n};\nimport { WorkletScrollBase } from './worklet-scroll.ts';\nimport { WorkletStyleBase } from './worklet-style.ts';\nimport { WORKLETS, type WorkletBackend } from './worklets.ts';\n\nexport {\n workletScroll,\n workletStyle,\n type SharedValue,\n type WorkletScrollSpec,\n type WorkletStyleSpec,\n} from './worklets.ts';\n\n/**\n * A value both runtimes can see. Reanimated's own `useSharedValue` is this plus a React ref, and\n * the ref is the half that does not apply here. Typed as Reanimated's own, so it goes to\n * `cancelAnimation` and the rest of the library as one of theirs would.\n */\nexport function sharedValue<T>(initial: T): Mutable<T> {\n return makeMutable(initial);\n}\n\nconst backend: WorkletBackend = {\n bind: (target, style) => {\n // The shape `updateProps` takes: a `{ value }` holder of descriptors, so that the set of\n // views a style drives can change without the worklet being rebuilt. Ours never does - one\n // directive drives one node - so a plain object is enough.\n const descriptors = { value: [{ tag: target.tag, shadowNodeWrapper: target.shadowNode }] };\n const { values, updater } = style;\n const id = startMapper(() => {\n 'worklet';\n updateProps(descriptors, updater(...values));\n }, values as unknown[]);\n return () => stopMapper(id);\n },\n\n scroll: (target, spec) => {\n const { values, handler } = spec;\n // The same registration a gesture uses, on the name React Native's scroll views emit. The\n // event still reaches our own listeners: Reanimated observes it rather than consuming it.\n const id = registerEventHandler(\n (event: never) => {\n 'worklet';\n handler(event, ...values);\n },\n 'onScroll',\n target.tag,\n );\n return () => unregisterEventHandler(id);\n },\n};\n\n/**\n * Not public, and the same call Reanimated's own `WorkletEventHandler` makes. Reached through\n * `src/` for the reason `updateProps` is, and required rather than imported so that those sources\n * stay out of our type-checking program.\n */\nconst { registerEventHandler, unregisterEventHandler } =\n require('react-native-reanimated/src/core.ts') as {\n registerEventHandler(\n worklet: (event: never) => void,\n eventName: string,\n emitterReactTag: number,\n ): number;\n unregisterEventHandler(id: number): void;\n };\n\n@Directive({\n selector: '[workletStyle]',\n providers: [{ provide: WORKLETS, useValue: backend }],\n})\nexport class WorkletStyle extends WorkletStyleBase {}\n\n@Directive({\n selector: '[workletScroll]',\n providers: [{ provide: WORKLETS, useValue: backend }],\n})\nexport class WorkletScroll extends WorkletScrollBase {}\n"]}
@@ -0,0 +1,50 @@
1
+ import { type AfterViewChecked } from '@angular/core';
2
+ import { ViewBase } from './view-base.ts';
3
+ import * as i0 from "@angular/core";
4
+ /**
5
+ * Pull to refresh, as a child of a scroll view. Commits as `PullToRefreshView` on iOS and
6
+ * `AndroidSwipeRefreshLayout` on Android.
7
+ *
8
+ * `refreshing` is a model: the pull fires `(refresh)`, the app sets `refreshing` to true while
9
+ * it works and back to false when done. Native shows the spinner the instant the user pulls,
10
+ * before the app has said anything, so the two can disagree. RN's wrapper reconciles them with
11
+ * `setNativeRefreshing`; so does this. If the app never sets `refreshing` after a pull, the
12
+ * spinner is stopped again, which is what RN's documentation warns about.
13
+ *
14
+ * On Android the swipe layout has to be the scroll view's *parent*, as RN's `ScrollView.js` makes
15
+ * it, with the layout half of the scroll view's style moved onto it. It is written as a child all
16
+ * the same, like on iOS, and moved into place after each pass; see `SwipeRefreshLayout`.
17
+ */
18
+ export declare class RefreshControl extends ViewBase implements AfterViewChecked {
19
+ /** Whether the spinner shows. Two-way: `[(refreshing)]`. */
20
+ readonly refreshing: import("@angular/core").ModelSignal<boolean>;
21
+ /** How far from the top the spinner sits. */
22
+ readonly progressViewOffset: import("@angular/core").InputSignalWithTransform<number | undefined, unknown>;
23
+ /** iOS: the spinner's colour. */
24
+ readonly tintColor: import("@angular/core").InputSignal<string | undefined>;
25
+ /** iOS: a label under the spinner. */
26
+ readonly title: import("@angular/core").InputSignal<string | undefined>;
27
+ /** iOS: the label's colour. */
28
+ readonly titleColor: import("@angular/core").InputSignal<string | undefined>;
29
+ /** Android: the colours the spinner cycles through. */
30
+ readonly colors: import("@angular/core").InputSignal<readonly string[] | undefined>;
31
+ /** Android: whether pulling does anything. Defaults to true. */
32
+ readonly enabled: import("@angular/core").InputSignalWithTransform<boolean | undefined, unknown>;
33
+ /** Android: the spinner's background. */
34
+ readonly progressBackgroundColor: import("@angular/core").InputSignal<string | undefined>;
35
+ /** Android: the spinner's size. */
36
+ readonly size: import("@angular/core").InputSignal<"large" | "default" | undefined>;
37
+ private readonly nativeRefreshing;
38
+ /** Android only: what moves this control's node to wrap the scroll view. */
39
+ private readonly wrap;
40
+ constructor();
41
+ /**
42
+ * The scroll view's style is written in the pass that declared this control, so splitting it
43
+ * here reaches native in the same commit.
44
+ */
45
+ ngAfterViewChecked(): void;
46
+ /** Native has already started spinning; the app is told and expected to set `refreshing`. */
47
+ protected onNativeRefresh(): void;
48
+ static ɵfac: i0.ɵɵFactoryDeclaration<RefreshControl, never>;
49
+ static ɵdir: i0.ɵɵDirectiveDeclaration<RefreshControl, "refresh-control", never, { "refreshing": { "alias": "refreshing"; "required": false; "isSignal": true; }; "progressViewOffset": { "alias": "progressViewOffset"; "required": false; "isSignal": true; }; "tintColor": { "alias": "tintColor"; "required": false; "isSignal": true; }; "title": { "alias": "title"; "required": false; "isSignal": true; }; "titleColor": { "alias": "titleColor"; "required": false; "isSignal": true; }; "colors": { "alias": "colors"; "required": false; "isSignal": true; }; "enabled": { "alias": "enabled"; "required": false; "isSignal": true; }; "progressBackgroundColor": { "alias": "progressBackgroundColor"; "required": false; "isSignal": true; }; "size": { "alias": "size"; "required": false; "isSignal": true; }; }, { "refreshing": "refreshingChange"; }, never, never, true, never>;
50
+ }
@@ -0,0 +1,103 @@
1
+ import { Directive, DestroyRef, afterEveryRender, effect, inject, input, model, signal, } from '@angular/core';
2
+ import { Engine, nativePlatform } from '@ng-native/fabric';
3
+ import { SwipeRefreshLayout } from "./swipe-refresh-layout.js";
4
+ import { optionalBoolean, optionalNumber } from "./transforms.js";
5
+ import { ViewBase } from "./view-base.js";
6
+ import * as i0 from "@angular/core";
7
+ /**
8
+ * Pull to refresh, as a child of a scroll view. Commits as `PullToRefreshView` on iOS and
9
+ * `AndroidSwipeRefreshLayout` on Android.
10
+ *
11
+ * `refreshing` is a model: the pull fires `(refresh)`, the app sets `refreshing` to true while
12
+ * it works and back to false when done. Native shows the spinner the instant the user pulls,
13
+ * before the app has said anything, so the two can disagree. RN's wrapper reconciles them with
14
+ * `setNativeRefreshing`; so does this. If the app never sets `refreshing` after a pull, the
15
+ * spinner is stopped again, which is what RN's documentation warns about.
16
+ *
17
+ * On Android the swipe layout has to be the scroll view's *parent*, as RN's `ScrollView.js` makes
18
+ * it, with the layout half of the scroll view's style moved onto it. It is written as a child all
19
+ * the same, like on iOS, and moved into place after each pass; see `SwipeRefreshLayout`.
20
+ */
21
+ export class RefreshControl extends ViewBase {
22
+ /** Whether the spinner shows. Two-way: `[(refreshing)]`. */
23
+ refreshing = model(false, /* @ts-ignore */
24
+ ...(ngDevMode ? [{ debugName: "refreshing" }] : /* istanbul ignore next */ []));
25
+ /** How far from the top the spinner sits. */
26
+ progressViewOffset = input(undefined, { ...(ngDevMode ? { debugName: "progressViewOffset" } : /* istanbul ignore next */ {}), transform: optionalNumber });
27
+ /** iOS: the spinner's colour. */
28
+ tintColor = input(/* @ts-ignore */
29
+ ...(ngDevMode ? [undefined, { debugName: "tintColor" }] : /* istanbul ignore next */ []));
30
+ /** iOS: a label under the spinner. */
31
+ title = input(/* @ts-ignore */
32
+ ...(ngDevMode ? [undefined, { debugName: "title" }] : /* istanbul ignore next */ []));
33
+ /** iOS: the label's colour. */
34
+ titleColor = input(/* @ts-ignore */
35
+ ...(ngDevMode ? [undefined, { debugName: "titleColor" }] : /* istanbul ignore next */ []));
36
+ /** Android: the colours the spinner cycles through. */
37
+ colors = input(/* @ts-ignore */
38
+ ...(ngDevMode ? [undefined, { debugName: "colors" }] : /* istanbul ignore next */ []));
39
+ /** Android: whether pulling does anything. Defaults to true. */
40
+ enabled = input(undefined, { ...(ngDevMode ? { debugName: "enabled" } : /* istanbul ignore next */ {}), transform: optionalBoolean });
41
+ /** Android: the spinner's background. */
42
+ progressBackgroundColor = input(/* @ts-ignore */
43
+ ...(ngDevMode ? [undefined, { debugName: "progressBackgroundColor" }] : /* istanbul ignore next */ []));
44
+ /** Android: the spinner's size. */
45
+ size = input(/* @ts-ignore */
46
+ ...(ngDevMode ? [undefined, { debugName: "size" }] : /* istanbul ignore next */ []));
47
+ nativeRefreshing = signal(null, /* @ts-ignore */
48
+ ...(ngDevMode ? [{ debugName: "nativeRefreshing" }] : /* istanbul ignore next */ []));
49
+ /** Android only: what moves this control's node to wrap the scroll view. */
50
+ wrap = nativePlatform() === 'android'
51
+ ? new SwipeRefreshLayout(inject(Engine), this.node)
52
+ : null;
53
+ constructor() {
54
+ super();
55
+ const wrap = this.wrap;
56
+ if (wrap) {
57
+ // After every render as well as after this control's own pass: Angular moving the scroll
58
+ // view happens in some other component's pass, and this one's hooks would not see it.
59
+ afterEveryRender(() => wrap.sync());
60
+ inject(DestroyRef).onDestroy(() => wrap.unwrap());
61
+ }
62
+ effect(() => {
63
+ const desired = this.refreshing();
64
+ const native = this.nativeRefreshing();
65
+ if (native !== null && native !== desired) {
66
+ this.nativeRefreshing.set(desired);
67
+ this.engine.dispatchCommand(this.node, 'setNativeRefreshing', [desired]);
68
+ }
69
+ });
70
+ }
71
+ /**
72
+ * The scroll view's style is written in the pass that declared this control, so splitting it
73
+ * here reaches native in the same commit.
74
+ */
75
+ ngAfterViewChecked() {
76
+ this.wrap?.sync();
77
+ }
78
+ /** Native has already started spinning; the app is told and expected to set `refreshing`. */
79
+ onNativeRefresh() {
80
+ this.nativeRefreshing.set(true);
81
+ }
82
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.2.0", ngImport: i0, type: RefreshControl, deps: [], target: i0.ɵɵFactoryTarget.Directive });
83
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "22.2.0", type: RefreshControl, isStandalone: true, selector: "refresh-control", inputs: { refreshing: { classPropertyName: "refreshing", publicName: "refreshing", isSignal: true, isRequired: false, transformFunction: null }, progressViewOffset: { classPropertyName: "progressViewOffset", publicName: "progressViewOffset", isSignal: true, isRequired: false, transformFunction: null }, tintColor: { classPropertyName: "tintColor", publicName: "tintColor", isSignal: true, isRequired: false, transformFunction: null }, title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: false, transformFunction: null }, titleColor: { classPropertyName: "titleColor", publicName: "titleColor", isSignal: true, isRequired: false, transformFunction: null }, colors: { classPropertyName: "colors", publicName: "colors", isSignal: true, isRequired: false, transformFunction: null }, enabled: { classPropertyName: "enabled", publicName: "enabled", isSignal: true, isRequired: false, transformFunction: null }, progressBackgroundColor: { classPropertyName: "progressBackgroundColor", publicName: "progressBackgroundColor", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { refreshing: "refreshingChange" }, host: { listeners: { "refresh": "onNativeRefresh()" }, properties: { "refreshing": "refreshing()", "progressViewOffset": "progressViewOffset()", "tintColor": "tintColor()", "title": "title()", "titleColor": "titleColor()", "colors": "colors()", "enabled": "enabled()", "progressBackgroundColor": "progressBackgroundColor()", "size": "size()" } }, usesInheritance: true, ngImport: i0 });
84
+ }
85
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.2.0", ngImport: i0, type: RefreshControl, decorators: [{
86
+ type: Directive,
87
+ args: [{
88
+ selector: 'refresh-control',
89
+ host: {
90
+ '[refreshing]': 'refreshing()',
91
+ '[progressViewOffset]': 'progressViewOffset()',
92
+ '[tintColor]': 'tintColor()',
93
+ '[title]': 'title()',
94
+ '[titleColor]': 'titleColor()',
95
+ '[colors]': 'colors()',
96
+ '[enabled]': 'enabled()',
97
+ '[progressBackgroundColor]': 'progressBackgroundColor()',
98
+ '[size]': 'size()',
99
+ '(refresh)': 'onNativeRefresh()',
100
+ },
101
+ }]
102
+ }], ctorParameters: () => [], propDecorators: { refreshing: [{ type: i0.Input, args: [{ isSignal: true, alias: "refreshing", required: false }] }, { type: i0.Output, args: ["refreshingChange"] }], progressViewOffset: [{ type: i0.Input, args: [{ isSignal: true, alias: "progressViewOffset", required: false }] }], tintColor: [{ type: i0.Input, args: [{ isSignal: true, alias: "tintColor", required: false }] }], title: [{ type: i0.Input, args: [{ isSignal: true, alias: "title", required: false }] }], titleColor: [{ type: i0.Input, args: [{ isSignal: true, alias: "titleColor", required: false }] }], colors: [{ type: i0.Input, args: [{ isSignal: true, alias: "colors", required: false }] }], enabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "enabled", required: false }] }], progressBackgroundColor: [{ type: i0.Input, args: [{ isSignal: true, alias: "progressBackgroundColor", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }] } });
103
+ //# sourceMappingURL=refresh-control.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"refresh-control.js","sourceRoot":"","sources":["../src/refresh-control.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,SAAS,EACT,UAAU,EACV,gBAAgB,EAChB,MAAM,EACN,MAAM,EACN,KAAK,EACL,KAAK,EACL,MAAM,GACP,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,MAAM,EAAmB,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAC5E,OAAO,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAC/D,OAAO,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAClE,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;;AAE1C;;;;;;;;;;;;;GAaG;AAgBH,MAAM,OAAO,cAAe,SAAQ,QAAQ;IAC1C,4DAA4D;IACnD,UAAU,GAAG,KAAK,CAAC,KAAK;mFAAC,CAAC;IACnC,6CAA6C;IACpC,kBAAkB,GAAG,KAAK,CAAC,SAAS,0FAAI,SAAS,EAAE,cAAc,GAAG,CAAC;IAC9E,iCAAiC;IACxB,SAAS,GAAG,KAAK;6FAAU,CAAC;IACrC,sCAAsC;IAC7B,KAAK,GAAG,KAAK;yFAAU,CAAC;IACjC,+BAA+B;IACtB,UAAU,GAAG,KAAK;8FAAU,CAAC;IACtC,uDAAuD;IAC9C,MAAM,GAAG,KAAK;0FAAqB,CAAC;IAC7C,gEAAgE;IACvD,OAAO,GAAG,KAAK,CAAC,SAAS,+EAAI,SAAS,EAAE,eAAe,GAAG,CAAC;IACpE,yCAAyC;IAChC,uBAAuB,GAAG,KAAK;2GAAU,CAAC;IACnD,mCAAmC;IAC1B,IAAI,GAAG,KAAK;wFAAuB,CAAC;IAE5B,gBAAgB,GAAG,MAAM,CAAiB,IAAI;yFAAC,CAAC;IAEjE,4EAA4E;IAC3D,IAAI,GACnB,cAAc,EAAE,KAAK,SAAS;QAC5B,CAAC,CAAC,IAAI,kBAAkB,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,IAAI,CAAC,IAAkB,CAAC;QACjE,CAAC,CAAC,IAAI,CAAC;IAEX;QACE,KAAK,EAAE,CAAC;QACR,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC;QACvB,IAAI,IAAI,EAAE,CAAC;YACT,yFAAyF;YACzF,sFAAsF;YACtF,gBAAgB,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC;YACpC,MAAM,CAAC,UAAU,CAAC,CAAC,SAAS,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC;QACpD,CAAC;QACD,MAAM,CAAC,GAAG,EAAE;YACV,MAAM,OAAO,GAAG,IAAI,CAAC,UAAU,EAAE,CAAC;YAClC,MAAM,MAAM,GAAG,IAAI,CAAC,gBAAgB,EAAE,CAAC;YACvC,IAAI,MAAM,KAAK,IAAI,IAAI,MAAM,KAAK,OAAO,EAAE,CAAC;gBAC1C,IAAI,CAAC,gBAAgB,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;gBACnC,IAAI,CAAC,MAAM,CAAC,eAAe,CAAC,IAAI,CAAC,IAAI,EAAE,qBAAqB,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC;YAC3E,CAAC;QACH,CAAC,CAAC,CAAC;IACL,CAAC;IAED;;;OAGG;IACH,kBAAkB;QAChB,IAAI,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC;IACpB,CAAC;IAED,6FAA6F;IACnF,eAAe;QACvB,IAAI,CAAC,gBAAgB,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IAClC,CAAC;uGA1DU,cAAc;2FAAd,cAAc;;2FAAd,cAAc;kBAf1B,SAAS;mBAAC;oBACT,QAAQ,EAAE,iBAAiB;oBAC3B,IAAI,EAAE;wBACJ,cAAc,EAAE,cAAc;wBAC9B,sBAAsB,EAAE,sBAAsB;wBAC9C,aAAa,EAAE,aAAa;wBAC5B,SAAS,EAAE,SAAS;wBACpB,cAAc,EAAE,cAAc;wBAC9B,UAAU,EAAE,UAAU;wBACtB,WAAW,EAAE,WAAW;wBACxB,2BAA2B,EAAE,2BAA2B;wBACxD,QAAQ,EAAE,QAAQ;wBAClB,WAAW,EAAE,mBAAmB;qBACjC;iBACF","sourcesContent":["import {\n type AfterViewChecked,\n Directive,\n DestroyRef,\n afterEveryRender,\n effect,\n inject,\n input,\n model,\n signal,\n} from '@angular/core';\nimport { Engine, type EngineNode, nativePlatform } from '@ng-native/fabric';\nimport { SwipeRefreshLayout } from './swipe-refresh-layout.ts';\nimport { optionalBoolean, optionalNumber } from './transforms.ts';\nimport { ViewBase } from './view-base.ts';\n\n/**\n * Pull to refresh, as a child of a scroll view. Commits as `PullToRefreshView` on iOS and\n * `AndroidSwipeRefreshLayout` on Android.\n *\n * `refreshing` is a model: the pull fires `(refresh)`, the app sets `refreshing` to true while\n * it works and back to false when done. Native shows the spinner the instant the user pulls,\n * before the app has said anything, so the two can disagree. RN's wrapper reconciles them with\n * `setNativeRefreshing`; so does this. If the app never sets `refreshing` after a pull, the\n * spinner is stopped again, which is what RN's documentation warns about.\n *\n * On Android the swipe layout has to be the scroll view's *parent*, as RN's `ScrollView.js` makes\n * it, with the layout half of the scroll view's style moved onto it. It is written as a child all\n * the same, like on iOS, and moved into place after each pass; see `SwipeRefreshLayout`.\n */\n@Directive({\n selector: 'refresh-control',\n host: {\n '[refreshing]': 'refreshing()',\n '[progressViewOffset]': 'progressViewOffset()',\n '[tintColor]': 'tintColor()',\n '[title]': 'title()',\n '[titleColor]': 'titleColor()',\n '[colors]': 'colors()',\n '[enabled]': 'enabled()',\n '[progressBackgroundColor]': 'progressBackgroundColor()',\n '[size]': 'size()',\n '(refresh)': 'onNativeRefresh()',\n },\n})\nexport class RefreshControl extends ViewBase implements AfterViewChecked {\n /** Whether the spinner shows. Two-way: `[(refreshing)]`. */\n readonly refreshing = model(false);\n /** How far from the top the spinner sits. */\n readonly progressViewOffset = input(undefined, { transform: optionalNumber });\n /** iOS: the spinner's colour. */\n readonly tintColor = input<string>();\n /** iOS: a label under the spinner. */\n readonly title = input<string>();\n /** iOS: the label's colour. */\n readonly titleColor = input<string>();\n /** Android: the colours the spinner cycles through. */\n readonly colors = input<readonly string[]>();\n /** Android: whether pulling does anything. Defaults to true. */\n readonly enabled = input(undefined, { transform: optionalBoolean });\n /** Android: the spinner's background. */\n readonly progressBackgroundColor = input<string>();\n /** Android: the spinner's size. */\n readonly size = input<'default' | 'large'>();\n\n private readonly nativeRefreshing = signal<boolean | null>(null);\n\n /** Android only: what moves this control's node to wrap the scroll view. */\n private readonly wrap =\n nativePlatform() === 'android'\n ? new SwipeRefreshLayout(inject(Engine), this.node as EngineNode)\n : null;\n\n constructor() {\n super();\n const wrap = this.wrap;\n if (wrap) {\n // After every render as well as after this control's own pass: Angular moving the scroll\n // view happens in some other component's pass, and this one's hooks would not see it.\n afterEveryRender(() => wrap.sync());\n inject(DestroyRef).onDestroy(() => wrap.unwrap());\n }\n effect(() => {\n const desired = this.refreshing();\n const native = this.nativeRefreshing();\n if (native !== null && native !== desired) {\n this.nativeRefreshing.set(desired);\n this.engine.dispatchCommand(this.node, 'setNativeRefreshing', [desired]);\n }\n });\n }\n\n /**\n * The scroll view's style is written in the pass that declared this control, so splitting it\n * here reaches native in the same commit.\n */\n ngAfterViewChecked(): void {\n this.wrap?.sync();\n }\n\n /** Native has already started spinning; the app is told and expected to set `refreshing`. */\n protected onNativeRefresh(): void {\n this.nativeRefreshing.set(true);\n }\n}\n"]}
@@ -0,0 +1,11 @@
1
+ import * as i0 from "@angular/core";
2
+ export declare class SafeAreaProvider {
3
+ /**
4
+ * Whether what this measures becomes `SafeArea.insets`. The app has one safe area; a second
5
+ * provider inside a modal is there so native descendants can find one, not to redefine it.
6
+ */
7
+ readonly reportInsets: import("@angular/core").InputSignalWithTransform<boolean, unknown>;
8
+ constructor();
9
+ static ɵfac: i0.ɵɵFactoryDeclaration<SafeAreaProvider, never>;
10
+ static ɵcmp: i0.ɵɵComponentDeclaration<SafeAreaProvider, "safe-area-provider", never, { "reportInsets": { "alias": "reportInsets"; "required": false; "isSignal": true; }; }, {}, never, ["*"], true, never>;
11
+ }
@@ -0,0 +1,70 @@
1
+ /**
2
+ * The view that measures the safe area and reports it, for the layouts that need the numbers.
3
+ *
4
+ * ```html
5
+ * <safe-area-provider>
6
+ * <native-stack-outlet />
7
+ * </safe-area-provider>
8
+ * ```
9
+ *
10
+ * One, at the root, wrapping everything. What it measures is its own frame and the insets around
11
+ * it, which is why it has to be the thing filling the window rather than a view somewhere inside
12
+ * it. It fills by default and paints nothing.
13
+ *
14
+ * **A `<safe-area-view>` needs one above it**, which is less obvious than it sounds. The native
15
+ * view walks its superviews for a provider and falls back to reading its own insets - but only
16
+ * once, as it enters the window, before it has been laid out, and nothing tells it again. With no
17
+ * provider it therefore insets by zero and looks like it is working.
18
+ *
19
+ * That is also why a presented screen needs its own: it is outside the stack's view tree, which
20
+ * is the same reason it has no header. Give a modal a provider of its own with
21
+ * `[reportInsets]="false"`, so its geometry stays out of the app-wide `SafeArea` while it is up.
22
+ */
23
+ import { Component, DestroyRef, ElementRef, Renderer2, booleanAttribute, inject, input, } from '@angular/core';
24
+ import { SafeArea } from '@ng-native/device';
25
+ import { Engine, claimHost } from '@ng-native/fabric';
26
+ import { registerSafeAreaComponents } from "./safe-area.js";
27
+ import * as i0 from "@angular/core";
28
+ /** The insets, in the form the cascade carries: one custom property per edge, in points. */
29
+ function insetTokens(insets) {
30
+ return {
31
+ '--safe-area-inset-top': { length: insets.top },
32
+ '--safe-area-inset-right': { length: insets.right },
33
+ '--safe-area-inset-bottom': { length: insets.bottom },
34
+ '--safe-area-inset-left': { length: insets.left },
35
+ };
36
+ }
37
+ export class SafeAreaProvider {
38
+ /**
39
+ * Whether what this measures becomes `SafeArea.insets`. The app has one safe area; a second
40
+ * provider inside a modal is there so native descendants can find one, not to redefine it.
41
+ */
42
+ reportInsets = input(true, { ...(ngDevMode ? { debugName: "reportInsets" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
43
+ constructor() {
44
+ registerSafeAreaComponents();
45
+ const host = inject(ElementRef).nativeElement;
46
+ claimHost(host);
47
+ const area = inject(SafeArea);
48
+ const engine = inject(Engine, { optional: true });
49
+ const stop = inject(Renderer2).listen(host, 'insetsChange', (event) => {
50
+ const change = event?.nativeEvent;
51
+ if (!change || !this.reportInsets())
52
+ return;
53
+ area.report(change.insets, change.frame);
54
+ // Also published to the stylesheet, where a padding that clears the home indicator
55
+ // belongs. `env()` on the web; a seeded custom property here.
56
+ engine?.updateTokens(insetTokens(change.insets));
57
+ });
58
+ inject(DestroyRef).onDestroy(stop);
59
+ }
60
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.2.0", ngImport: i0, type: SafeAreaProvider, deps: [], target: i0.ɵɵFactoryTarget.Component });
61
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "22.2.0", type: SafeAreaProvider, isStandalone: true, selector: "safe-area-provider", inputs: { reportInsets: { classPropertyName: "reportInsets", publicName: "reportInsets", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: '<ng-content />', isInline: true });
62
+ }
63
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.2.0", ngImport: i0, type: SafeAreaProvider, decorators: [{
64
+ type: Component,
65
+ args: [{
66
+ selector: 'safe-area-provider',
67
+ template: '<ng-content />',
68
+ }]
69
+ }], ctorParameters: () => [], propDecorators: { reportInsets: [{ type: i0.Input, args: [{ isSignal: true, alias: "reportInsets", required: false }] }] } });
70
+ //# sourceMappingURL=safe-area-provider.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"safe-area-provider.js","sourceRoot":"","sources":["../src/safe-area-provider.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,OAAO,EACL,SAAS,EACT,UAAU,EACV,UAAU,EACV,SAAS,EACT,gBAAgB,EAChB,MAAM,EACN,KAAK,GACN,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,QAAQ,EAA2B,MAAM,mBAAmB,CAAC;AACtE,OAAO,EAAE,MAAM,EAAE,SAAS,EAAiB,MAAM,mBAAmB,CAAC;AACrE,OAAO,EAAE,0BAA0B,EAAE,MAAM,gBAAgB,CAAC;;AAE5D,4FAA4F;AAC5F,SAAS,WAAW,CAAC,MAAc;IACjC,OAAO;QACL,uBAAuB,EAAE,EAAE,MAAM,EAAE,MAAM,CAAC,GAAG,EAAE;QAC/C,yBAAyB,EAAE,EAAE,MAAM,EAAE,MAAM,CAAC,KAAK,EAAE;QACnD,0BAA0B,EAAE,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE;QACrD,wBAAwB,EAAE,EAAE,MAAM,EAAE,MAAM,CAAC,IAAI,EAAE;KAClD,CAAC;AACJ,CAAC;AAWD,MAAM,OAAO,gBAAgB;IAC3B;;;OAGG;IACM,YAAY,GAAG,KAAK,CAAC,IAAI,oFAAI,SAAS,EAAE,gBAAgB,GAAG,CAAC;IAErE;QACE,0BAA0B,EAAE,CAAC;QAC7B,MAAM,IAAI,GAAG,MAAM,CAAC,UAAU,CAAC,CAAC,aAAyB,CAAC;QAC1D,SAAS,CAAC,IAAI,CAAC,CAAC;QAEhB,MAAM,IAAI,GAAG,MAAM,CAAC,QAAQ,CAAC,CAAC;QAC9B,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC;QAClD,MAAM,IAAI,GAAG,MAAM,CAAC,SAAS,CAAC,CAAC,MAAM,CACnC,IAAI,EACJ,cAAc,EACd,CAAC,KAAqC,EAAE,EAAE;YACxC,MAAM,MAAM,GAAG,KAAK,EAAE,WAAW,CAAC;YAClC,IAAI,CAAC,MAAM,IAAI,CAAC,IAAI,CAAC,YAAY,EAAE;gBAAE,OAAO;YAC5C,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC;YACzC,mFAAmF;YACnF,8DAA8D;YAC9D,MAAM,EAAE,YAAY,CAAC,WAAW,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC;QACnD,CAAC,CACF,CAAC;QACF,MAAM,CAAC,UAAU,CAAC,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;IACrC,CAAC;uGA3BU,gBAAgB;2FAAhB,gBAAgB,uOAFjB,gBAAgB;;2FAEf,gBAAgB;kBAJ5B,SAAS;mBAAC;oBACT,QAAQ,EAAE,oBAAoB;oBAC9B,QAAQ,EAAE,gBAAgB;iBAC3B","sourcesContent":["/**\n * The view that measures the safe area and reports it, for the layouts that need the numbers.\n *\n * ```html\n * <safe-area-provider>\n * <native-stack-outlet />\n * </safe-area-provider>\n * ```\n *\n * One, at the root, wrapping everything. What it measures is its own frame and the insets around\n * it, which is why it has to be the thing filling the window rather than a view somewhere inside\n * it. It fills by default and paints nothing.\n *\n * **A `<safe-area-view>` needs one above it**, which is less obvious than it sounds. The native\n * view walks its superviews for a provider and falls back to reading its own insets - but only\n * once, as it enters the window, before it has been laid out, and nothing tells it again. With no\n * provider it therefore insets by zero and looks like it is working.\n *\n * That is also why a presented screen needs its own: it is outside the stack's view tree, which\n * is the same reason it has no header. Give a modal a provider of its own with\n * `[reportInsets]=\"false\"`, so its geometry stays out of the app-wide `SafeArea` while it is up.\n */\nimport {\n Component,\n DestroyRef,\n ElementRef,\n Renderer2,\n booleanAttribute,\n inject,\n input,\n} from '@angular/core';\nimport { SafeArea, type Frame, type Insets } from '@ng-native/device';\nimport { Engine, claimHost, type HostNode } from '@ng-native/fabric';\nimport { registerSafeAreaComponents } from './safe-area.ts';\n\n/** The insets, in the form the cascade carries: one custom property per edge, in points. */\nfunction insetTokens(insets: Insets): Record<string, { length: number }> {\n return {\n '--safe-area-inset-top': { length: insets.top },\n '--safe-area-inset-right': { length: insets.right },\n '--safe-area-inset-bottom': { length: insets.bottom },\n '--safe-area-inset-left': { length: insets.left },\n };\n}\n\ninterface InsetsChange {\n readonly insets: Insets;\n readonly frame: Frame;\n}\n\n@Component({\n selector: 'safe-area-provider',\n template: '<ng-content />',\n})\nexport class SafeAreaProvider {\n /**\n * Whether what this measures becomes `SafeArea.insets`. The app has one safe area; a second\n * provider inside a modal is there so native descendants can find one, not to redefine it.\n */\n readonly reportInsets = input(true, { transform: booleanAttribute });\n\n constructor() {\n registerSafeAreaComponents();\n const host = inject(ElementRef).nativeElement as HostNode;\n claimHost(host);\n\n const area = inject(SafeArea);\n const engine = inject(Engine, { optional: true });\n const stop = inject(Renderer2).listen(\n host,\n 'insetsChange',\n (event: { nativeEvent?: InsetsChange }) => {\n const change = event?.nativeEvent;\n if (!change || !this.reportInsets()) return;\n area.report(change.insets, change.frame);\n // Also published to the stylesheet, where a padding that clears the home indicator\n // belongs. `env()` on the web; a seeded custom property here.\n engine?.updateTokens(insetTokens(change.insets));\n },\n );\n inject(DestroyRef).onDestroy(stop);\n }\n}\n"]}
@@ -0,0 +1,22 @@
1
+ import { type SafeAreaEdge, type SafeAreaEdges } from './safe-area.ts';
2
+ import { ViewBase } from './view-base.ts';
3
+ import * as i0 from "@angular/core";
4
+ /** How an edge combines with the padding already there. */
5
+ export type SafeAreaEdgeMode = 'additive' | 'maximum' | 'off';
6
+ export declare class SafeAreaView extends ViewBase {
7
+ constructor();
8
+ /**
9
+ * Which edges to inset: `['top', 'bottom']`, or a record for per-edge modes. Absent insets all
10
+ * four.
11
+ */
12
+ readonly edges: import("@angular/core").InputSignal<SafeAreaEdges | undefined>;
13
+ /** Whether the insets become padding, which is the default, or margin. */
14
+ readonly mode: import("@angular/core").InputSignal<"padding" | "margin" | undefined>;
15
+ /**
16
+ * Native takes all four edges every time - a partial record leaves the missing ones at whatever
17
+ * they were, which reads as an inset that will not go away.
18
+ */
19
+ protected readonly resolvedEdges: import("@angular/core").Signal<Record<SafeAreaEdge, SafeAreaEdgeMode>>;
20
+ static ɵfac: i0.ɵɵFactoryDeclaration<SafeAreaView, never>;
21
+ static ɵdir: i0.ɵɵDirectiveDeclaration<SafeAreaView, "safe-area-view", never, { "edges": { "alias": "edges"; "required": false; "isSignal": true; }; "mode": { "alias": "mode"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
22
+ }
@@ -0,0 +1,77 @@
1
+ /**
2
+ * A view whose padding - or margin - keeps its content clear of the notch, the status bar, the
3
+ * home indicator, and on Android the display cutout and the navigation bar.
4
+ *
5
+ * The insets are applied natively, in the shadow node, so nothing crosses to JavaScript and there
6
+ * is no frame where the content sits under the system's furniture before moving out from under
7
+ * it. That is the reason to prefer this over reading `SafeArea.insets` and doing the arithmetic:
8
+ * the arithmetic is a frame late and re-runs on every rotation.
9
+ *
10
+ * ```html
11
+ * <safe-area-view [edges]="['top', 'bottom']" [style]="fill">…</safe-area-view>
12
+ * ```
13
+ *
14
+ * Which edges matter is usually a subset. A screen in a native stack already has its header
15
+ * covering the top, so it wants `bottom` alone; a presented sheet draws its own chrome and wants
16
+ * both. Passing nothing insets all four, which is what React Native's own deprecated
17
+ * `SafeAreaView` did.
18
+ *
19
+ * `maximum` is the third mode per edge and exists for a view that already has padding: `additive`
20
+ * adds the inset to it, `maximum` takes whichever is larger, and `off` ignores that edge.
21
+ *
22
+ * The insets come from the nearest `<safe-area-provider>` above it in the native view tree. A
23
+ * screen presented as a full-screen modal is not below the app's root provider - UIKit presents
24
+ * it from a view controller of its own - so there the view finds no insets and sits under the
25
+ * status bar. Such a screen wraps its content in a `<safe-area-provider>` of its own.
26
+ *
27
+ * The app must have `react-native-safe-area-context` installed, which is where the native
28
+ * component comes from; none of its JavaScript is imported. React Native's own `SafeAreaView` is
29
+ * deprecated in favour of it, is iOS-only, and offers no control over which edges apply.
30
+ */
31
+ import { Directive, computed, input } from '@angular/core';
32
+ import { registerSafeAreaComponents } from "./safe-area.js";
33
+ import { ViewBase } from "./view-base.js";
34
+ import * as i0 from "@angular/core";
35
+ const ALL = ['top', 'right', 'bottom', 'left'];
36
+ export class SafeAreaView extends ViewBase {
37
+ constructor() {
38
+ super();
39
+ // Before the first commit of this element, which is this component's own.
40
+ registerSafeAreaComponents();
41
+ }
42
+ /**
43
+ * Which edges to inset: `['top', 'bottom']`, or a record for per-edge modes. Absent insets all
44
+ * four.
45
+ */
46
+ edges = input(/* @ts-ignore */
47
+ ...(ngDevMode ? [undefined, { debugName: "edges" }] : /* istanbul ignore next */ []));
48
+ /** Whether the insets become padding, which is the default, or margin. */
49
+ mode = input(/* @ts-ignore */
50
+ ...(ngDevMode ? [undefined, { debugName: "mode" }] : /* istanbul ignore next */ []));
51
+ /**
52
+ * Native takes all four edges every time - a partial record leaves the missing ones at whatever
53
+ * they were, which reads as an inset that will not go away.
54
+ */
55
+ resolvedEdges = computed(() => {
56
+ const edges = this.edges();
57
+ const given = Array.isArray(edges)
58
+ ? Object.fromEntries(edges.map((edge) => [edge, 'additive']))
59
+ : (edges ?? {});
60
+ const all = edges === undefined;
61
+ return Object.fromEntries(ALL.map((edge) => [edge, all ? 'additive' : (given[edge] ?? 'off')]));
62
+ }, /* @ts-ignore */
63
+ ...(ngDevMode ? [{ debugName: "resolvedEdges" }] : /* istanbul ignore next */ []));
64
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.2.0", ngImport: i0, type: SafeAreaView, deps: [], target: i0.ɵɵFactoryTarget.Directive });
65
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "22.2.0", type: SafeAreaView, isStandalone: true, selector: "safe-area-view", inputs: { edges: { classPropertyName: "edges", publicName: "edges", isSignal: true, isRequired: false, transformFunction: null }, mode: { classPropertyName: "mode", publicName: "mode", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "edges": "resolvedEdges()", "mode": "mode()" } }, usesInheritance: true, ngImport: i0 });
66
+ }
67
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.2.0", ngImport: i0, type: SafeAreaView, decorators: [{
68
+ type: Directive,
69
+ args: [{
70
+ selector: 'safe-area-view',
71
+ host: {
72
+ '[edges]': 'resolvedEdges()',
73
+ '[mode]': 'mode()',
74
+ },
75
+ }]
76
+ }], ctorParameters: () => [], propDecorators: { edges: [{ type: i0.Input, args: [{ isSignal: true, alias: "edges", required: false }] }], mode: [{ type: i0.Input, args: [{ isSignal: true, alias: "mode", required: false }] }] } });
77
+ //# sourceMappingURL=safe-area-view.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"safe-area-view.js","sourceRoot":"","sources":["../src/safe-area-view.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,eAAe,CAAC;AAC3D,OAAO,EAAE,0BAA0B,EAAyC,MAAM,gBAAgB,CAAC;AACnG,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;;AAK1C,MAAM,GAAG,GAA4B,CAAC,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,CAAC,CAAC;AASxE,MAAM,OAAO,YAAa,SAAQ,QAAQ;IACxC;QACE,KAAK,EAAE,CAAC;QACR,0EAA0E;QAC1E,0BAA0B,EAAE,CAAC;IAC/B,CAAC;IAED;;;OAGG;IACM,KAAK,GAAG,KAAK;yFAAiB,CAAC;IAExC,0EAA0E;IACjE,IAAI,GAAG,KAAK;wFAAwB,CAAC;IAE9C;;;OAGG;IACgB,aAAa,GAAG,QAAQ,CAAC,GAAG,EAAE;QAC/C,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,EAAE,CAAC;QAC3B,MAAM,KAAK,GAAoD,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;YACjF,CAAC,CAAC,MAAM,CAAC,WAAW,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE,UAAU,CAAC,CAAC,CAAC;YAC7D,CAAC,CAAC,CAAE,KAA4D,IAAI,EAAE,CAAC,CAAC;QAE1E,MAAM,GAAG,GAAG,KAAK,KAAK,SAAS,CAAC;QAChC,OAAO,MAAM,CAAC,WAAW,CACvB,GAAG,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,KAAK,CAAC,CAAC,CAAC,CAC3B,CAAC;IAC9C,CAAC;sFAAC,CAAC;uGA9BQ,YAAY;2FAAZ,YAAY;;2FAAZ,YAAY;kBAPxB,SAAS;mBAAC;oBACT,QAAQ,EAAE,gBAAgB;oBAC1B,IAAI,EAAE;wBACJ,SAAS,EAAE,iBAAiB;wBAC5B,QAAQ,EAAE,QAAQ;qBACnB;iBACF","sourcesContent":["/**\n * A view whose padding - or margin - keeps its content clear of the notch, the status bar, the\n * home indicator, and on Android the display cutout and the navigation bar.\n *\n * The insets are applied natively, in the shadow node, so nothing crosses to JavaScript and there\n * is no frame where the content sits under the system's furniture before moving out from under\n * it. That is the reason to prefer this over reading `SafeArea.insets` and doing the arithmetic:\n * the arithmetic is a frame late and re-runs on every rotation.\n *\n * ```html\n * <safe-area-view [edges]=\"['top', 'bottom']\" [style]=\"fill\">…</safe-area-view>\n * ```\n *\n * Which edges matter is usually a subset. A screen in a native stack already has its header\n * covering the top, so it wants `bottom` alone; a presented sheet draws its own chrome and wants\n * both. Passing nothing insets all four, which is what React Native's own deprecated\n * `SafeAreaView` did.\n *\n * `maximum` is the third mode per edge and exists for a view that already has padding: `additive`\n * adds the inset to it, `maximum` takes whichever is larger, and `off` ignores that edge.\n *\n * The insets come from the nearest `<safe-area-provider>` above it in the native view tree. A\n * screen presented as a full-screen modal is not below the app's root provider - UIKit presents\n * it from a view controller of its own - so there the view finds no insets and sits under the\n * status bar. Such a screen wraps its content in a `<safe-area-provider>` of its own.\n *\n * The app must have `react-native-safe-area-context` installed, which is where the native\n * component comes from; none of its JavaScript is imported. React Native's own `SafeAreaView` is\n * deprecated in favour of it, is iOS-only, and offers no control over which edges apply.\n */\nimport { Directive, computed, input } from '@angular/core';\nimport { registerSafeAreaComponents, type SafeAreaEdge, type SafeAreaEdges } from './safe-area.ts';\nimport { ViewBase } from './view-base.ts';\n\n/** How an edge combines with the padding already there. */\nexport type SafeAreaEdgeMode = 'additive' | 'maximum' | 'off';\n\nconst ALL: readonly SafeAreaEdge[] = ['top', 'right', 'bottom', 'left'];\n\n@Directive({\n selector: 'safe-area-view',\n host: {\n '[edges]': 'resolvedEdges()',\n '[mode]': 'mode()',\n },\n})\nexport class SafeAreaView extends ViewBase {\n constructor() {\n super();\n // Before the first commit of this element, which is this component's own.\n registerSafeAreaComponents();\n }\n\n /**\n * Which edges to inset: `['top', 'bottom']`, or a record for per-edge modes. Absent insets all\n * four.\n */\n readonly edges = input<SafeAreaEdges>();\n\n /** Whether the insets become padding, which is the default, or margin. */\n readonly mode = input<'padding' | 'margin'>();\n\n /**\n * Native takes all four edges every time - a partial record leaves the missing ones at whatever\n * they were, which reads as an inset that will not go away.\n */\n protected readonly resolvedEdges = computed(() => {\n const edges = this.edges();\n const given: Partial<Record<SafeAreaEdge, SafeAreaEdgeMode>> = Array.isArray(edges)\n ? Object.fromEntries(edges.map((edge) => [edge, 'additive']))\n : ((edges as Record<SafeAreaEdge, SafeAreaEdgeMode> | undefined) ?? {});\n\n const all = edges === undefined;\n return Object.fromEntries(\n ALL.map((edge) => [edge, all ? 'additive' : (given[edge] ?? 'off')]),\n ) as Record<SafeAreaEdge, SafeAreaEdgeMode>;\n });\n}\n"]}
@@ -0,0 +1,12 @@
1
+ /** The edges of the screen, as both components name them. */
2
+ export type SafeAreaEdge = 'top' | 'right' | 'bottom' | 'left';
3
+ /** `['top', 'bottom']`, or `{ top: 'maximum', bottom: 'off' }` for per-edge control. */
4
+ export type SafeAreaEdges = readonly SafeAreaEdge[] | Readonly<Partial<Record<SafeAreaEdge, 'additive' | 'maximum' | 'off'>>>;
5
+ /**
6
+ * `safe-area-view` already had a mapping - React Native's own `SafeAreaView`, which is iOS-only,
7
+ * insets every edge and is deprecated upstream - so this replaces it. An app without
8
+ * `react-native-safe-area-context` installed therefore renders an unimplemented view rather than
9
+ * the old behaviour, which is the honest failure: the alternative is a view that silently insets
10
+ * nothing on half the platforms it runs on.
11
+ */
12
+ export declare function registerSafeAreaComponents(): void;
@@ -0,0 +1,27 @@
1
+ /**
2
+ * react-native-safe-area-context's two components, driven directly.
3
+ *
4
+ * The same arrangement as react-native-screens in the router: the native side is codegen'd Fabric
5
+ * components, their React wrappers are unreachable, and the engine is taught the element names.
6
+ * Registration happens when either component is first constructed, so importing one is the whole
7
+ * setup.
8
+ *
9
+ * No decorators here: tests import this at runtime.
10
+ */
11
+ import { registerViewName } from '@ng-native/fabric';
12
+ let registered = false;
13
+ /**
14
+ * `safe-area-view` already had a mapping - React Native's own `SafeAreaView`, which is iOS-only,
15
+ * insets every edge and is deprecated upstream - so this replaces it. An app without
16
+ * `react-native-safe-area-context` installed therefore renders an unimplemented view rather than
17
+ * the old behaviour, which is the honest failure: the alternative is a view that silently insets
18
+ * nothing on half the platforms it runs on.
19
+ */
20
+ export function registerSafeAreaComponents() {
21
+ if (registered)
22
+ return;
23
+ registered = true;
24
+ registerViewName('safe-area-view', 'RNCSafeAreaView');
25
+ registerViewName('safe-area-provider', 'RNCSafeAreaProvider', { flex: 1 });
26
+ }
27
+ //# sourceMappingURL=safe-area.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"safe-area.js","sourceRoot":"","sources":["../src/safe-area.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AASrD,IAAI,UAAU,GAAG,KAAK,CAAC;AAEvB;;;;;;GAMG;AACH,MAAM,UAAU,0BAA0B;IACxC,IAAI,UAAU;QAAE,OAAO;IACvB,UAAU,GAAG,IAAI,CAAC;IAClB,gBAAgB,CAAC,gBAAgB,EAAE,iBAAiB,CAAC,CAAC;IACtD,gBAAgB,CAAC,oBAAoB,EAAE,qBAAqB,EAAE,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC,CAAC;AAC7E,CAAC","sourcesContent":["/**\n * react-native-safe-area-context's two components, driven directly.\n *\n * The same arrangement as react-native-screens in the router: the native side is codegen'd Fabric\n * components, their React wrappers are unreachable, and the engine is taught the element names.\n * Registration happens when either component is first constructed, so importing one is the whole\n * setup.\n *\n * No decorators here: tests import this at runtime.\n */\nimport { registerViewName } from '@ng-native/fabric';\n\n/** The edges of the screen, as both components name them. */\nexport type SafeAreaEdge = 'top' | 'right' | 'bottom' | 'left';\n\n/** `['top', 'bottom']`, or `{ top: 'maximum', bottom: 'off' }` for per-edge control. */\nexport type SafeAreaEdges =\n readonly SafeAreaEdge[] | Readonly<Partial<Record<SafeAreaEdge, 'additive' | 'maximum' | 'off'>>>;\n\nlet registered = false;\n\n/**\n * `safe-area-view` already had a mapping - React Native's own `SafeAreaView`, which is iOS-only,\n * insets every edge and is deprecated upstream - so this replaces it. An app without\n * `react-native-safe-area-context` installed therefore renders an unimplemented view rather than\n * the old behaviour, which is the honest failure: the alternative is a view that silently insets\n * nothing on half the platforms it runs on.\n */\nexport function registerSafeAreaComponents(): void {\n if (registered) return;\n registered = true;\n registerViewName('safe-area-view', 'RNCSafeAreaView');\n registerViewName('safe-area-provider', 'RNCSafeAreaProvider', { flex: 1 });\n}\n"]}