@kanso-labs/react-native-kanso-ui 0.9.0 → 0.11.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 (217) hide show
  1. package/README.md +4 -3
  2. package/dist/autocomplete/index.js +15 -1
  3. package/dist/autocomplete/index.js.map +1 -1
  4. package/dist/button/group.d.ts +5 -0
  5. package/dist/button/group.js +115 -0
  6. package/dist/button/group.js.map +1 -0
  7. package/dist/button/index.d.ts +4 -1
  8. package/dist/button/index.js +44 -22
  9. package/dist/button/index.js.map +1 -1
  10. package/dist/button/slots.js +2 -1
  11. package/dist/button/slots.js.map +1 -1
  12. package/dist/calendar/index.js +351 -182
  13. package/dist/calendar/index.js.map +1 -1
  14. package/dist/calendar/styles.js +33 -2
  15. package/dist/calendar/styles.js.map +1 -1
  16. package/dist/carousel/arrangement.d.ts +5 -0
  17. package/dist/carousel/arrangement.js +123 -0
  18. package/dist/carousel/arrangement.js.map +1 -0
  19. package/dist/chequer/index.js +95 -0
  20. package/dist/chequer/index.js.map +1 -0
  21. package/dist/collection/index.d.ts +157 -0
  22. package/dist/collection/index.js +1358 -0
  23. package/dist/collection/index.js.map +1 -0
  24. package/dist/color-thumb/index.js +56 -0
  25. package/dist/color-thumb/index.js.map +1 -0
  26. package/dist/components/button/index.d.ts +4 -2
  27. package/dist/components/button/index.js +227 -188
  28. package/dist/components/button/index.js.map +1 -1
  29. package/dist/components/button-group/index.d.ts +87 -0
  30. package/dist/components/button-group/index.js +275 -0
  31. package/dist/components/button-group/index.js.map +1 -0
  32. package/dist/components/calendar/index.d.ts +11 -3
  33. package/dist/components/calendar/index.js +60 -45
  34. package/dist/components/calendar/index.js.map +1 -1
  35. package/dist/components/carousel/index.d.ts +72 -0
  36. package/dist/components/carousel/index.js +496 -0
  37. package/dist/components/carousel/index.js.map +1 -0
  38. package/dist/components/checkbox-group/index.d.ts +3 -4
  39. package/dist/components/checkbox-group/index.js +1 -1
  40. package/dist/components/checkbox-group/index.js.map +1 -1
  41. package/dist/components/chip/index.d.ts +4 -1
  42. package/dist/components/chip/index.js +229 -161
  43. package/dist/components/chip/index.js.map +1 -1
  44. package/dist/components/color-area/index.d.ts +85 -0
  45. package/dist/components/color-area/index.js +630 -0
  46. package/dist/components/color-area/index.js.map +1 -0
  47. package/dist/components/color-field/index.d.ts +144 -0
  48. package/dist/components/color-field/index.js +516 -0
  49. package/dist/components/color-field/index.js.map +1 -0
  50. package/dist/components/color-picker/index.d.ts +74 -0
  51. package/dist/components/color-picker/index.js +317 -0
  52. package/dist/components/color-picker/index.js.map +1 -0
  53. package/dist/components/color-slider/index.d.ts +82 -0
  54. package/dist/components/color-slider/index.js +456 -0
  55. package/dist/components/color-slider/index.js.map +1 -0
  56. package/dist/components/color-swatch/index.d.ts +46 -0
  57. package/dist/components/color-swatch/index.js +127 -0
  58. package/dist/components/color-swatch/index.js.map +1 -0
  59. package/dist/components/color-swatch-picker/index.d.ts +81 -0
  60. package/dist/components/color-swatch-picker/index.js +287 -0
  61. package/dist/components/color-swatch-picker/index.js.map +1 -0
  62. package/dist/components/color-wheel/index.d.ts +71 -0
  63. package/dist/components/color-wheel/index.js +407 -0
  64. package/dist/components/color-wheel/index.js.map +1 -0
  65. package/dist/components/combo-box/index.d.ts +193 -0
  66. package/dist/components/combo-box/index.js +616 -0
  67. package/dist/components/combo-box/index.js.map +1 -0
  68. package/dist/components/date-field/index.d.ts +120 -0
  69. package/dist/components/date-field/index.js +111 -0
  70. package/dist/components/date-field/index.js.map +1 -0
  71. package/dist/components/date-picker/index.d.ts +130 -0
  72. package/dist/components/date-picker/index.js +310 -0
  73. package/dist/components/date-picker/index.js.map +1 -0
  74. package/dist/components/date-range-picker/index.d.ts +139 -0
  75. package/dist/components/date-range-picker/index.js +421 -0
  76. package/dist/components/date-range-picker/index.js.map +1 -0
  77. package/dist/components/dialog/index.d.ts +5 -5
  78. package/dist/components/dialog/index.js +5 -5
  79. package/dist/components/dialog/index.js.map +1 -1
  80. package/dist/components/disclosure/index.d.ts +94 -0
  81. package/dist/components/disclosure/index.js +365 -0
  82. package/dist/components/disclosure/index.js.map +1 -0
  83. package/dist/components/disclosure-group/index.d.ts +61 -0
  84. package/dist/components/disclosure-group/index.js +100 -0
  85. package/dist/components/disclosure-group/index.js.map +1 -0
  86. package/dist/components/drop-zone/index.d.ts +113 -0
  87. package/dist/components/drop-zone/index.js +304 -0
  88. package/dist/components/drop-zone/index.js.map +1 -0
  89. package/dist/components/fab/index.d.ts +1 -1
  90. package/dist/components/fab/index.js +91 -76
  91. package/dist/components/fab/index.js.map +1 -1
  92. package/dist/components/form/index.d.ts +3 -2
  93. package/dist/components/form/index.js.map +1 -1
  94. package/dist/components/icon-button/index.d.ts +4 -2
  95. package/dist/components/icon-button/index.js +204 -171
  96. package/dist/components/icon-button/index.js.map +1 -1
  97. package/dist/components/list/index.d.ts +15 -158
  98. package/dist/components/list/index.js +21 -1047
  99. package/dist/components/list/index.js.map +1 -1
  100. package/dist/components/list-box/index.d.ts +73 -0
  101. package/dist/components/list-box/index.js +82 -0
  102. package/dist/components/list-box/index.js.map +1 -0
  103. package/dist/components/loading-indicator/index.d.ts +32 -0
  104. package/dist/components/loading-indicator/index.js +174 -0
  105. package/dist/components/loading-indicator/index.js.map +1 -0
  106. package/dist/components/menu/index.d.ts +3 -3
  107. package/dist/components/menu/index.js +3 -3
  108. package/dist/components/menu/index.js.map +1 -1
  109. package/dist/components/navigation-tree/index.d.ts +117 -0
  110. package/dist/components/navigation-tree/index.js +135 -0
  111. package/dist/components/navigation-tree/index.js.map +1 -0
  112. package/dist/components/number-field/index.js +132 -143
  113. package/dist/components/number-field/index.js.map +1 -1
  114. package/dist/components/popover/index.d.ts +2 -2
  115. package/dist/components/popover/index.js +2 -2
  116. package/dist/components/popover/index.js.map +1 -1
  117. package/dist/components/range-calendar/index.d.ts +69 -0
  118. package/dist/components/range-calendar/index.js +144 -0
  119. package/dist/components/range-calendar/index.js.map +1 -0
  120. package/dist/components/search-view/index.d.ts +79 -0
  121. package/dist/components/search-view/index.js +571 -0
  122. package/dist/components/search-view/index.js.map +1 -0
  123. package/dist/components/select/index.d.ts +152 -0
  124. package/dist/components/select/index.js +419 -0
  125. package/dist/components/select/index.js.map +1 -0
  126. package/dist/components/sheet/index.d.ts +16 -7
  127. package/dist/components/sheet/index.js +157 -152
  128. package/dist/components/sheet/index.js.map +1 -1
  129. package/dist/components/slider/index.d.ts +111 -0
  130. package/dist/components/slider/index.js +673 -0
  131. package/dist/components/slider/index.js.map +1 -0
  132. package/dist/components/split-button/index.d.ts +77 -0
  133. package/dist/components/split-button/index.js +354 -0
  134. package/dist/components/split-button/index.js.map +1 -0
  135. package/dist/components/table/index.d.ts +391 -0
  136. package/dist/components/table/index.js +1708 -0
  137. package/dist/components/table/index.js.map +1 -0
  138. package/dist/components/tabs/index.d.ts +196 -0
  139. package/dist/components/tabs/index.js +1137 -0
  140. package/dist/components/tabs/index.js.map +1 -0
  141. package/dist/components/time-field/index.d.ts +43 -0
  142. package/dist/components/time-field/index.js +107 -0
  143. package/dist/components/time-field/index.js.map +1 -0
  144. package/dist/components/time-picker/index.d.ts +65 -0
  145. package/dist/components/time-picker/index.js +1168 -0
  146. package/dist/components/time-picker/index.js.map +1 -0
  147. package/dist/components/token-field/index.d.ts +105 -0
  148. package/dist/components/token-field/index.js +574 -0
  149. package/dist/components/token-field/index.js.map +1 -0
  150. package/dist/components/tooltip/index.d.ts +102 -0
  151. package/dist/components/tooltip/index.js +223 -0
  152. package/dist/components/tooltip/index.js.map +1 -0
  153. package/dist/components/tree/index.d.ts +112 -0
  154. package/dist/components/tree/index.js +157 -0
  155. package/dist/components/tree/index.js.map +1 -0
  156. package/dist/disclosure/chevron.js +75 -0
  157. package/dist/disclosure/chevron.js.map +1 -0
  158. package/dist/disclosure/index.js +7 -0
  159. package/dist/disclosure/index.js.map +1 -0
  160. package/dist/drop/index.d.ts +54 -0
  161. package/dist/drop/index.js +161 -0
  162. package/dist/drop/index.js.map +1 -0
  163. package/dist/field/chevron.js +74 -0
  164. package/dist/field/chevron.js.map +1 -0
  165. package/dist/field/index.d.ts +2 -1
  166. package/dist/field/index.js +359 -154
  167. package/dist/field/index.js.map +1 -1
  168. package/dist/field/styles.js +18 -1
  169. package/dist/field/styles.js.map +1 -1
  170. package/dist/files/index.d.ts +18 -0
  171. package/dist/files/index.js +107 -0
  172. package/dist/files/index.js.map +1 -0
  173. package/dist/form/index.d.ts +5 -2
  174. package/dist/form/index.js +64 -85
  175. package/dist/form/index.js.map +1 -1
  176. package/dist/glyphs/index.js +128 -1
  177. package/dist/glyphs/index.js.map +1 -1
  178. package/dist/i18n/index.js +36 -1
  179. package/dist/i18n/index.js.map +1 -1
  180. package/dist/i18n/messages.js +1734 -34
  181. package/dist/i18n/messages.js.map +1 -1
  182. package/dist/index.d.ts +37 -3
  183. package/dist/index.js +36 -3
  184. package/dist/indicator/paths.js +23 -1
  185. package/dist/indicator/paths.js.map +1 -1
  186. package/dist/modal/index.js +92 -77
  187. package/dist/modal/index.js.map +1 -1
  188. package/dist/number/keyboard.js +16 -0
  189. package/dist/number/keyboard.js.map +1 -0
  190. package/dist/overlay/anchored.js +68 -38
  191. package/dist/overlay/anchored.js.map +1 -1
  192. package/dist/overlay/keyboard.js +57 -0
  193. package/dist/overlay/keyboard.js.map +1 -0
  194. package/dist/overlay/panel.js +173 -19
  195. package/dist/overlay/panel.js.map +1 -1
  196. package/dist/overlay/placement.js +13 -1
  197. package/dist/overlay/placement.js.map +1 -1
  198. package/dist/picker/index.js +322 -0
  199. package/dist/picker/index.js.map +1 -0
  200. package/dist/press/index.d.ts +2 -0
  201. package/dist/press/index.js +102 -100
  202. package/dist/press/index.js.map +1 -1
  203. package/dist/row/index.js +77 -69
  204. package/dist/row/index.js.map +1 -1
  205. package/dist/row/styles.js +13 -2
  206. package/dist/row/styles.js.map +1 -1
  207. package/dist/segments/field.js +277 -0
  208. package/dist/segments/field.js.map +1 -0
  209. package/dist/segments/index.js +574 -0
  210. package/dist/segments/index.js.map +1 -0
  211. package/dist/segments/styles.js +24 -0
  212. package/dist/segments/styles.js.map +1 -0
  213. package/dist/slider/index.js +145 -0
  214. package/dist/slider/index.js.map +1 -0
  215. package/dist/swatch/index.js +56 -0
  216. package/dist/swatch/index.js.map +1 -0
  217. package/package.json +11 -2
@@ -1,6 +1,7 @@
1
1
  import { useTheme } from "../theme/scope.js";
2
2
  import { OverlayHostContext } from "./host.js";
3
- import { boundsOf, place } from "./placement.js";
3
+ import { useKeyboardTop, watchKeyboard } from "./keyboard.js";
4
+ import { aboveKeyboard, boundsOf, place } from "./placement.js";
4
5
  import { c } from "react/compiler-runtime";
5
6
  import { Dimensions, I18nManager, useWindowDimensions } from "react-native";
6
7
  import { SafeAreaInsetsContext } from "react-native-safe-area-context";
@@ -24,14 +25,15 @@ const NO_INSETS = {
24
25
  * web's anchored overlays are placed: on `side`, lined up by `align`, flipped
25
26
  * to the opposite side at the edge of the window, and kept inside the safe
26
27
  * area's insets with `spacing.md` to spare, the padding React Aria keeps from
27
- * the edge of the viewport. On `top` and `bottom`, `start` and `end` follow
28
- * `I18nManager.isRTL`.
28
+ * the edge of the viewport. The software keyboard is an edge too while it is
29
+ * shown, so a list opened from a field being typed in stays above the keys.
30
+ * On `top` and `bottom`, `start` and `end` follow `I18nManager.isRTL`.
29
31
  *
30
32
  * The anchor is measured with `measureInWindow` whenever the surface reports
31
- * a new size or the window changes size.
33
+ * a new size, the window changes size or the keyboard moves.
32
34
  */
33
35
  function useAnchoredPlacement(t0) {
34
- const $ = c(31);
36
+ const $ = c(39);
35
37
  const { align: t1, alignOffset: t2, anchor, side: t3, sideOffset } = t0;
36
38
  const align = t1 === void 0 ? "center" : t1;
37
39
  const alignOffset = t2 === void 0 ? 0 : t2;
@@ -40,6 +42,7 @@ function useAnchoredPlacement(t0) {
40
42
  const { spacing } = useTheme();
41
43
  const window = useWindowDimensions();
42
44
  const insets = use(SafeAreaInsetsContext) ?? NO_INSETS;
45
+ const keyboardTop = useKeyboardTop();
43
46
  const [measured, setMeasured] = useState(null);
44
47
  const [surface, setSurface] = useState(null);
45
48
  let t4;
@@ -68,8 +71,12 @@ function useAnchoredPlacement(t0) {
68
71
  };
69
72
  measure();
70
73
  const subscription = Dimensions.addEventListener("change", measure);
74
+ const unwatch = watchKeyboard(() => {
75
+ measure();
76
+ });
71
77
  return () => {
72
78
  subscription.remove();
79
+ unwatch();
73
80
  };
74
81
  };
75
82
  $[0] = anchor.current;
@@ -106,6 +113,8 @@ function useAnchoredPlacement(t0) {
106
113
  let t7;
107
114
  if ($[9] !== side) {
108
115
  t7 = {
116
+ anchorFrame: void 0,
117
+ anchorWidth: void 0,
109
118
  onLayout,
110
119
  placed: false,
111
120
  side,
@@ -117,12 +126,12 @@ function useAnchoredPlacement(t0) {
117
126
  return t7;
118
127
  }
119
128
  let t7;
120
- if ($[11] !== align || $[12] !== alignOffset || $[13] !== insets || $[14] !== measured.anchor || $[15] !== side || $[16] !== sideOffset || $[17] !== spacing.md || $[18] !== spacing.sm || $[19] !== surface || $[20] !== window) {
129
+ if ($[11] !== align || $[12] !== alignOffset || $[13] !== insets || $[14] !== keyboardTop || $[15] !== measured.anchor || $[16] !== side || $[17] !== sideOffset || $[18] !== spacing.md || $[19] !== spacing.sm || $[20] !== surface || $[21] !== window) {
121
130
  t7 = place({
122
131
  align,
123
132
  alignOffset,
124
133
  anchor: measured.anchor,
125
- bounds: boundsOf(window, insets, spacing.md),
134
+ bounds: aboveKeyboard(boundsOf(window, insets, spacing.md), keyboardTop, spacing.md),
126
135
  rtl: I18nManager.isRTL,
127
136
  side,
128
137
  sideOffset: sideOffset ?? spacing.sm,
@@ -131,50 +140,71 @@ function useAnchoredPlacement(t0) {
131
140
  $[11] = align;
132
141
  $[12] = alignOffset;
133
142
  $[13] = insets;
134
- $[14] = measured.anchor;
135
- $[15] = side;
136
- $[16] = sideOffset;
137
- $[17] = spacing.md;
138
- $[18] = spacing.sm;
139
- $[19] = surface;
140
- $[20] = window;
141
- $[21] = t7;
142
- } else t7 = $[21];
143
+ $[14] = keyboardTop;
144
+ $[15] = measured.anchor;
145
+ $[16] = side;
146
+ $[17] = sideOffset;
147
+ $[18] = spacing.md;
148
+ $[19] = spacing.sm;
149
+ $[20] = surface;
150
+ $[21] = window;
151
+ $[22] = t7;
152
+ } else t7 = $[22];
143
153
  const placement = t7;
144
154
  const x_0 = placement.x - measured.origin.x;
145
- const t8 = placement.y - measured.origin.y;
146
- let t9;
147
- if ($[22] !== x_0) {
148
- t9 = I18nManager.isRTL && I18nManager.doLeftAndRightSwapInRTL ? { right: x_0 } : { left: x_0 };
149
- $[22] = x_0;
150
- $[23] = t9;
151
- } else t9 = $[23];
155
+ const t8 = measured.anchor.x - measured.origin.x;
156
+ const t9 = measured.anchor.y - measured.origin.y;
152
157
  let t10;
153
- if ($[24] !== placement.maxHeight || $[25] !== t8 || $[26] !== t9) {
158
+ if ($[23] !== measured.anchor.height || $[24] !== measured.anchor.width || $[25] !== t8 || $[26] !== t9) {
154
159
  t10 = {
155
- maxHeight: placement.maxHeight,
156
- position: "absolute",
157
- top: t8,
158
- ...t9
160
+ height: measured.anchor.height,
161
+ width: measured.anchor.width,
162
+ x: t8,
163
+ y: t9
159
164
  };
160
- $[24] = placement.maxHeight;
165
+ $[23] = measured.anchor.height;
166
+ $[24] = measured.anchor.width;
161
167
  $[25] = t8;
162
168
  $[26] = t9;
163
169
  $[27] = t10;
164
170
  } else t10 = $[27];
165
- let t11;
166
- if ($[28] !== placement.side || $[29] !== t10) {
167
- t11 = {
171
+ const t11 = placement.y - measured.origin.y;
172
+ let t12;
173
+ if ($[28] !== x_0) {
174
+ t12 = I18nManager.isRTL && I18nManager.doLeftAndRightSwapInRTL ? { right: x_0 } : { left: x_0 };
175
+ $[28] = x_0;
176
+ $[29] = t12;
177
+ } else t12 = $[29];
178
+ let t13;
179
+ if ($[30] !== placement.maxHeight || $[31] !== t11 || $[32] !== t12) {
180
+ t13 = {
181
+ maxHeight: placement.maxHeight,
182
+ position: "absolute",
183
+ top: t11,
184
+ ...t12
185
+ };
186
+ $[30] = placement.maxHeight;
187
+ $[31] = t11;
188
+ $[32] = t12;
189
+ $[33] = t13;
190
+ } else t13 = $[33];
191
+ let t14;
192
+ if ($[34] !== measured.anchor.width || $[35] !== placement.side || $[36] !== t10 || $[37] !== t13) {
193
+ t14 = {
194
+ anchorFrame: t10,
195
+ anchorWidth: measured.anchor.width,
168
196
  onLayout,
169
197
  placed: true,
170
198
  side: placement.side,
171
- style: t10
199
+ style: t13
172
200
  };
173
- $[28] = placement.side;
174
- $[29] = t10;
175
- $[30] = t11;
176
- } else t11 = $[30];
177
- return t11;
201
+ $[34] = measured.anchor.width;
202
+ $[35] = placement.side;
203
+ $[36] = t10;
204
+ $[37] = t13;
205
+ $[38] = t14;
206
+ } else t14 = $[38];
207
+ return t14;
178
208
  }
179
209
  //#endregion
180
210
  export { useAnchoredPlacement };
@@ -1 +1 @@
1
- {"version":3,"file":"anchored.js","names":["RefObject","HostInstance","LayoutChangeEvent","ViewStyle","use","useEffect","useState","Dimensions","I18nManager","useWindowDimensions","SafeAreaInsetsContext","OverlayAlign","OverlaySide","Rect","Size","useTheme","OverlayHostContext","boundsOf","place","AnchoredPlacement","onLayout","event","placed","side","style","AnchoredPlacementOptions","align","alignOffset","anchor","Pick","sideOffset","Measured","origin","x","y","HIDDEN","left","opacity","pointerEvents","position","top","NO_INSETS","bottom","right","useAnchoredPlacement","t0","$","_c","t1","t2","t3","undefined","store","spacing","window","insets","measured","setMeasured","surface","setSurface","t4","current","measure","layer","target","measureInWindow","originX","originY","width","height","subscription","addEventListener","remove","t5","t6","Symbol","for","height_0","width_0","nativeEvent","layout","known","t7","md","sm","bounds","rtl","isRTL","placement","x_0","t8","t9","doLeftAndRightSwapInRTL","t10","maxHeight","t11","_c"],"sources":["../../src/overlay/anchored.ts"],"sourcesContent":["import type { RefObject } from 'react'\nimport type { HostInstance, LayoutChangeEvent, ViewStyle } from 'react-native'\n\nimport { use, useEffect, useState } from 'react'\nimport { Dimensions, I18nManager, useWindowDimensions } from 'react-native'\nimport { SafeAreaInsetsContext } from 'react-native-safe-area-context'\n\nimport type { OverlayAlign, OverlaySide, Rect, Size } from './placement'\n\nimport { useTheme } from '../theme/scope'\nimport { OverlayHostContext } from './host'\nimport { boundsOf, place } from './placement'\n\ntype AnchoredPlacement = {\n /**\n * Hand to the surface's own `onLayout`. The surface is placed once it has\n * reported its size, and placed again whenever that size changes.\n */\n readonly onLayout: (event: LayoutChangeEvent) => void\n /**\n * Whether the surface has been placed. Until it has, it is laid out out of\n * sight, and a screen reader cannot be sent to it.\n */\n readonly placed: boolean\n /** The side the surface opened on, which is the opposite one after a flip. */\n readonly side: OverlaySide\n /**\n * The surface's position in the overlay layer, and the height it may take.\n * Until it has been placed it is laid out out of sight, to be measured.\n */\n readonly style: ViewStyle\n}\n\ntype AnchoredPlacementOptions = {\n /**\n * Where the surface sits along the side it opens on.\n * @default 'center'\n */\n readonly align?: OverlayAlign | undefined\n /** Moves the surface along that side, in dp: right or down when positive. */\n readonly alignOffset?: number | undefined\n /** The view the surface opens beside. */\n readonly anchor: RefObject<null | Pick<HostInstance, 'measureInWindow'>>\n /**\n * Which side of the anchor the surface opens on. It flips to the opposite\n * side when there is no room.\n * @default 'bottom'\n */\n readonly side?: OverlaySide | undefined\n /**\n * The gap between the anchor and the surface, in dp.\n * @default spacing.sm\n */\n readonly sideOffset?: number | undefined\n}\n\ntype Measured = {\n readonly anchor: Rect\n /** Where the overlay layer starts in the window. */\n readonly origin: { readonly x: number; readonly y: number }\n}\n\nconst HIDDEN: ViewStyle = {\n left: 0,\n opacity: 0,\n pointerEvents: 'none',\n position: 'absolute',\n top: 0,\n}\n\n// Outside a SafeAreaProvider the insets are unknown, and the window's own edge\n// is the best bound there is.\nconst NO_INSETS = { bottom: 0, left: 0, right: 0, top: 0 }\n\n/**\n * Places a surface drawn in an `Overlay` beside the view that opened it, as\n * web's anchored overlays are placed: on `side`, lined up by `align`, flipped\n * to the opposite side at the edge of the window, and kept inside the safe\n * area's insets with `spacing.md` to spare, the padding React Aria keeps from\n * the edge of the viewport. On `top` and `bottom`, `start` and `end` follow\n * `I18nManager.isRTL`.\n *\n * The anchor is measured with `measureInWindow` whenever the surface reports\n * a new size or the window changes size.\n */\nfunction useAnchoredPlacement({\n align = 'center',\n alignOffset = 0,\n anchor,\n side = 'bottom',\n sideOffset,\n}: AnchoredPlacementOptions): AnchoredPlacement {\n const store = use(OverlayHostContext)\n const { spacing } = useTheme()\n const window = useWindowDimensions()\n const insets = use(SafeAreaInsetsContext) ?? NO_INSETS\n const [measured, setMeasured] = useState<Measured | null>(null)\n const [surface, setSurface] = useState<null | Size>(null)\n\n useEffect(() => {\n // The layer is measured as well as the anchor, since the host need not\n // start at the window's corner: the surface is placed in the layer, and\n // the anchor is measured in the window.\n const measure = () => {\n const layer = store?.layer() ?? null\n const target = anchor.current\n\n if (surface === null || layer === null || target === null) {\n return\n }\n\n layer.measureInWindow((originX, originY) => {\n target.measureInWindow((x, y, width, height) => {\n setMeasured({\n anchor: { height, width, x, y },\n origin: { x: originX, y: originY },\n })\n })\n })\n }\n\n measure()\n\n // A rotation or a resized window can move the anchor without the\n // surface changing size.\n const subscription = Dimensions.addEventListener('change', measure)\n\n return () => {\n subscription.remove()\n }\n }, [anchor, store, surface])\n\n const onLayout = (event: LayoutChangeEvent) => {\n const { height, width } = event.nativeEvent.layout\n\n setSurface((known) =>\n known?.height === height && known.width === width\n ? known\n : { height, width },\n )\n }\n\n if (measured === null || surface === null) {\n return { onLayout, placed: false, side, style: HIDDEN }\n }\n\n const placement = place({\n align,\n alignOffset,\n anchor: measured.anchor,\n bounds: boundsOf(window, insets, spacing.md),\n rtl: I18nManager.isRTL,\n side,\n sideOffset: sideOffset ?? spacing.sm,\n surface,\n })\n const x = placement.x - measured.origin.x\n\n return {\n onLayout,\n placed: true,\n side: placement.side,\n style: {\n maxHeight: placement.maxHeight,\n position: 'absolute',\n top: placement.y - measured.origin.y,\n // The placement is in physical coordinates, as `measureInWindow`\n // reports them. React Native swaps `left` and `right` in a right-to-left\n // layout unless an app turns that off, so there `right` is what puts\n // the surface's left edge where the placement says.\n ...(I18nManager.isRTL && I18nManager.doLeftAndRightSwapInRTL\n ? { right: x }\n : { left: x }),\n },\n }\n}\n\nexport type { AnchoredPlacement, AnchoredPlacementOptions }\n\nexport { useAnchoredPlacement }\n"],"mappings":";;;;;;;;AA8DA,MAAMmC,SAAoB;CACxBC,MAAM;CACNC,SAAS;CACTC,eAAe;CACfC,UAAU;CACVC,KAAK;AACP;AAIA,MAAMC,YAAY;CAAEC,QAAQ;CAAGN,MAAM;CAAGO,OAAO;CAAGH,KAAK;AAAE;;;;;;;;;;;;AAazD,SAAAI,qBAAAC,IAAA;CAAA,MAAAC,IAAAC,EAAA,EAAA;CAA8B,MAAA,EAAArB,OAAAsB,IAAArB,aAAAsB,IAAArB,QAAAL,MAAA2B,IAAApB,eAAAe;CAC5B,MAAAnB,QAAAsB,OAAAG,KAAAA,IAAA,WAAAH;CACA,MAAArB,cAAAsB,OAAAE,KAAAA,IAAA,IAAAF;CAEA,MAAA1B,OAAA2B,OAAAC,KAAAA,IAAA,WAAAD;CAGA,MAAAE,QAAchD,IAAIY,kBAAkB;CACpC,MAAA,EAAAqC,YAAoBtC,SAAS;CAC7B,MAAAuC,SAAe7C,oBAAoB;CACnC,MAAA8C,SAAenD,IAAIM,qBAAkC,KAAtC+B;CACf,MAAA,CAAAe,UAAAC,eAAgCnD,SAA0B,IAAI;CAC9D,MAAA,CAAAoD,SAAAC,cAA8BrD,SAAsB,IAAI;CAAC,IAAAsD;CAAA,IAAAd,EAAA,OAAAlB,OAAAiC,WAAAf,EAAA,OAAAM,SAAAN,EAAA,OAAAY,SAAA;EAE/CE,WAAA;GAIR,MAAAE,gBAAgB;IACd,MAAAC,QAAcX,OAAKW,MAAgB,KAArB;IACd,MAAAC,SAAepC,OAAMiC;IAErB,IAAIH,YAAY,QAAQK,UAAU,QAAQC,WAAW,MAAI;IAIzDD,MAAKE,iBAAiBC,SAAAC,YAAA;KACpBH,OAAMC,iBAAiBhC,GAAAC,GAAAkC,OAAAC,WAAA;MACrBZ,YAAY;OAAA7B,QACF;QAAAyC;QAAAD;QAAAnC;QAAAC;OAAsB;OAACF,QACvB;QAAAC,GAAKiC;QAAOhC,GAAKiC;OAAQ;MACnC,CAAC;KAAC,CACH;IAAC,CACH;GAAC;GAGJL,QAAQ;GAIR,MAAAQ,eAAqB/D,WAAUgE,iBAAkB,UAAUT,OAAO;GAAC,aAE5D;IACLQ,aAAYE,OAAQ;GAAC;EACtB;EACF1B,EAAA,KAAAlB,OAAAiC;EAAAf,EAAA,KAAAM;EAAAN,EAAA,KAAAY;EAAAZ,EAAA,KAAAc;CAAA,OAAAA,KAAAd,EAAA;CAAA,IAAA2B;CAAA,IAAA3B,EAAA,OAAAlB,UAAAkB,EAAA,OAAAM,SAAAN,EAAA,OAAAY,SAAA;EAAEe,KAAA;GAAC7C;GAAQwB;GAAOM;EAAO;EAACZ,EAAA,KAAAlB;EAAAkB,EAAA,KAAAM;EAAAN,EAAA,KAAAY;EAAAZ,EAAA,KAAA2B;CAAA,OAAAA,KAAA3B,EAAA;CA/B3BzC,UAAUuD,IA+BPa,EAAwB;CAAC,IAAAC;CAAA,IAAA5B,EAAA,OAAA6B,OAAAC,IAAA,2BAAA,GAAA;EAEXF,MAAArD,UAAA;GACf,MAAA,EAAAgD,QAAAQ,UAAAT,OAAAU,YAA0BzD,MAAK0D,YAAYC;GAE3CrB,YAAWsB,UACTA,OAAKZ,WAAaA,YAAUY,MAAKb,UAAWA,UAA5Ca,QAAA;IAAAZ,QAEMA;IAAMD,OAAEA;GAAM,CACtB;EAAC;EACFtB,EAAA,KAAA4B;CAAA,OAAAA,KAAA5B,EAAA;CARD,MAAA1B,WAAiBsD;CAUjB,IAAIlB,aAAa,QAAQE,YAAY,MAAI;EAAA,IAAAwB;EAAA,IAAApC,EAAA,OAAAvB,MAAA;GAChC2D,KAAA;IAAA9D;IAAAE,QAAoB;IAAKC;IAAAC,OAAeW;GAAO;GAACW,EAAA,KAAAvB;GAAAuB,EAAA,MAAAoC;EAAA,OAAAA,KAAApC,EAAA;EAAA,OAAhDoC;CAAgD;CACxD,IAAAA;CAAA,IAAApC,EAAA,QAAApB,SAAAoB,EAAA,QAAAnB,eAAAmB,EAAA,QAAAS,UAAAT,EAAA,QAAAU,SAAA5B,UAAAkB,EAAA,QAAAvB,QAAAuB,EAAA,QAAAhB,cAAAgB,EAAA,QAAAO,QAAA8B,MAAArC,EAAA,QAAAO,QAAA+B,MAAAtC,EAAA,QAAAY,WAAAZ,EAAA,QAAAQ,QAAA;EAEiB4B,KAAAhE,MAAM;GAAAQ;GAAAC;GAAAC,QAGd4B,SAAQ5B;GAAOyD,QACfpE,SAASqC,QAAQC,QAAQF,QAAO8B,EAAG;GAACG,KACvC9E,YAAW+E;GAAMhE;GAAAO,YAEVA,cAAcuB,QAAO+B;GAAG1B;EAEtC,CAAC;EAACZ,EAAA,MAAApB;EAAAoB,EAAA,MAAAnB;EAAAmB,EAAA,MAAAS;EAAAT,EAAA,MAAAU,SAAA5B;EAAAkB,EAAA,MAAAvB;EAAAuB,EAAA,MAAAhB;EAAAgB,EAAA,MAAAO,QAAA8B;EAAArC,EAAA,MAAAO,QAAA+B;EAAAtC,EAAA,MAAAY;EAAAZ,EAAA,MAAAQ;EAAAR,EAAA,MAAAoC;CAAA,OAAAA,KAAApC,EAAA;CATF,MAAA0C,YAAkBN;CAUlB,MAAAO,MAAUD,UAASvD,IAAKuB,SAAQxB,OAAOC;CAS9B,MAAAyD,KAAAF,UAAStD,IAAKsB,SAAQxB,OAAOE;CAAE,IAAAyD;CAAA,IAAA7C,EAAA,QAAA2C,KAAA;EAKhCE,KAAAnF,YAAW+E,SAAU/E,YAAWoF,0BAAhC,EAAAjD,OACSV,IACC,IAFV,EAAAG,MAEQH,IAAE;EAACa,EAAA,MAAA2C;EAAA3C,EAAA,MAAA6C;CAAA,OAAAA,KAAA7C,EAAA;CAAA,IAAA+C;CAAA,IAAA/C,EAAA,QAAA0C,UAAAM,aAAAhD,EAAA,QAAA4C,MAAA5C,EAAA,QAAA6C,IAAA;EAVVE,MAAA;GAAAC,WACMN,UAASM;GAAUvD,UACpB;GAAUC,KACfkD;GAA+B,GAKhCC;EAGN;EAAC7C,EAAA,MAAA0C,UAAAM;EAAAhD,EAAA,MAAA4C;EAAA5C,EAAA,MAAA6C;EAAA7C,EAAA,MAAA+C;CAAA,OAAAA,MAAA/C,EAAA;CAAA,IAAAiD;CAAA,IAAAjD,EAAA,QAAA0C,UAAAjE,QAAAuB,EAAA,QAAA+C,KAAA;EAfIE,MAAA;GAAA3E;GAAAE,QAEG;GAAIC,MACNiE,UAASjE;GAAKC,OACbqE;EAYT;EAAC/C,EAAA,MAAA0C,UAAAjE;EAAAuB,EAAA,MAAA+C;EAAA/C,EAAA,MAAAiD;CAAA,OAAAA,MAAAjD,EAAA;CAAA,OAhBMiD;AAgBN"}
1
+ {"version":3,"file":"anchored.js","names":["RefObject","HostInstance","LayoutChangeEvent","ViewStyle","use","useEffect","useState","Dimensions","I18nManager","useWindowDimensions","SafeAreaInsetsContext","OverlayAlign","OverlaySide","Rect","Size","useTheme","OverlayHostContext","useKeyboardTop","watchKeyboard","aboveKeyboard","boundsOf","place","AnchoredPlacement","anchorFrame","anchorWidth","onLayout","event","placed","side","style","AnchoredPlacementOptions","align","alignOffset","anchor","Pick","sideOffset","Measured","origin","x","y","HIDDEN","left","opacity","pointerEvents","position","top","NO_INSETS","bottom","right","useAnchoredPlacement","t0","$","_c","t1","t2","t3","undefined","store","spacing","window","insets","keyboardTop","measured","setMeasured","surface","setSurface","t4","current","measure","layer","target","measureInWindow","originX","originY","width","height","subscription","addEventListener","unwatch","remove","t5","t6","Symbol","for","height_0","width_0","nativeEvent","layout","known","t7","md","sm","bounds","rtl","isRTL","placement","x_0","t8","t9","t10","t11","t12","doLeftAndRightSwapInRTL","t13","maxHeight","t14","_c"],"sources":["../../src/overlay/anchored.ts"],"sourcesContent":["import type { RefObject } from 'react'\nimport type { HostInstance, LayoutChangeEvent, ViewStyle } from 'react-native'\n\nimport { use, useEffect, useState } from 'react'\nimport { Dimensions, I18nManager, useWindowDimensions } from 'react-native'\nimport { SafeAreaInsetsContext } from 'react-native-safe-area-context'\n\nimport type { OverlayAlign, OverlaySide, Rect, Size } from './placement'\n\nimport { useTheme } from '../theme/scope'\nimport { OverlayHostContext } from './host'\nimport { useKeyboardTop, watchKeyboard } from './keyboard'\nimport { aboveKeyboard, boundsOf, place } from './placement'\n\ntype AnchoredPlacement = {\n /**\n * Where the anchor sits in the overlay layer, in physical coordinates, for\n * a layer drawn around it, and undefined until the surface has been\n * placed.\n */\n readonly anchorFrame: Rect | undefined\n /**\n * The anchor's width as it was measured, for a surface as wide as what\n * opened it, and undefined until the surface has been placed.\n */\n readonly anchorWidth: number | undefined\n /**\n * Hand to the surface's own `onLayout`. The surface is placed once it has\n * reported its size, and placed again whenever that size changes.\n */\n readonly onLayout: (event: LayoutChangeEvent) => void\n /**\n * Whether the surface has been placed. Until it has, it is laid out out of\n * sight, and a screen reader cannot be sent to it.\n */\n readonly placed: boolean\n /** The side the surface opened on, which is the opposite one after a flip. */\n readonly side: OverlaySide\n /**\n * The surface's position in the overlay layer, and the height it may take.\n * Until it has been placed it is laid out out of sight, to be measured.\n */\n readonly style: ViewStyle\n}\n\ntype AnchoredPlacementOptions = {\n /**\n * Where the surface sits along the side it opens on.\n * @default 'center'\n */\n readonly align?: OverlayAlign | undefined\n /** Moves the surface along that side, in dp: right or down when positive. */\n readonly alignOffset?: number | undefined\n /** The view the surface opens beside. */\n readonly anchor: RefObject<null | Pick<HostInstance, 'measureInWindow'>>\n /**\n * Which side of the anchor the surface opens on. It flips to the opposite\n * side when there is no room.\n * @default 'bottom'\n */\n readonly side?: OverlaySide | undefined\n /**\n * The gap between the anchor and the surface, in dp.\n * @default spacing.sm\n */\n readonly sideOffset?: number | undefined\n}\n\ntype Measured = {\n readonly anchor: Rect\n /** Where the overlay layer starts in the window. */\n readonly origin: { readonly x: number; readonly y: number }\n}\n\nconst HIDDEN: ViewStyle = {\n left: 0,\n opacity: 0,\n pointerEvents: 'none',\n position: 'absolute',\n top: 0,\n}\n\n// Outside a SafeAreaProvider the insets are unknown, and the window's own edge\n// is the best bound there is.\nconst NO_INSETS = { bottom: 0, left: 0, right: 0, top: 0 }\n\n/**\n * Places a surface drawn in an `Overlay` beside the view that opened it, as\n * web's anchored overlays are placed: on `side`, lined up by `align`, flipped\n * to the opposite side at the edge of the window, and kept inside the safe\n * area's insets with `spacing.md` to spare, the padding React Aria keeps from\n * the edge of the viewport. The software keyboard is an edge too while it is\n * shown, so a list opened from a field being typed in stays above the keys.\n * On `top` and `bottom`, `start` and `end` follow `I18nManager.isRTL`.\n *\n * The anchor is measured with `measureInWindow` whenever the surface reports\n * a new size, the window changes size or the keyboard moves.\n */\nfunction useAnchoredPlacement({\n align = 'center',\n alignOffset = 0,\n anchor,\n side = 'bottom',\n sideOffset,\n}: AnchoredPlacementOptions): AnchoredPlacement {\n const store = use(OverlayHostContext)\n const { spacing } = useTheme()\n const window = useWindowDimensions()\n const insets = use(SafeAreaInsetsContext) ?? NO_INSETS\n const keyboardTop = useKeyboardTop()\n const [measured, setMeasured] = useState<Measured | null>(null)\n const [surface, setSurface] = useState<null | Size>(null)\n\n useEffect(() => {\n // The layer is measured as well as the anchor, since the host need not\n // start at the window's corner: the surface is placed in the layer, and\n // the anchor is measured in the window.\n const measure = () => {\n const layer = store?.layer() ?? null\n const target = anchor.current\n\n if (surface === null || layer === null || target === null) {\n return\n }\n\n layer.measureInWindow((originX, originY) => {\n target.measureInWindow((x, y, width, height) => {\n setMeasured({\n anchor: { height, width, x, y },\n origin: { x: originX, y: originY },\n })\n })\n })\n }\n\n measure()\n\n // A rotation or a resized window can move the anchor without the\n // surface changing size, and so can a keyboard arriving, as a screen\n // makes room for the field being typed in.\n const subscription = Dimensions.addEventListener('change', measure)\n const unwatch = watchKeyboard(() => {\n measure()\n })\n\n return () => {\n subscription.remove()\n unwatch()\n }\n }, [anchor, store, surface])\n\n const onLayout = (event: LayoutChangeEvent) => {\n const { height, width } = event.nativeEvent.layout\n\n setSurface((known) =>\n known?.height === height && known.width === width\n ? known\n : { height, width },\n )\n }\n\n if (measured === null || surface === null) {\n return {\n anchorFrame: undefined,\n anchorWidth: undefined,\n onLayout,\n placed: false,\n side,\n style: HIDDEN,\n }\n }\n\n const placement = place({\n align,\n alignOffset,\n anchor: measured.anchor,\n bounds: aboveKeyboard(\n boundsOf(window, insets, spacing.md),\n keyboardTop,\n spacing.md,\n ),\n rtl: I18nManager.isRTL,\n side,\n sideOffset: sideOffset ?? spacing.sm,\n surface,\n })\n const x = placement.x - measured.origin.x\n\n return {\n anchorFrame: {\n height: measured.anchor.height,\n width: measured.anchor.width,\n x: measured.anchor.x - measured.origin.x,\n y: measured.anchor.y - measured.origin.y,\n },\n anchorWidth: measured.anchor.width,\n onLayout,\n placed: true,\n side: placement.side,\n style: {\n maxHeight: placement.maxHeight,\n position: 'absolute',\n top: placement.y - measured.origin.y,\n // The placement is in physical coordinates, as `measureInWindow`\n // reports them. React Native swaps `left` and `right` in a right-to-left\n // layout unless an app turns that off, so there `right` is what puts\n // the surface's left edge where the placement says.\n ...(I18nManager.isRTL && I18nManager.doLeftAndRightSwapInRTL\n ? { right: x }\n : { left: x }),\n },\n }\n}\n\nexport type { AnchoredPlacement, AnchoredPlacementOptions }\n\nexport { useAnchoredPlacement }\n"],"mappings":"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"}
@@ -0,0 +1,57 @@
1
+ import { c } from "react/compiler-runtime";
2
+ import { Keyboard, Platform } from "react-native";
3
+ import { useEffect, useState } from "react";
4
+ //#region src/overlay/keyboard.ts
5
+ function topOf(metrics) {
6
+ return metrics === void 0 || metrics === null || metrics.height === 0 ? null : metrics.screenY;
7
+ }
8
+ /**
9
+ * Where the software keyboard's top edge is in the window, in dp, or null
10
+ * while no keyboard is shown, for a surface that has to stay above it. A
11
+ * field's list opens while its keyboard is up, and the keyboard is drawn
12
+ * over the window rather than shrinking it, so the window's own edge would
13
+ * put the bottom of the list under the keys.
14
+ */
15
+ function useKeyboardTop() {
16
+ const $ = c(2);
17
+ const [top, setTop] = useState(_temp);
18
+ let t0;
19
+ let t1;
20
+ if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
21
+ t0 = () => watchKeyboard(setTop);
22
+ t1 = [];
23
+ $[0] = t0;
24
+ $[1] = t1;
25
+ } else {
26
+ t0 = $[0];
27
+ t1 = $[1];
28
+ }
29
+ useEffect(t0, t1);
30
+ return top;
31
+ }
32
+ /**
33
+ * Hands `listener` where the software keyboard's top edge is, or null, each
34
+ * time the keyboard moves, and returns what stops it. iOS reports a frame as
35
+ * the keyboard starts to move, and Android once it has arrived or gone,
36
+ * which is all either reports. React Native Web has no keyboard to report,
37
+ * and reports nothing.
38
+ */
39
+ function _temp() {
40
+ return Platform.OS === "web" ? null : topOf(Keyboard.metrics());
41
+ }
42
+ function watchKeyboard(listener) {
43
+ const moved = (event) => {
44
+ listener(topOf(event.endCoordinates));
45
+ };
46
+ const hidden = () => {
47
+ listener(null);
48
+ };
49
+ const subscriptions = Platform.OS === "ios" ? [Keyboard.addListener("keyboardWillChangeFrame", moved), Keyboard.addListener("keyboardWillHide", hidden)] : [Keyboard.addListener("keyboardDidShow", moved), Keyboard.addListener("keyboardDidHide", hidden)];
50
+ return () => {
51
+ for (const subscription of subscriptions) subscription.remove();
52
+ };
53
+ }
54
+ //#endregion
55
+ export { useKeyboardTop, watchKeyboard };
56
+
57
+ //# sourceMappingURL=keyboard.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"keyboard.js","names":["KeyboardEvent","KeyboardMetrics","useEffect","useState","Keyboard","Platform","topOf","metrics","undefined","height","screenY","useKeyboardTop","$","_c","top","setTop","_temp","t0","t1","Symbol","for","watchKeyboard","OS","listener","moved","event","endCoordinates","hidden","subscriptions","addListener","subscription","remove","_c"],"sources":["../../src/overlay/keyboard.ts"],"sourcesContent":["import type { KeyboardEvent, KeyboardMetrics } from 'react-native'\n\nimport { useEffect, useState } from 'react'\nimport { Keyboard, Platform } from 'react-native'\n\n// A keyboard reported with no height covers nothing.\nfunction topOf(metrics: KeyboardMetrics | null | undefined): null | number {\n return metrics === undefined || metrics === null || metrics.height === 0\n ? null\n : metrics.screenY\n}\n\n/**\n * Where the software keyboard's top edge is in the window, in dp, or null\n * while no keyboard is shown, for a surface that has to stay above it. A\n * field's list opens while its keyboard is up, and the keyboard is drawn\n * over the window rather than shrinking it, so the window's own edge would\n * put the bottom of the list under the keys.\n */\nfunction useKeyboardTop(): null | number {\n const [top, setTop] = useState(() =>\n Platform.OS === 'web' ? null : topOf(Keyboard.metrics()),\n )\n\n useEffect(() => watchKeyboard(setTop), [])\n\n return top\n}\n\n/**\n * Hands `listener` where the software keyboard's top edge is, or null, each\n * time the keyboard moves, and returns what stops it. iOS reports a frame as\n * the keyboard starts to move, and Android once it has arrived or gone,\n * which is all either reports. React Native Web has no keyboard to report,\n * and reports nothing.\n */\nfunction watchKeyboard(listener: (top: null | number) => void): () => void {\n const moved = (event: KeyboardEvent) => {\n listener(topOf(event.endCoordinates))\n }\n const hidden = () => {\n listener(null)\n }\n const subscriptions =\n Platform.OS === 'ios'\n ? [\n Keyboard.addListener('keyboardWillChangeFrame', moved),\n Keyboard.addListener('keyboardWillHide', hidden),\n ]\n : [\n Keyboard.addListener('keyboardDidShow', moved),\n Keyboard.addListener('keyboardDidHide', hidden),\n ]\n\n return () => {\n for (const subscription of subscriptions) {\n subscription.remove()\n }\n }\n}\n\nexport { useKeyboardTop, watchKeyboard }\n"],"mappings":";;;;AAMA,SAASM,MAAMC,SAA4D;CACzE,OAAOA,YAAYC,KAAAA,KAAaD,YAAY,QAAQA,QAAQE,WAAW,IACnE,OACAF,QAAQG;AACd;;;;;;;;AASA,SAAAC,iBAAA;CAAA,MAAAC,IAAAC,EAAA,CAAA;CACE,MAAA,CAAAC,KAAAC,UAAsBZ,SAASa,KAE/B;CAAC,IAAAC;CAAA,IAAAC;CAAA,IAAAN,EAAA,OAAAO,OAAAC,IAAA,2BAAA,GAAA;EAESH,WAAMI,cAAcN,MAAM;EAAGG,KAAA,CAAA;EAAEN,EAAA,KAAAK;EAAAL,EAAA,KAAAM;CAAA,OAAA;EAAAD,KAAAL,EAAA;EAAAM,KAAAN,EAAA;CAAA;CAAzCV,UAAUe,IAA6BC,EAAE;CAAC,OAEnCJ;AAAG;;;;;;;;AAPZ,SAAAE,QAAA;CAAA,OAEIX,SAAQiB,OAAQ,QAAhB,OAA+BhB,MAAMF,SAAQG,QAAS,CAAC;AAAC;AAe5D,SAASc,cAAcE,UAAoD;CACzE,MAAMC,SAASC,UAAyB;EACtCF,SAASjB,MAAMmB,MAAMC,cAAc,CAAC;CACtC;CACA,MAAMC,eAAe;EACnBJ,SAAS,IAAI;CACf;CACA,MAAMK,gBACJvB,SAASiB,OAAO,QACZ,CACElB,SAASyB,YAAY,2BAA2BL,KAAK,GACrDpB,SAASyB,YAAY,oBAAoBF,MAAM,CAAC,IAElD,CACEvB,SAASyB,YAAY,mBAAmBL,KAAK,GAC7CpB,SAASyB,YAAY,mBAAmBF,MAAM,CAAC;CAGvD,aAAa;EACX,KAAK,MAAMG,gBAAgBF,eACzBE,aAAaC,OAAO;CAExB;AACF"}
@@ -1,9 +1,9 @@
1
1
  import { useTheme } from "../theme/scope.js";
2
2
  import { c } from "react/compiler-runtime";
3
- import { AccessibilityInfo, BackHandler, Platform, Pressable, StyleSheet } from "react-native";
3
+ import { AccessibilityInfo, BackHandler, I18nManager, Platform, Pressable, StyleSheet, View } from "react-native";
4
4
  import { Easing, useAnimatedStyle, useReducedMotion, useSharedValue, withTiming } from "react-native-reanimated";
5
5
  import { useEffect, useRef } from "react";
6
- import { jsx } from "react/jsx-runtime";
6
+ import { jsx, jsxs } from "react/jsx-runtime";
7
7
  //#region src/overlay/panel.tsx
8
8
  const SCALE_FROM = .95;
9
9
  /** The edge a panel grows from, the one facing its anchor. */
@@ -13,39 +13,181 @@ const PANEL_ORIGINS = {
13
13
  right: "left",
14
14
  top: "bottom"
15
15
  };
16
- const styles = StyleSheet.create({ layer: {
17
- bottom: 0,
18
- left: 0,
19
- position: "absolute",
20
- right: 0,
21
- top: 0
22
- } });
16
+ const styles = StyleSheet.create({
17
+ layer: {
18
+ bottom: 0,
19
+ left: 0,
20
+ position: "absolute",
21
+ right: 0,
22
+ top: 0
23
+ },
24
+ layerAround: {
25
+ bottom: 0,
26
+ left: 0,
27
+ pointerEvents: "box-none",
28
+ position: "absolute",
29
+ right: 0,
30
+ top: 0
31
+ }
32
+ });
23
33
  /**
24
34
  * The layer a press outside a non-modal panel lands on, drawn just before the
25
35
  * panel so it sits under it. The press goes no further, so a press on the
26
- * trigger closes the panel rather than opening it again, as on web. Nothing
27
- * but that press reaches it: React Native Web's Pressable is a tab stop
28
- * unless told otherwise, whatever `focusable` says.
36
+ * trigger closes the panel rather than opening it again, as on web.
37
+ *
38
+ * Given a `hole`, the layer is drawn around that frame rather than over it,
39
+ * so a press there reaches the screen under it and leaves the panel open: a
40
+ * combo box's box, where a tap places the caret in the text being typed, as
41
+ * a click in a combo box's input leaves its list open on web.
29
42
  */
30
43
  function DismissLayer(t0) {
31
- const $ = c(2);
32
- const { onPress } = t0;
44
+ const $ = c(21);
45
+ const { hole, onPress } = t0;
46
+ if (hole === void 0) {
47
+ let t1;
48
+ if ($[0] !== onPress) {
49
+ t1 = /* @__PURE__ */ jsx(LayerPart, {
50
+ onPress,
51
+ style: styles.layer
52
+ });
53
+ $[0] = onPress;
54
+ $[1] = t1;
55
+ } else t1 = $[1];
56
+ return t1;
57
+ }
58
+ let t1;
59
+ if ($[2] !== hole) {
60
+ t1 = partsAround(hole);
61
+ $[2] = hole;
62
+ $[3] = t1;
63
+ } else t1 = $[3];
64
+ const parts = t1;
65
+ let t2;
66
+ if ($[4] !== onPress || $[5] !== parts.above) {
67
+ t2 = /* @__PURE__ */ jsx(LayerPart, {
68
+ onPress,
69
+ style: parts.above
70
+ });
71
+ $[4] = onPress;
72
+ $[5] = parts.above;
73
+ $[6] = t2;
74
+ } else t2 = $[6];
75
+ let t3;
76
+ if ($[7] !== onPress || $[8] !== parts.below) {
77
+ t3 = /* @__PURE__ */ jsx(LayerPart, {
78
+ onPress,
79
+ style: parts.below
80
+ });
81
+ $[7] = onPress;
82
+ $[8] = parts.below;
83
+ $[9] = t3;
84
+ } else t3 = $[9];
85
+ let t4;
86
+ if ($[10] !== onPress || $[11] !== parts.left) {
87
+ t4 = /* @__PURE__ */ jsx(LayerPart, {
88
+ onPress,
89
+ style: parts.left
90
+ });
91
+ $[10] = onPress;
92
+ $[11] = parts.left;
93
+ $[12] = t4;
94
+ } else t4 = $[12];
95
+ let t5;
96
+ if ($[13] !== onPress || $[14] !== parts.right) {
97
+ t5 = /* @__PURE__ */ jsx(LayerPart, {
98
+ onPress,
99
+ style: parts.right
100
+ });
101
+ $[13] = onPress;
102
+ $[14] = parts.right;
103
+ $[15] = t5;
104
+ } else t5 = $[15];
105
+ let t6;
106
+ if ($[16] !== t2 || $[17] !== t3 || $[18] !== t4 || $[19] !== t5) {
107
+ t6 = /* @__PURE__ */ jsxs(View, {
108
+ style: styles.layerAround,
109
+ children: [
110
+ t2,
111
+ t3,
112
+ t4,
113
+ t5
114
+ ]
115
+ });
116
+ $[16] = t2;
117
+ $[17] = t3;
118
+ $[18] = t4;
119
+ $[19] = t5;
120
+ $[20] = t6;
121
+ } else t6 = $[20];
122
+ return t6;
123
+ }
124
+ /**
125
+ * One piece of the layer. Nothing but a press reaches it: React Native Web's
126
+ * Pressable is a tab stop unless told otherwise, whatever `focusable` says.
127
+ */
128
+ function LayerPart(t0) {
129
+ const $ = c(3);
130
+ const { onPress, style } = t0;
33
131
  let t1;
34
- if ($[0] !== onPress) {
132
+ if ($[0] !== onPress || $[1] !== style) {
35
133
  t1 = /* @__PURE__ */ jsx(Pressable, {
36
134
  accessible: false,
37
135
  "aria-hidden": true,
38
136
  focusable: false,
39
137
  onPress,
40
- style: styles.layer,
138
+ style,
41
139
  tabIndex: -1
42
140
  });
43
141
  $[0] = onPress;
44
- $[1] = t1;
45
- } else t1 = $[1];
142
+ $[1] = style;
143
+ $[2] = t1;
144
+ } else t1 = $[2];
46
145
  return t1;
47
146
  }
48
147
  /**
148
+ * The four pieces of a layer drawn around a frame: the bands above and below
149
+ * it, across the whole layer, and the two beside it, as tall as it. The frame
150
+ * is in physical coordinates, as `measureInWindow` reports it, and React
151
+ * Native swaps `left` and `right` in a right-to-left layout unless an app
152
+ * turns that off, so there each side is set through the other's name.
153
+ */
154
+ function partsAround({ height, width, x, y }) {
155
+ const swapped = I18nManager.isRTL && I18nManager.doLeftAndRightSwapInRTL;
156
+ const left = swapped ? "right" : "left";
157
+ const right = swapped ? "left" : "right";
158
+ const beside = {
159
+ height,
160
+ position: "absolute",
161
+ top: y
162
+ };
163
+ return {
164
+ above: {
165
+ height: Math.max(0, y),
166
+ left: 0,
167
+ position: "absolute",
168
+ right: 0,
169
+ top: 0
170
+ },
171
+ below: {
172
+ bottom: 0,
173
+ left: 0,
174
+ position: "absolute",
175
+ right: 0,
176
+ top: y + height
177
+ },
178
+ left: {
179
+ ...beside,
180
+ [left]: 0,
181
+ width: Math.max(0, x)
182
+ },
183
+ right: {
184
+ ...beside,
185
+ [left]: x + width,
186
+ [right]: 0
187
+ }
188
+ };
189
+ }
190
+ /**
49
191
  * Closes a non-modal panel from Android's back gesture, as a `Modal` closes a
50
192
  * modal one. React Native calls the latest listener first, so a panel opened
51
193
  * from another closes before the one it came from. React Native Web has no
@@ -111,6 +253,14 @@ function useFocusOnPlaced(ready, target) {
111
253
  * until then. Under reduced motion it arrives and leaves at once.
112
254
  */
113
255
  function usePanelMotion(isOpen, placed, setPresent) {
256
+ return usePanelStyle(usePanelShown(isOpen, placed, setPresent));
257
+ }
258
+ /**
259
+ * How far a panel has arrived, from 0 to 1, on `usePanelMotion`'s timing,
260
+ * for a panel that moves something besides itself with it, as a picker's
261
+ * scrim fades with the surface it is cast by.
262
+ */
263
+ function usePanelShown(isOpen, placed, setPresent) {
114
264
  const $ = c(8);
115
265
  const { motion } = useTheme();
116
266
  const reduceMotion = useReducedMotion();
@@ -164,6 +314,10 @@ function usePanelMotion(isOpen, placed, setPresent) {
164
314
  t1 = $[7];
165
315
  }
166
316
  useEffect(t0, t1);
317
+ return shown;
318
+ }
319
+ /** The panel's fade and scale, for how far it has arrived. */
320
+ function usePanelStyle(shown) {
167
321
  return useAnimatedStyle(() => {
168
322
  "worklet";
169
323
  const progress = shown.get();
@@ -210,6 +364,6 @@ function useReturnFocus(present, quiet, trigger) {
210
364
  useEffect(t0, t1);
211
365
  }
212
366
  //#endregion
213
- export { DismissLayer, PANEL_ORIGINS, useBackToClose, useFocusOnPlaced, usePanelMotion, useReturnFocus };
367
+ export { DismissLayer, PANEL_ORIGINS, useBackToClose, useFocusOnPlaced, usePanelMotion, usePanelShown, usePanelStyle, useReturnFocus };
214
368
 
215
369
  //# sourceMappingURL=panel.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"panel.js","names":["RefObject","HostInstance","useEffect","useRef","AccessibilityInfo","BackHandler","Platform","Pressable","StyleSheet","Easing","useAnimatedStyle","useReducedMotion","useSharedValue","withTiming","OverlaySide","useTheme","SCALE_FROM","PANEL_ORIGINS","bottom","left","right","top","const","Record","styles","create","layer","position","DismissLayer","t0","$","_c","onPress","t1","useBackToClose","close","active","OS","subscription","addEventListener","remove","useFocusOnPlaced","ready","target","sendAccessibilityEvent","usePanelMotion","isOpen","placed","setPresent","motion","reduceMotion","shown","set","duration","durationShort3","easing","bezier","easingEmphasizedDecelerate","durationShort2","easingEmphasizedAccelerate","timer","setTimeout","clearTimeout","progress","get","opacity","transform","scale","useReturnFocus","present","quiet","trigger","current","gone","_c"],"sources":["../../src/overlay/panel.tsx"],"sourcesContent":["import type { RefObject } from 'react'\nimport type { HostInstance } from 'react-native'\n\nimport { useEffect, useRef } from 'react'\nimport {\n AccessibilityInfo,\n BackHandler,\n Platform,\n Pressable,\n StyleSheet,\n} from 'react-native'\nimport {\n Easing,\n useAnimatedStyle,\n useReducedMotion,\n useSharedValue,\n withTiming,\n} from 'react-native-reanimated'\n\nimport type { OverlaySide } from './placement'\n\nimport { useTheme } from '../theme/scope'\n\n// What a non-modal panel anchored beside its trigger does besides being\n// placed, shared by Popover and Menu so the two cannot drift: the layer a\n// press outside lands on, Android's back gesture, the motion in and out, and\n// where a screen reader is sent as it comes and goes.\n\n// What the panel scales up from as it arrives, web's keyframes'.\nconst SCALE_FROM = 0.95\n\n/** The edge a panel grows from, the one facing its anchor. */\nconst PANEL_ORIGINS = {\n bottom: 'top',\n left: 'right',\n right: 'left',\n top: 'bottom',\n} as const satisfies Record<OverlaySide, string>\n\nconst styles = StyleSheet.create({\n // Over the whole screen and under the panel.\n layer: {\n bottom: 0,\n left: 0,\n position: 'absolute',\n right: 0,\n top: 0,\n },\n})\n\n/**\n * The layer a press outside a non-modal panel lands on, drawn just before the\n * panel so it sits under it. The press goes no further, so a press on the\n * trigger closes the panel rather than opening it again, as on web. Nothing\n * but that press reaches it: React Native Web's Pressable is a tab stop\n * unless told otherwise, whatever `focusable` says.\n */\nfunction DismissLayer({ onPress }: { readonly onPress: () => void }) {\n return (\n <Pressable\n accessible={false}\n aria-hidden\n focusable={false}\n onPress={onPress}\n style={styles.layer}\n tabIndex={-1}\n />\n )\n}\n\n/**\n * Closes a non-modal panel from Android's back gesture, as a `Modal` closes a\n * modal one. React Native calls the latest listener first, so a panel opened\n * from another closes before the one it came from. React Native Web has no\n * back gesture, and its BackHandler reports an error when one is listened for,\n * so nothing listens there.\n */\nfunction useBackToClose(close: () => void, active: boolean) {\n useEffect(() => {\n if (!active || Platform.OS === 'web') {\n return undefined\n }\n\n const subscription = BackHandler.addEventListener(\n 'hardwareBackPress',\n () => {\n close()\n return true\n },\n )\n\n return () => {\n subscription.remove()\n }\n }, [active, close])\n}\n\n/**\n * Sends the screen reader to `target` once `ready`, which a panel passes once\n * it has been placed, and so can be seen. React Native Web has no screen\n * reader of its own to send.\n */\nfunction useFocusOnPlaced(ready: boolean, target: HostInstance | null) {\n useEffect(() => {\n if (ready && target !== null && Platform.OS !== 'web') {\n AccessibilityInfo.sendAccessibilityEvent(target, 'focus')\n }\n }, [ready, target])\n}\n\n/**\n * A panel's motion, and the timer that unmounts it once its exit has run: it\n * fades and scales up from 95% over the short3 duration on the emphasised\n * decelerating curve, and back over short2 on the accelerating one. The\n * entrance waits for the panel to be placed, so it is not spent while the\n * panel is still hidden being measured, and the panel stays transparent\n * until then. Under reduced motion it arrives and leaves at once.\n */\nfunction usePanelMotion(\n isOpen: boolean,\n placed: boolean,\n setPresent: (present: boolean) => void,\n) {\n const { motion } = useTheme()\n const reduceMotion = useReducedMotion()\n const shown = useSharedValue(0)\n\n useEffect(() => {\n if (isOpen && !placed) {\n return undefined\n }\n\n if (isOpen) {\n shown.set(\n reduceMotion\n ? 1\n : withTiming(1, {\n duration: motion.durationShort3,\n easing: Easing.bezier(...motion.easingEmphasizedDecelerate),\n }),\n )\n return undefined\n }\n\n if (reduceMotion) {\n shown.set(0)\n setPresent(false)\n return undefined\n }\n\n shown.set(\n withTiming(0, {\n duration: motion.durationShort2,\n easing: Easing.bezier(...motion.easingEmphasizedAccelerate),\n }),\n )\n const timer = setTimeout(() => {\n setPresent(false)\n }, motion.durationShort2)\n\n return () => {\n clearTimeout(timer)\n }\n }, [isOpen, motion, placed, reduceMotion, setPresent, shown])\n\n return useAnimatedStyle(() => {\n 'worklet'\n const progress = shown.get()\n\n return {\n opacity: progress,\n transform: [{ scale: SCALE_FROM + (1 - SCALE_FROM) * progress }],\n }\n })\n}\n\n/**\n * Sends the screen reader back to the trigger once a panel has gone, unless\n * `quiet` says nothing moved it there, as a pointer resting on a hover\n * trigger does not. React Native Web's `Modal` restores focus itself, and has\n * no screen reader to send otherwise.\n */\nfunction useReturnFocus(\n present: boolean,\n quiet: boolean,\n trigger: RefObject<HostInstance | null>,\n) {\n const shown = useRef(present)\n\n useEffect(() => {\n const gone = shown.current && !present\n const target = trigger.current\n\n shown.current = present\n if (gone && !quiet && target !== null && Platform.OS !== 'web') {\n AccessibilityInfo.sendAccessibilityEvent(target, 'focus')\n }\n }, [quiet, present, trigger])\n}\n\nexport {\n DismissLayer,\n PANEL_ORIGINS,\n useBackToClose,\n useFocusOnPlaced,\n usePanelMotion,\n useReturnFocus,\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"panel.js","names":["RefObject","HostInstance","ViewStyle","SharedValue","useEffect","useRef","AccessibilityInfo","BackHandler","I18nManager","Platform","Pressable","StyleSheet","View","Easing","useAnimatedStyle","useReducedMotion","useSharedValue","withTiming","OverlaySide","Rect","useTheme","SCALE_FROM","PANEL_ORIGINS","bottom","left","right","top","const","Record","styles","create","layer","position","layerAround","pointerEvents","DismissLayer","t0","$","_c","hole","onPress","undefined","t1","partsAround","parts","t2","above","t3","below","t4","t5","t6","LayerPart","style","height","width","x","y","swapped","isRTL","doLeftAndRightSwapInRTL","beside","Math","max","useBackToClose","close","active","OS","subscription","addEventListener","remove","useFocusOnPlaced","ready","target","sendAccessibilityEvent","usePanelMotion","isOpen","placed","setPresent","usePanelStyle","usePanelShown","motion","reduceMotion","shown","set","duration","durationShort3","easing","bezier","easingEmphasizedDecelerate","durationShort2","easingEmphasizedAccelerate","timer","setTimeout","clearTimeout","progress","get","opacity","transform","scale","useReturnFocus","present","quiet","trigger","current","gone","_c"],"sources":["../../src/overlay/panel.tsx"],"sourcesContent":["import type { RefObject } from 'react'\nimport type { HostInstance, ViewStyle } from 'react-native'\nimport type { SharedValue } from 'react-native-reanimated'\n\nimport { useEffect, useRef } from 'react'\nimport {\n AccessibilityInfo,\n BackHandler,\n I18nManager,\n Platform,\n Pressable,\n StyleSheet,\n View,\n} from 'react-native'\nimport {\n Easing,\n useAnimatedStyle,\n useReducedMotion,\n useSharedValue,\n withTiming,\n} from 'react-native-reanimated'\n\nimport type { OverlaySide, Rect } from './placement'\n\nimport { useTheme } from '../theme/scope'\n\n// What a non-modal panel anchored beside its trigger does besides being\n// placed, shared by Popover and Menu so the two cannot drift: the layer a\n// press outside lands on, Android's back gesture, the motion in and out, and\n// where a screen reader is sent as it comes and goes.\n\n// What the panel scales up from as it arrives, web's keyframes'.\nconst SCALE_FROM = 0.95\n\n/** The edge a panel grows from, the one facing its anchor. */\nconst PANEL_ORIGINS = {\n bottom: 'top',\n left: 'right',\n right: 'left',\n top: 'bottom',\n} as const satisfies Record<OverlaySide, string>\n\nconst styles = StyleSheet.create({\n // Over the whole screen and under the panel.\n layer: {\n bottom: 0,\n left: 0,\n position: 'absolute',\n right: 0,\n top: 0,\n },\n // The same, passing a press through wherever no part of it is drawn.\n layerAround: {\n bottom: 0,\n left: 0,\n pointerEvents: 'box-none',\n position: 'absolute',\n right: 0,\n top: 0,\n },\n})\n\n/**\n * The layer a press outside a non-modal panel lands on, drawn just before the\n * panel so it sits under it. The press goes no further, so a press on the\n * trigger closes the panel rather than opening it again, as on web.\n *\n * Given a `hole`, the layer is drawn around that frame rather than over it,\n * so a press there reaches the screen under it and leaves the panel open: a\n * combo box's box, where a tap places the caret in the text being typed, as\n * a click in a combo box's input leaves its list open on web.\n */\nfunction DismissLayer({\n hole,\n onPress,\n}: {\n readonly hole?: Rect | undefined\n readonly onPress: () => void\n}) {\n if (hole === undefined) {\n return <LayerPart onPress={onPress} style={styles.layer} />\n }\n\n const parts = partsAround(hole)\n\n return (\n <View style={styles.layerAround}>\n <LayerPart onPress={onPress} style={parts.above} />\n <LayerPart onPress={onPress} style={parts.below} />\n <LayerPart onPress={onPress} style={parts.left} />\n <LayerPart onPress={onPress} style={parts.right} />\n </View>\n )\n}\n\n/**\n * One piece of the layer. Nothing but a press reaches it: React Native Web's\n * Pressable is a tab stop unless told otherwise, whatever `focusable` says.\n */\nfunction LayerPart({\n onPress,\n style,\n}: {\n readonly onPress: () => void\n readonly style: ViewStyle\n}) {\n return (\n <Pressable\n accessible={false}\n aria-hidden\n focusable={false}\n onPress={onPress}\n style={style}\n tabIndex={-1}\n />\n )\n}\n\n/**\n * The four pieces of a layer drawn around a frame: the bands above and below\n * it, across the whole layer, and the two beside it, as tall as it. The frame\n * is in physical coordinates, as `measureInWindow` reports it, and React\n * Native swaps `left` and `right` in a right-to-left layout unless an app\n * turns that off, so there each side is set through the other's name.\n */\nfunction partsAround({ height, width, x, y }: Rect) {\n const swapped = I18nManager.isRTL && I18nManager.doLeftAndRightSwapInRTL\n const left = swapped ? 'right' : 'left'\n const right = swapped ? 'left' : 'right'\n const beside: ViewStyle = {\n height,\n position: 'absolute',\n top: y,\n }\n\n return {\n above: {\n height: Math.max(0, y),\n left: 0,\n position: 'absolute',\n right: 0,\n top: 0,\n },\n below: {\n bottom: 0,\n left: 0,\n position: 'absolute',\n right: 0,\n top: y + height,\n },\n left: { ...beside, [left]: 0, width: Math.max(0, x) },\n right: { ...beside, [left]: x + width, [right]: 0 },\n } satisfies Record<string, ViewStyle>\n}\n\n/**\n * Closes a non-modal panel from Android's back gesture, as a `Modal` closes a\n * modal one. React Native calls the latest listener first, so a panel opened\n * from another closes before the one it came from. React Native Web has no\n * back gesture, and its BackHandler reports an error when one is listened for,\n * so nothing listens there.\n */\nfunction useBackToClose(close: () => void, active: boolean) {\n useEffect(() => {\n if (!active || Platform.OS === 'web') {\n return undefined\n }\n\n const subscription = BackHandler.addEventListener(\n 'hardwareBackPress',\n () => {\n close()\n return true\n },\n )\n\n return () => {\n subscription.remove()\n }\n }, [active, close])\n}\n\n/**\n * Sends the screen reader to `target` once `ready`, which a panel passes once\n * it has been placed, and so can be seen. React Native Web has no screen\n * reader of its own to send.\n */\nfunction useFocusOnPlaced(ready: boolean, target: HostInstance | null) {\n useEffect(() => {\n if (ready && target !== null && Platform.OS !== 'web') {\n AccessibilityInfo.sendAccessibilityEvent(target, 'focus')\n }\n }, [ready, target])\n}\n\n/**\n * A panel's motion, and the timer that unmounts it once its exit has run: it\n * fades and scales up from 95% over the short3 duration on the emphasised\n * decelerating curve, and back over short2 on the accelerating one. The\n * entrance waits for the panel to be placed, so it is not spent while the\n * panel is still hidden being measured, and the panel stays transparent\n * until then. Under reduced motion it arrives and leaves at once.\n */\nfunction usePanelMotion(\n isOpen: boolean,\n placed: boolean,\n setPresent: (present: boolean) => void,\n) {\n return usePanelStyle(usePanelShown(isOpen, placed, setPresent))\n}\n\n/**\n * How far a panel has arrived, from 0 to 1, on `usePanelMotion`'s timing,\n * for a panel that moves something besides itself with it, as a picker's\n * scrim fades with the surface it is cast by.\n */\nfunction usePanelShown(\n isOpen: boolean,\n placed: boolean,\n setPresent: (present: boolean) => void,\n) {\n const { motion } = useTheme()\n const reduceMotion = useReducedMotion()\n const shown = useSharedValue(0)\n\n useEffect(() => {\n if (isOpen && !placed) {\n return undefined\n }\n\n if (isOpen) {\n shown.set(\n reduceMotion\n ? 1\n : withTiming(1, {\n duration: motion.durationShort3,\n easing: Easing.bezier(...motion.easingEmphasizedDecelerate),\n }),\n )\n return undefined\n }\n\n if (reduceMotion) {\n shown.set(0)\n setPresent(false)\n return undefined\n }\n\n shown.set(\n withTiming(0, {\n duration: motion.durationShort2,\n easing: Easing.bezier(...motion.easingEmphasizedAccelerate),\n }),\n )\n const timer = setTimeout(() => {\n setPresent(false)\n }, motion.durationShort2)\n\n return () => {\n clearTimeout(timer)\n }\n }, [isOpen, motion, placed, reduceMotion, setPresent, shown])\n\n return shown\n}\n\n/** The panel's fade and scale, for how far it has arrived. */\nfunction usePanelStyle(shown: SharedValue<number>) {\n return useAnimatedStyle(() => {\n 'worklet'\n const progress = shown.get()\n\n return {\n opacity: progress,\n transform: [{ scale: SCALE_FROM + (1 - SCALE_FROM) * progress }],\n }\n })\n}\n\n/**\n * Sends the screen reader back to the trigger once a panel has gone, unless\n * `quiet` says nothing moved it there, as a pointer resting on a hover\n * trigger does not. React Native Web's `Modal` restores focus itself, and has\n * no screen reader to send otherwise.\n */\nfunction useReturnFocus(\n present: boolean,\n quiet: boolean,\n trigger: RefObject<HostInstance | null>,\n) {\n const shown = useRef(present)\n\n useEffect(() => {\n const gone = shown.current && !present\n const target = trigger.current\n\n shown.current = present\n if (gone && !quiet && target !== null && Platform.OS !== 'web') {\n AccessibilityInfo.sendAccessibilityEvent(target, 'focus')\n }\n }, [quiet, present, trigger])\n}\n\nexport {\n DismissLayer,\n PANEL_ORIGINS,\n useBackToClose,\n useFocusOnPlaced,\n usePanelMotion,\n usePanelShown,\n usePanelStyle,\n useReturnFocus,\n}\n"],"mappings":"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"}
@@ -6,6 +6,18 @@ const OPPOSITE = {
6
6
  top: "bottom"
7
7
  };
8
8
  /**
9
+ * Bounds that end above the software keyboard, with the same padding above
10
+ * it, where one is shown: its top edge in the window, or null.
11
+ */
12
+ function aboveKeyboard(bounds, keyboardTop, padding) {
13
+ if (keyboardTop === null) return bounds;
14
+ const bottom = Math.min(bounds.y + bounds.height, keyboardTop - padding);
15
+ return {
16
+ ...bounds,
17
+ height: Math.max(0, bottom - bounds.y)
18
+ };
19
+ }
20
+ /**
9
21
  * Where a surface of a given length starts along the anchor, for an edge,
10
22
  * moved by the offset. However far the offset moves it, it keeps overlapping
11
23
  * the anchor, as React Aria's placement does on web.
@@ -84,6 +96,6 @@ function within(position, start, length, size) {
84
96
  return position;
85
97
  }
86
98
  //#endregion
87
- export { boundsOf, place };
99
+ export { aboveKeyboard, boundsOf, place };
88
100
 
89
101
  //# sourceMappingURL=placement.js.map