@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.
- package/README.md +4 -3
- package/dist/autocomplete/index.js +15 -1
- package/dist/autocomplete/index.js.map +1 -1
- package/dist/button/group.d.ts +5 -0
- package/dist/button/group.js +115 -0
- package/dist/button/group.js.map +1 -0
- package/dist/button/index.d.ts +4 -1
- package/dist/button/index.js +44 -22
- package/dist/button/index.js.map +1 -1
- package/dist/button/slots.js +2 -1
- package/dist/button/slots.js.map +1 -1
- package/dist/calendar/index.js +351 -182
- package/dist/calendar/index.js.map +1 -1
- package/dist/calendar/styles.js +33 -2
- package/dist/calendar/styles.js.map +1 -1
- package/dist/carousel/arrangement.d.ts +5 -0
- package/dist/carousel/arrangement.js +123 -0
- package/dist/carousel/arrangement.js.map +1 -0
- package/dist/chequer/index.js +95 -0
- package/dist/chequer/index.js.map +1 -0
- package/dist/collection/index.d.ts +157 -0
- package/dist/collection/index.js +1358 -0
- package/dist/collection/index.js.map +1 -0
- package/dist/color-thumb/index.js +56 -0
- package/dist/color-thumb/index.js.map +1 -0
- package/dist/components/button/index.d.ts +4 -2
- package/dist/components/button/index.js +227 -188
- package/dist/components/button/index.js.map +1 -1
- package/dist/components/button-group/index.d.ts +87 -0
- package/dist/components/button-group/index.js +275 -0
- package/dist/components/button-group/index.js.map +1 -0
- package/dist/components/calendar/index.d.ts +11 -3
- package/dist/components/calendar/index.js +60 -45
- package/dist/components/calendar/index.js.map +1 -1
- package/dist/components/carousel/index.d.ts +72 -0
- package/dist/components/carousel/index.js +496 -0
- package/dist/components/carousel/index.js.map +1 -0
- package/dist/components/checkbox-group/index.d.ts +3 -4
- package/dist/components/checkbox-group/index.js +1 -1
- package/dist/components/checkbox-group/index.js.map +1 -1
- package/dist/components/chip/index.d.ts +4 -1
- package/dist/components/chip/index.js +229 -161
- package/dist/components/chip/index.js.map +1 -1
- package/dist/components/color-area/index.d.ts +85 -0
- package/dist/components/color-area/index.js +630 -0
- package/dist/components/color-area/index.js.map +1 -0
- package/dist/components/color-field/index.d.ts +144 -0
- package/dist/components/color-field/index.js +516 -0
- package/dist/components/color-field/index.js.map +1 -0
- package/dist/components/color-picker/index.d.ts +74 -0
- package/dist/components/color-picker/index.js +317 -0
- package/dist/components/color-picker/index.js.map +1 -0
- package/dist/components/color-slider/index.d.ts +82 -0
- package/dist/components/color-slider/index.js +456 -0
- package/dist/components/color-slider/index.js.map +1 -0
- package/dist/components/color-swatch/index.d.ts +46 -0
- package/dist/components/color-swatch/index.js +127 -0
- package/dist/components/color-swatch/index.js.map +1 -0
- package/dist/components/color-swatch-picker/index.d.ts +81 -0
- package/dist/components/color-swatch-picker/index.js +287 -0
- package/dist/components/color-swatch-picker/index.js.map +1 -0
- package/dist/components/color-wheel/index.d.ts +71 -0
- package/dist/components/color-wheel/index.js +407 -0
- package/dist/components/color-wheel/index.js.map +1 -0
- package/dist/components/combo-box/index.d.ts +193 -0
- package/dist/components/combo-box/index.js +616 -0
- package/dist/components/combo-box/index.js.map +1 -0
- package/dist/components/date-field/index.d.ts +120 -0
- package/dist/components/date-field/index.js +111 -0
- package/dist/components/date-field/index.js.map +1 -0
- package/dist/components/date-picker/index.d.ts +130 -0
- package/dist/components/date-picker/index.js +310 -0
- package/dist/components/date-picker/index.js.map +1 -0
- package/dist/components/date-range-picker/index.d.ts +139 -0
- package/dist/components/date-range-picker/index.js +421 -0
- package/dist/components/date-range-picker/index.js.map +1 -0
- package/dist/components/dialog/index.d.ts +5 -5
- package/dist/components/dialog/index.js +5 -5
- package/dist/components/dialog/index.js.map +1 -1
- package/dist/components/disclosure/index.d.ts +94 -0
- package/dist/components/disclosure/index.js +365 -0
- package/dist/components/disclosure/index.js.map +1 -0
- package/dist/components/disclosure-group/index.d.ts +61 -0
- package/dist/components/disclosure-group/index.js +100 -0
- package/dist/components/disclosure-group/index.js.map +1 -0
- package/dist/components/drop-zone/index.d.ts +113 -0
- package/dist/components/drop-zone/index.js +304 -0
- package/dist/components/drop-zone/index.js.map +1 -0
- package/dist/components/fab/index.d.ts +1 -1
- package/dist/components/fab/index.js +91 -76
- package/dist/components/fab/index.js.map +1 -1
- package/dist/components/form/index.d.ts +3 -2
- package/dist/components/form/index.js.map +1 -1
- package/dist/components/icon-button/index.d.ts +4 -2
- package/dist/components/icon-button/index.js +204 -171
- package/dist/components/icon-button/index.js.map +1 -1
- package/dist/components/list/index.d.ts +15 -158
- package/dist/components/list/index.js +21 -1047
- package/dist/components/list/index.js.map +1 -1
- package/dist/components/list-box/index.d.ts +73 -0
- package/dist/components/list-box/index.js +82 -0
- package/dist/components/list-box/index.js.map +1 -0
- package/dist/components/loading-indicator/index.d.ts +32 -0
- package/dist/components/loading-indicator/index.js +174 -0
- package/dist/components/loading-indicator/index.js.map +1 -0
- package/dist/components/menu/index.d.ts +3 -3
- package/dist/components/menu/index.js +3 -3
- package/dist/components/menu/index.js.map +1 -1
- package/dist/components/navigation-tree/index.d.ts +117 -0
- package/dist/components/navigation-tree/index.js +135 -0
- package/dist/components/navigation-tree/index.js.map +1 -0
- package/dist/components/number-field/index.js +132 -143
- package/dist/components/number-field/index.js.map +1 -1
- package/dist/components/popover/index.d.ts +2 -2
- package/dist/components/popover/index.js +2 -2
- package/dist/components/popover/index.js.map +1 -1
- package/dist/components/range-calendar/index.d.ts +69 -0
- package/dist/components/range-calendar/index.js +144 -0
- package/dist/components/range-calendar/index.js.map +1 -0
- package/dist/components/search-view/index.d.ts +79 -0
- package/dist/components/search-view/index.js +571 -0
- package/dist/components/search-view/index.js.map +1 -0
- package/dist/components/select/index.d.ts +152 -0
- package/dist/components/select/index.js +419 -0
- package/dist/components/select/index.js.map +1 -0
- package/dist/components/sheet/index.d.ts +16 -7
- package/dist/components/sheet/index.js +157 -152
- package/dist/components/sheet/index.js.map +1 -1
- package/dist/components/slider/index.d.ts +111 -0
- package/dist/components/slider/index.js +673 -0
- package/dist/components/slider/index.js.map +1 -0
- package/dist/components/split-button/index.d.ts +77 -0
- package/dist/components/split-button/index.js +354 -0
- package/dist/components/split-button/index.js.map +1 -0
- package/dist/components/table/index.d.ts +391 -0
- package/dist/components/table/index.js +1708 -0
- package/dist/components/table/index.js.map +1 -0
- package/dist/components/tabs/index.d.ts +196 -0
- package/dist/components/tabs/index.js +1137 -0
- package/dist/components/tabs/index.js.map +1 -0
- package/dist/components/time-field/index.d.ts +43 -0
- package/dist/components/time-field/index.js +107 -0
- package/dist/components/time-field/index.js.map +1 -0
- package/dist/components/time-picker/index.d.ts +65 -0
- package/dist/components/time-picker/index.js +1168 -0
- package/dist/components/time-picker/index.js.map +1 -0
- package/dist/components/token-field/index.d.ts +105 -0
- package/dist/components/token-field/index.js +574 -0
- package/dist/components/token-field/index.js.map +1 -0
- package/dist/components/tooltip/index.d.ts +102 -0
- package/dist/components/tooltip/index.js +223 -0
- package/dist/components/tooltip/index.js.map +1 -0
- package/dist/components/tree/index.d.ts +112 -0
- package/dist/components/tree/index.js +157 -0
- package/dist/components/tree/index.js.map +1 -0
- package/dist/disclosure/chevron.js +75 -0
- package/dist/disclosure/chevron.js.map +1 -0
- package/dist/disclosure/index.js +7 -0
- package/dist/disclosure/index.js.map +1 -0
- package/dist/drop/index.d.ts +54 -0
- package/dist/drop/index.js +161 -0
- package/dist/drop/index.js.map +1 -0
- package/dist/field/chevron.js +74 -0
- package/dist/field/chevron.js.map +1 -0
- package/dist/field/index.d.ts +2 -1
- package/dist/field/index.js +359 -154
- package/dist/field/index.js.map +1 -1
- package/dist/field/styles.js +18 -1
- package/dist/field/styles.js.map +1 -1
- package/dist/files/index.d.ts +18 -0
- package/dist/files/index.js +107 -0
- package/dist/files/index.js.map +1 -0
- package/dist/form/index.d.ts +5 -2
- package/dist/form/index.js +64 -85
- package/dist/form/index.js.map +1 -1
- package/dist/glyphs/index.js +128 -1
- package/dist/glyphs/index.js.map +1 -1
- package/dist/i18n/index.js +36 -1
- package/dist/i18n/index.js.map +1 -1
- package/dist/i18n/messages.js +1734 -34
- package/dist/i18n/messages.js.map +1 -1
- package/dist/index.d.ts +37 -3
- package/dist/index.js +36 -3
- package/dist/indicator/paths.js +23 -1
- package/dist/indicator/paths.js.map +1 -1
- package/dist/modal/index.js +92 -77
- package/dist/modal/index.js.map +1 -1
- package/dist/number/keyboard.js +16 -0
- package/dist/number/keyboard.js.map +1 -0
- package/dist/overlay/anchored.js +68 -38
- package/dist/overlay/anchored.js.map +1 -1
- package/dist/overlay/keyboard.js +57 -0
- package/dist/overlay/keyboard.js.map +1 -0
- package/dist/overlay/panel.js +173 -19
- package/dist/overlay/panel.js.map +1 -1
- package/dist/overlay/placement.js +13 -1
- package/dist/overlay/placement.js.map +1 -1
- package/dist/picker/index.js +322 -0
- package/dist/picker/index.js.map +1 -0
- package/dist/press/index.d.ts +2 -0
- package/dist/press/index.js +102 -100
- package/dist/press/index.js.map +1 -1
- package/dist/row/index.js +77 -69
- package/dist/row/index.js.map +1 -1
- package/dist/row/styles.js +13 -2
- package/dist/row/styles.js.map +1 -1
- package/dist/segments/field.js +277 -0
- package/dist/segments/field.js.map +1 -0
- package/dist/segments/index.js +574 -0
- package/dist/segments/index.js.map +1 -0
- package/dist/segments/styles.js +24 -0
- package/dist/segments/styles.js.map +1 -0
- package/dist/slider/index.js +145 -0
- package/dist/slider/index.js.map +1 -0
- package/dist/swatch/index.js +56 -0
- package/dist/swatch/index.js.map +1 -0
- package/package.json +11 -2
package/dist/overlay/anchored.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { useTheme } from "../theme/scope.js";
|
|
2
2
|
import { OverlayHostContext } from "./host.js";
|
|
3
|
-
import {
|
|
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.
|
|
28
|
-
*
|
|
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
|
|
33
|
+
* a new size, the window changes size or the keyboard moves.
|
|
32
34
|
*/
|
|
33
35
|
function useAnchoredPlacement(t0) {
|
|
34
|
-
const $ = c(
|
|
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 || $[
|
|
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] =
|
|
135
|
-
$[15] =
|
|
136
|
-
$[16] =
|
|
137
|
-
$[17] =
|
|
138
|
-
$[18] = spacing.
|
|
139
|
-
$[19] =
|
|
140
|
-
$[20] =
|
|
141
|
-
$[21] =
|
|
142
|
-
|
|
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 =
|
|
146
|
-
|
|
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] !==
|
|
158
|
+
if ($[23] !== measured.anchor.height || $[24] !== measured.anchor.width || $[25] !== t8 || $[26] !== t9) {
|
|
154
159
|
t10 = {
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
160
|
+
height: measured.anchor.height,
|
|
161
|
+
width: measured.anchor.width,
|
|
162
|
+
x: t8,
|
|
163
|
+
y: t9
|
|
159
164
|
};
|
|
160
|
-
$[
|
|
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
|
-
|
|
166
|
-
|
|
167
|
-
|
|
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:
|
|
199
|
+
style: t13
|
|
172
200
|
};
|
|
173
|
-
$[
|
|
174
|
-
$[
|
|
175
|
-
$[
|
|
176
|
-
|
|
177
|
-
|
|
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":"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"}
|
|
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"}
|
package/dist/overlay/panel.js
CHANGED
|
@@ -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({
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
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.
|
|
27
|
-
*
|
|
28
|
-
*
|
|
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(
|
|
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
|
|
138
|
+
style,
|
|
41
139
|
tabIndex: -1
|
|
42
140
|
});
|
|
43
141
|
$[0] = onPress;
|
|
44
|
-
$[1] =
|
|
45
|
-
|
|
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
|