@vellira-ui/react-native 2.57.0 → 2.58.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/dist/index.js +1035 -714
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { Children, cloneElement, createContext, forwardRef, isValidElement, useCallback, useContext, useEffect, useId, useMemo, useRef, useState } from "react";
|
|
2
2
|
import { Check, ChevronDown, Close, Search } from "@vellira-ui/icons";
|
|
3
3
|
import { AccessibilityInfo, ActivityIndicator, Animated, BackHandler, Dimensions, Easing, FlatList, Modal as Modal$1, Platform, Pressable, ScrollView, StyleSheet, Text, TextInput, View, findNodeHandle, useWindowDimensions } from "react-native";
|
|
4
|
+
import { createConsoleOverlayDiagnostics, createOverlayZIndexPolicy, resolveOverlayZIndex } from "@vellira-ui/core";
|
|
4
5
|
import { darkTheme, highContrastTheme, lightTheme } from "@vellira-ui/tokens";
|
|
5
6
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
6
7
|
//#region src/theme/fontWeight.ts
|
|
@@ -23,306 +24,254 @@ function toNativeFontWeight(weight) {
|
|
|
23
24
|
return normalizedWeight;
|
|
24
25
|
}
|
|
25
26
|
//#endregion
|
|
26
|
-
//#region src/managers/
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
}
|
|
37
|
-
function createPlacement(side, align) {
|
|
38
|
-
return align === "center" ? side : `${side}-${align}`;
|
|
39
|
-
}
|
|
40
|
-
function getOppositeSide(side) {
|
|
41
|
-
switch (side) {
|
|
42
|
-
case "top": return "bottom";
|
|
43
|
-
case "right": return "left";
|
|
44
|
-
case "bottom": return "top";
|
|
45
|
-
case "left": return "right";
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
function computeBasePosition({ reference, floating, side, align, offset }) {
|
|
49
|
-
const referenceCenterX = reference.x + reference.width / 2;
|
|
50
|
-
const referenceCenterY = reference.y + reference.height / 2;
|
|
51
|
-
const alignedLeft = align === "start" ? reference.x : align === "end" ? reference.x + reference.width - floating.width : referenceCenterX - floating.width / 2;
|
|
52
|
-
const alignedTop = align === "start" ? reference.y : align === "end" ? reference.y + reference.height - floating.height : referenceCenterY - floating.height / 2;
|
|
53
|
-
switch (side) {
|
|
54
|
-
case "top": return {
|
|
55
|
-
top: reference.y - floating.height - offset,
|
|
56
|
-
left: alignedLeft
|
|
57
|
-
};
|
|
58
|
-
case "right": return {
|
|
59
|
-
top: alignedTop,
|
|
60
|
-
left: reference.x + reference.width + offset
|
|
61
|
-
};
|
|
62
|
-
case "bottom": return {
|
|
63
|
-
top: reference.y + reference.height + offset,
|
|
64
|
-
left: alignedLeft
|
|
65
|
-
};
|
|
66
|
-
case "left": return {
|
|
67
|
-
top: alignedTop,
|
|
68
|
-
left: reference.x - floating.width - offset
|
|
69
|
-
};
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
function getMainAxisOverflow({ side, position, floating, boundary, padding }) {
|
|
73
|
-
switch (side) {
|
|
74
|
-
case "top": return padding - position.top;
|
|
75
|
-
case "right": return position.left + floating.width + padding - boundary.width;
|
|
76
|
-
case "bottom": return position.top + floating.height + padding - boundary.height;
|
|
77
|
-
case "left": return padding - position.left;
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
function computeFloatingPosition({ reference, floating, boundary, placement, offset = 8, padding = 12, arrowPadding = 16, flip = true, shift = true }) {
|
|
81
|
-
const parsed = parsePlacement(placement);
|
|
82
|
-
let resolvedSide = parsed.side;
|
|
83
|
-
let position = computeBasePosition({
|
|
84
|
-
reference,
|
|
85
|
-
floating,
|
|
86
|
-
side: resolvedSide,
|
|
87
|
-
align: parsed.align,
|
|
88
|
-
offset
|
|
89
|
-
});
|
|
90
|
-
if (flip && getMainAxisOverflow({
|
|
91
|
-
side: resolvedSide,
|
|
92
|
-
position,
|
|
93
|
-
floating,
|
|
94
|
-
boundary,
|
|
95
|
-
padding
|
|
96
|
-
}) > 0) {
|
|
97
|
-
const oppositeSide = getOppositeSide(resolvedSide);
|
|
98
|
-
const oppositePosition = computeBasePosition({
|
|
99
|
-
reference,
|
|
100
|
-
floating,
|
|
101
|
-
side: oppositeSide,
|
|
102
|
-
align: parsed.align,
|
|
103
|
-
offset
|
|
104
|
-
});
|
|
105
|
-
if (getMainAxisOverflow({
|
|
106
|
-
side: oppositeSide,
|
|
107
|
-
position: oppositePosition,
|
|
108
|
-
floating,
|
|
109
|
-
boundary,
|
|
110
|
-
padding
|
|
111
|
-
}) <= 0) {
|
|
112
|
-
resolvedSide = oppositeSide;
|
|
113
|
-
position = oppositePosition;
|
|
114
|
-
}
|
|
115
|
-
}
|
|
116
|
-
if (shift) position = {
|
|
117
|
-
top: clamp(position.top, padding, boundary.height - floating.height - padding),
|
|
118
|
-
left: clamp(position.left, padding, boundary.width - floating.width - padding)
|
|
119
|
-
};
|
|
120
|
-
const referenceCenterX = reference.x + reference.width / 2;
|
|
121
|
-
const referenceCenterY = reference.y + reference.height / 2;
|
|
122
|
-
const arrowPosition = resolvedSide === "top" || resolvedSide === "bottom" ? { left: clamp(referenceCenterX - position.left, arrowPadding, floating.width - arrowPadding) } : { top: clamp(referenceCenterY - position.top, arrowPadding, floating.height - arrowPadding) };
|
|
27
|
+
//#region src/managers/OverlayManager/NativeOverlayManager.ts
|
|
28
|
+
const nativeOverlayZIndexPolicy = createOverlayZIndexPolicy({
|
|
29
|
+
defaultLevel: "modal",
|
|
30
|
+
levels: { modal: lightTheme.tokens.zIndex.modal }
|
|
31
|
+
});
|
|
32
|
+
const nativeOverlayDiagnostics = createConsoleOverlayDiagnostics("NativeOverlayManager");
|
|
33
|
+
const createNativeOverlayManager = () => {
|
|
34
|
+
let stack = [];
|
|
35
|
+
const dismissHandlers = /* @__PURE__ */ new Map();
|
|
36
|
+
const outsidePressHandlers = /* @__PURE__ */ new Map();
|
|
123
37
|
return {
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
38
|
+
register(id) {
|
|
39
|
+
if (stack.some((item) => item.id === id)) nativeOverlayDiagnostics.duplicateRegistration?.(id);
|
|
40
|
+
stack = stack.filter((item) => item.id !== id);
|
|
41
|
+
const entry = {
|
|
42
|
+
id,
|
|
43
|
+
zIndex: resolveOverlayZIndex({
|
|
44
|
+
level: nativeOverlayZIndexPolicy.defaultLevel,
|
|
45
|
+
order: stack.length,
|
|
46
|
+
policy: nativeOverlayZIndexPolicy
|
|
47
|
+
})
|
|
48
|
+
};
|
|
49
|
+
stack.push(entry);
|
|
50
|
+
return entry;
|
|
136
51
|
},
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
}
|
|
158
|
-
}));
|
|
159
|
-
return;
|
|
160
|
-
}
|
|
161
|
-
triggerNode.measureInWindow((x, y, width, height) => {
|
|
162
|
-
const commitPosition = (containerX, containerY, containerWidth, containerHeight) => {
|
|
163
|
-
const nextResult = computeFloatingPosition({
|
|
164
|
-
reference: {
|
|
165
|
-
x: x - containerX,
|
|
166
|
-
y: y - containerY,
|
|
167
|
-
width,
|
|
168
|
-
height
|
|
169
|
-
},
|
|
170
|
-
floating: measuredSize,
|
|
171
|
-
boundary: {
|
|
172
|
-
width: containerWidth,
|
|
173
|
-
height: containerHeight
|
|
174
|
-
},
|
|
175
|
-
placement,
|
|
176
|
-
offset
|
|
177
|
-
});
|
|
178
|
-
setResult(nextResult);
|
|
52
|
+
unregister(id) {
|
|
53
|
+
if (!stack.some((item) => item.id === id)) nativeOverlayDiagnostics.unknownUnregister?.(id);
|
|
54
|
+
dismissHandlers.delete(id);
|
|
55
|
+
outsidePressHandlers.delete(id);
|
|
56
|
+
stack = stack.filter((item) => item.id !== id);
|
|
57
|
+
},
|
|
58
|
+
isTop(id) {
|
|
59
|
+
return stack.at(-1)?.id === id;
|
|
60
|
+
},
|
|
61
|
+
getTop() {
|
|
62
|
+
return stack.at(-1);
|
|
63
|
+
},
|
|
64
|
+
getZIndex(id) {
|
|
65
|
+
return stack.find((item) => item.id === id)?.zIndex ?? nativeOverlayZIndexPolicy.levels[nativeOverlayZIndexPolicy.defaultLevel];
|
|
66
|
+
},
|
|
67
|
+
registerDismissHandler(id, handler) {
|
|
68
|
+
dismissHandlers.set(id, handler);
|
|
69
|
+
return () => {
|
|
70
|
+
if (dismissHandlers.get(id) !== handler) return;
|
|
71
|
+
dismissHandlers.delete(id);
|
|
179
72
|
};
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
73
|
+
},
|
|
74
|
+
registerOutsidePressHandler(id, handler) {
|
|
75
|
+
outsidePressHandlers.set(id, handler);
|
|
76
|
+
return () => {
|
|
77
|
+
if (outsidePressHandlers.get(id) !== handler) return;
|
|
78
|
+
outsidePressHandlers.delete(id);
|
|
79
|
+
};
|
|
80
|
+
},
|
|
81
|
+
dispatchTopDismiss() {
|
|
82
|
+
const top = this.getTop();
|
|
83
|
+
if (!top) return false;
|
|
84
|
+
const handler = dismissHandlers.get(top.id);
|
|
85
|
+
if (!handler) return false;
|
|
86
|
+
return handler();
|
|
87
|
+
},
|
|
88
|
+
dispatchTopOutsidePress() {
|
|
89
|
+
const top = this.getTop();
|
|
90
|
+
if (!top) return false;
|
|
91
|
+
const handler = outsidePressHandlers.get(top.id);
|
|
92
|
+
if (!handler) return false;
|
|
93
|
+
return handler();
|
|
94
|
+
},
|
|
95
|
+
clear() {
|
|
96
|
+
stack = [];
|
|
97
|
+
dismissHandlers.clear();
|
|
98
|
+
outsidePressHandlers.clear();
|
|
99
|
+
}
|
|
205
100
|
};
|
|
206
|
-
}
|
|
207
|
-
//#endregion
|
|
208
|
-
//#region src/managers/OverlayManager/NativeOverlayManager.ts
|
|
209
|
-
const BASE_LAYER = 1e3;
|
|
210
|
-
const LAYER_STEP = 10;
|
|
211
|
-
let stack = [];
|
|
212
|
-
const nativeOverlayManager = {
|
|
213
|
-
register(id) {
|
|
214
|
-
stack = stack.filter((item) => item.id !== id);
|
|
215
|
-
const entry = {
|
|
216
|
-
id,
|
|
217
|
-
layer: BASE_LAYER + stack.length * LAYER_STEP
|
|
218
|
-
};
|
|
219
|
-
stack.push(entry);
|
|
220
|
-
return entry;
|
|
221
|
-
},
|
|
222
|
-
unregister(id) {
|
|
223
|
-
stack = stack.filter((item) => item.id !== id);
|
|
224
|
-
},
|
|
225
|
-
isTop(id) {
|
|
226
|
-
return stack.at(-1)?.id === id;
|
|
227
|
-
},
|
|
228
|
-
getTop() {
|
|
229
|
-
return stack.at(-1);
|
|
230
|
-
},
|
|
231
|
-
getLayer(id) {
|
|
232
|
-
return stack.find((item) => item.id === id)?.layer ?? BASE_LAYER;
|
|
233
|
-
}
|
|
234
101
|
};
|
|
102
|
+
const nativeOverlayManager = createNativeOverlayManager();
|
|
235
103
|
//#endregion
|
|
236
|
-
//#region src/managers/OverlayManager/
|
|
237
|
-
const
|
|
238
|
-
|
|
104
|
+
//#region src/managers/OverlayManager/OverlayManagerProvider.tsx
|
|
105
|
+
const NativeOverlayManagerContext = createContext(null);
|
|
106
|
+
const useNativeOverlayManager = () => useContext(NativeOverlayManagerContext) ?? nativeOverlayManager;
|
|
107
|
+
//#endregion
|
|
108
|
+
//#region src/hooks/behavior/overlay/useOverlayRegistration.ts
|
|
109
|
+
const useOverlayRegistration = ({ active, id }) => {
|
|
110
|
+
const nativeOverlayManager = useNativeOverlayManager();
|
|
111
|
+
const [zIndex, setZIndex] = useState(() => nativeOverlayManager.getZIndex(id));
|
|
239
112
|
useEffect(() => {
|
|
240
|
-
if (!
|
|
113
|
+
if (!active) return;
|
|
241
114
|
const entry = nativeOverlayManager.register(id);
|
|
242
|
-
|
|
115
|
+
setZIndex(entry.zIndex);
|
|
243
116
|
return () => {
|
|
244
117
|
nativeOverlayManager.unregister(id);
|
|
245
118
|
};
|
|
246
|
-
}, [
|
|
119
|
+
}, [
|
|
120
|
+
active,
|
|
121
|
+
id,
|
|
122
|
+
nativeOverlayManager
|
|
123
|
+
]);
|
|
247
124
|
return {
|
|
248
|
-
|
|
249
|
-
isTopOverlay: useCallback(() => nativeOverlayManager.isTop(id), [id])
|
|
125
|
+
zIndex,
|
|
126
|
+
isTopOverlay: useCallback(() => nativeOverlayManager.isTop(id), [id, nativeOverlayManager])
|
|
250
127
|
};
|
|
251
128
|
};
|
|
252
129
|
//#endregion
|
|
253
|
-
//#region src/hooks/behavior/overlay/useOverlayStack.ts
|
|
254
|
-
const useOverlayStack = ({ active, id }) => useNativeOverlayRegistration({
|
|
255
|
-
id,
|
|
256
|
-
visible: active
|
|
257
|
-
});
|
|
258
|
-
//#endregion
|
|
259
130
|
//#region src/hooks/behavior/overlay/useOverlayDismiss.ts
|
|
260
|
-
const
|
|
261
|
-
|
|
131
|
+
const dismissListeners = /* @__PURE__ */ new Map();
|
|
132
|
+
function attachDismissListener(manager) {
|
|
133
|
+
if (dismissListeners.has(manager)) return;
|
|
134
|
+
if (Platform.OS === "web") {
|
|
135
|
+
const handleKeyDown = (event) => {
|
|
136
|
+
if (event.key !== "Escape") return;
|
|
137
|
+
manager.dispatchTopDismiss();
|
|
138
|
+
};
|
|
139
|
+
document.addEventListener("keydown", handleKeyDown);
|
|
140
|
+
dismissListeners.set(manager, {
|
|
141
|
+
count: 0,
|
|
142
|
+
detach: () => {
|
|
143
|
+
document.removeEventListener("keydown", handleKeyDown);
|
|
144
|
+
dismissListeners.delete(manager);
|
|
145
|
+
}
|
|
146
|
+
});
|
|
147
|
+
return;
|
|
148
|
+
}
|
|
149
|
+
const subscription = BackHandler.addEventListener("hardwareBackPress", () => manager.dispatchTopDismiss());
|
|
150
|
+
dismissListeners.set(manager, {
|
|
151
|
+
count: 0,
|
|
152
|
+
detach: () => {
|
|
153
|
+
subscription.remove();
|
|
154
|
+
dismissListeners.delete(manager);
|
|
155
|
+
}
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
function retainDismissListener(manager) {
|
|
159
|
+
attachDismissListener(manager);
|
|
160
|
+
const retained = dismissListeners.get(manager);
|
|
161
|
+
if (!retained) return () => void 0;
|
|
162
|
+
retained.count += 1;
|
|
163
|
+
return () => {
|
|
164
|
+
const current = dismissListeners.get(manager);
|
|
165
|
+
if (!current) return;
|
|
166
|
+
current.count = Math.max(0, current.count - 1);
|
|
167
|
+
if (current.count > 0) return;
|
|
168
|
+
current.detach();
|
|
169
|
+
};
|
|
170
|
+
}
|
|
171
|
+
const useOverlayDismiss = ({ active, closeOnEscape = true, closeOnOutsidePress = true, id, requestClose, requestOutsideClose }) => {
|
|
172
|
+
const nativeOverlayManager = useNativeOverlayManager();
|
|
173
|
+
const registration = useOverlayRegistration({
|
|
262
174
|
active,
|
|
263
175
|
id
|
|
264
176
|
});
|
|
177
|
+
const { isTopOverlay } = registration;
|
|
265
178
|
const requestTopClose = useCallback(() => {
|
|
266
179
|
if (!isTopOverlay()) return;
|
|
267
180
|
requestClose();
|
|
268
181
|
}, [isTopOverlay, requestClose]);
|
|
269
|
-
const
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
}, [closeOnOutsidePress, requestTopClose]);
|
|
182
|
+
const requestOutsideTopClose = useCallback(() => {
|
|
183
|
+
nativeOverlayManager.dispatchTopOutsidePress();
|
|
184
|
+
}, [nativeOverlayManager]);
|
|
273
185
|
useEffect(() => {
|
|
274
|
-
if (!active
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
if (event.key !== "Escape") return;
|
|
278
|
-
requestTopClose();
|
|
279
|
-
};
|
|
280
|
-
document.addEventListener("keydown", handleKeyDown);
|
|
281
|
-
return () => {
|
|
282
|
-
document.removeEventListener("keydown", handleKeyDown);
|
|
283
|
-
};
|
|
284
|
-
}
|
|
285
|
-
const subscription = BackHandler.addEventListener("hardwareBackPress", () => {
|
|
186
|
+
if (!active) return;
|
|
187
|
+
return nativeOverlayManager.registerOutsidePressHandler(id, () => {
|
|
188
|
+
if (!closeOnOutsidePress) return false;
|
|
286
189
|
if (!isTopOverlay()) return false;
|
|
190
|
+
if (requestOutsideClose) {
|
|
191
|
+
requestOutsideClose();
|
|
192
|
+
return true;
|
|
193
|
+
}
|
|
287
194
|
requestClose();
|
|
288
195
|
return true;
|
|
289
196
|
});
|
|
197
|
+
}, [
|
|
198
|
+
active,
|
|
199
|
+
closeOnOutsidePress,
|
|
200
|
+
id,
|
|
201
|
+
isTopOverlay,
|
|
202
|
+
nativeOverlayManager,
|
|
203
|
+
requestClose,
|
|
204
|
+
requestOutsideClose
|
|
205
|
+
]);
|
|
206
|
+
useEffect(() => {
|
|
207
|
+
if (!active) return;
|
|
208
|
+
const releaseDismissListener = retainDismissListener(nativeOverlayManager);
|
|
209
|
+
const unregisterDismissHandler = nativeOverlayManager.registerDismissHandler(id, () => {
|
|
210
|
+
if (!closeOnEscape) return false;
|
|
211
|
+
requestTopClose();
|
|
212
|
+
return true;
|
|
213
|
+
});
|
|
290
214
|
return () => {
|
|
291
|
-
|
|
215
|
+
unregisterDismissHandler();
|
|
216
|
+
releaseDismissListener();
|
|
292
217
|
};
|
|
293
218
|
}, [
|
|
294
219
|
active,
|
|
295
220
|
closeOnEscape,
|
|
296
|
-
|
|
297
|
-
|
|
221
|
+
id,
|
|
222
|
+
nativeOverlayManager,
|
|
298
223
|
requestTopClose
|
|
299
224
|
]);
|
|
300
225
|
return {
|
|
226
|
+
zIndex: registration.zIndex,
|
|
301
227
|
isTopOverlay,
|
|
302
228
|
requestClose: requestTopClose,
|
|
303
|
-
requestOutsideClose
|
|
229
|
+
requestOutsideClose: requestOutsideTopClose
|
|
304
230
|
};
|
|
305
231
|
};
|
|
306
232
|
//#endregion
|
|
307
233
|
//#region src/hooks/behavior/overlay/useOverlayFocusRestore.ts
|
|
308
|
-
|
|
234
|
+
function isFocusableWebNode(node) {
|
|
235
|
+
return typeof node === "object" && node !== null && "focus" in node && typeof node.focus === "function";
|
|
236
|
+
}
|
|
237
|
+
const useOverlayFocusRestore = ({ active = false, enabled = true, finalFocus, triggerRef }) => {
|
|
238
|
+
const previouslyFocusedRef = useRef(null);
|
|
239
|
+
const saveFocusSnapshot = useCallback(() => {
|
|
240
|
+
if (Platform.OS !== "web" || typeof document === "undefined") return;
|
|
241
|
+
previouslyFocusedRef.current = document.activeElement;
|
|
242
|
+
}, []);
|
|
309
243
|
const restoreFocus = useCallback(() => {
|
|
310
244
|
if (!enabled) return;
|
|
311
245
|
if (Platform.OS === "web") {
|
|
312
|
-
const
|
|
313
|
-
if (
|
|
246
|
+
const preferredNode = finalFocus?.current ?? triggerRef.current;
|
|
247
|
+
if (isFocusableWebNode(preferredNode)) {
|
|
248
|
+
preferredNode.focus();
|
|
249
|
+
return;
|
|
250
|
+
}
|
|
251
|
+
const previouslyFocused = previouslyFocusedRef.current;
|
|
252
|
+
if (previouslyFocused instanceof HTMLElement && previouslyFocused.isConnected) previouslyFocused.focus();
|
|
314
253
|
return;
|
|
315
254
|
}
|
|
316
255
|
if (typeof findNodeHandle !== "function") return;
|
|
317
|
-
const handle = findNodeHandle(triggerRef.current);
|
|
256
|
+
const handle = findNodeHandle(finalFocus?.current ?? triggerRef.current);
|
|
318
257
|
if (handle && AccessibilityInfo.setAccessibilityFocus) AccessibilityInfo.setAccessibilityFocus(handle);
|
|
319
|
-
}, [
|
|
258
|
+
}, [
|
|
259
|
+
enabled,
|
|
260
|
+
finalFocus,
|
|
261
|
+
triggerRef
|
|
262
|
+
]);
|
|
263
|
+
const restoreFocusAfterClose = useCallback(() => {
|
|
264
|
+
if (!enabled) return;
|
|
265
|
+
requestAnimationFrame(restoreFocus);
|
|
266
|
+
}, [enabled, restoreFocus]);
|
|
267
|
+
useEffect(() => {
|
|
268
|
+
if (!active) return;
|
|
269
|
+
saveFocusSnapshot();
|
|
270
|
+
}, [active, saveFocusSnapshot]);
|
|
320
271
|
return {
|
|
321
272
|
restoreFocus,
|
|
322
|
-
restoreFocusAfterClose
|
|
323
|
-
|
|
324
|
-
requestAnimationFrame(restoreFocus);
|
|
325
|
-
}, [enabled, restoreFocus])
|
|
273
|
+
restoreFocusAfterClose,
|
|
274
|
+
saveFocusSnapshot
|
|
326
275
|
};
|
|
327
276
|
};
|
|
328
277
|
//#endregion
|
|
@@ -764,6 +713,16 @@ function useThemeStyles(createStyles) {
|
|
|
764
713
|
return useMemo(() => createStyles(theme), [createStyles, theme]);
|
|
765
714
|
}
|
|
766
715
|
//#endregion
|
|
716
|
+
//#region src/components/Dropdown/internal/DropdownContext.tsx
|
|
717
|
+
const DropdownContext = createContext(null);
|
|
718
|
+
const DropdownProvider = DropdownContext.Provider;
|
|
719
|
+
const useDropdownContext = () => {
|
|
720
|
+
const context = useContext(DropdownContext);
|
|
721
|
+
if (!context) throw new Error("Dropdown components must be used inside Dropdown");
|
|
722
|
+
return context;
|
|
723
|
+
};
|
|
724
|
+
DropdownContext.displayName = "DropdownContext";
|
|
725
|
+
//#endregion
|
|
767
726
|
//#region src/components/Dropdown/Content/DropdownContent.styles.ts
|
|
768
727
|
const createStyles$21 = (theme) => StyleSheet.create({
|
|
769
728
|
modalRoot: { flex: 1 },
|
|
@@ -848,13 +807,14 @@ const createStyles$21 = (theme) => StyleSheet.create({
|
|
|
848
807
|
//#region src/components/Dropdown/Content/DropdownContent.tsx
|
|
849
808
|
const nativePointerEventsBoxNone$1 = Platform.OS === "web" ? void 0 : { pointerEvents: "box-none" };
|
|
850
809
|
const webPointerEventsBoxNone$1 = Platform.OS === "web" ? { pointerEvents: "box-none" } : void 0;
|
|
851
|
-
function DropdownContent({
|
|
810
|
+
function DropdownContent({ children, contentStyle, accessibilityLabel }) {
|
|
811
|
+
const { open, color, presentation, zIndex, position, searchable, searchValue, searchPlaceholder, searchAccessibilityLabel, requestClose, requestOutsideClose, onSearchChange, onFloatingLayout } = useDropdownContext();
|
|
852
812
|
const { theme } = useTheme();
|
|
853
813
|
const styles = useThemeStyles(createStyles$21);
|
|
854
814
|
const colorPalette = theme.components.dropdown[color];
|
|
855
815
|
const isSheet = presentation === "sheet";
|
|
856
816
|
const isPopover = presentation === "popover";
|
|
857
|
-
const animation = useRef(new Animated.Value(
|
|
817
|
+
const animation = useRef(new Animated.Value(open ? 1 : 0)).current;
|
|
858
818
|
const [reduceMotion, setReduceMotion] = useState(false);
|
|
859
819
|
useEffect(() => {
|
|
860
820
|
AccessibilityInfo.isReduceMotionEnabled?.().then(setReduceMotion);
|
|
@@ -864,7 +824,7 @@ function DropdownContent({ isOpen, children, onClose, color = "primary", content
|
|
|
864
824
|
};
|
|
865
825
|
}, []);
|
|
866
826
|
useEffect(() => {
|
|
867
|
-
if (!
|
|
827
|
+
if (!open) {
|
|
868
828
|
animation.setValue(0);
|
|
869
829
|
return;
|
|
870
830
|
}
|
|
@@ -880,7 +840,7 @@ function DropdownContent({ isOpen, children, onClose, color = "primary", content
|
|
|
880
840
|
}).start();
|
|
881
841
|
}, [
|
|
882
842
|
animation,
|
|
883
|
-
|
|
843
|
+
open,
|
|
884
844
|
isSheet,
|
|
885
845
|
reduceMotion
|
|
886
846
|
]);
|
|
@@ -904,11 +864,15 @@ function DropdownContent({ isOpen, children, onClose, color = "primary", content
|
|
|
904
864
|
}, [animation, isSheet]);
|
|
905
865
|
return /* @__PURE__ */ jsx(Modal$1, {
|
|
906
866
|
transparent: true,
|
|
907
|
-
visible:
|
|
867
|
+
visible: open,
|
|
908
868
|
animationType: "none",
|
|
909
|
-
onRequestClose:
|
|
869
|
+
onRequestClose: requestClose,
|
|
910
870
|
children: /* @__PURE__ */ jsxs(View, {
|
|
911
|
-
style: [
|
|
871
|
+
style: [
|
|
872
|
+
styles.modalRoot,
|
|
873
|
+
styles[presentation],
|
|
874
|
+
Platform.OS === "web" && { zIndex }
|
|
875
|
+
],
|
|
912
876
|
children: [/* @__PURE__ */ jsx(Animated.View, {
|
|
913
877
|
...nativePointerEventsBoxNone$1,
|
|
914
878
|
style: [
|
|
@@ -920,7 +884,7 @@ function DropdownContent({ isOpen, children, onClose, color = "primary", content
|
|
|
920
884
|
accessibilityRole: "button",
|
|
921
885
|
accessibilityLabel: "Close menu",
|
|
922
886
|
style: StyleSheet.absoluteFill,
|
|
923
|
-
onPress:
|
|
887
|
+
onPress: requestOutsideClose
|
|
924
888
|
})
|
|
925
889
|
}), /* @__PURE__ */ jsxs(Animated.View, {
|
|
926
890
|
accessibilityRole: "menu",
|
|
@@ -1068,6 +1032,279 @@ function getItemLabel(children) {
|
|
|
1068
1032
|
return labelParts.join("").trim();
|
|
1069
1033
|
}
|
|
1070
1034
|
//#endregion
|
|
1035
|
+
//#region src/hooks/behavior/dropdown/useDropdownAccessibility.ts
|
|
1036
|
+
const useDropdownAccessibility = ({ accessibilityLabel, label, open }) => {
|
|
1037
|
+
const menuAccessibilityLabel = useMemo(() => {
|
|
1038
|
+
if (accessibilityLabel) return accessibilityLabel;
|
|
1039
|
+
return typeof label === "string" ? label : "Menu";
|
|
1040
|
+
}, [accessibilityLabel, label]);
|
|
1041
|
+
useEffect(() => {
|
|
1042
|
+
if (!open) return;
|
|
1043
|
+
AccessibilityInfo.announceForAccessibility(`${menuAccessibilityLabel} opened`);
|
|
1044
|
+
}, [menuAccessibilityLabel, open]);
|
|
1045
|
+
return { menuAccessibilityLabel };
|
|
1046
|
+
};
|
|
1047
|
+
//#endregion
|
|
1048
|
+
//#region src/hooks/behavior/dropdown/useDropdownEntries.ts
|
|
1049
|
+
const useDropdownEntries = ({ parsed, filteredParsed, loading, loadingText, isSearchable, empty }) => {
|
|
1050
|
+
return {
|
|
1051
|
+
navigableItems: useMemo(() => parsed.items.map((item) => ({
|
|
1052
|
+
disabled: item.disabled,
|
|
1053
|
+
label: item.label,
|
|
1054
|
+
value: item.id
|
|
1055
|
+
})), [parsed.items]),
|
|
1056
|
+
data: useMemo(() => {
|
|
1057
|
+
if (loading) return [{
|
|
1058
|
+
type: "loading",
|
|
1059
|
+
id: "loading",
|
|
1060
|
+
props: { children: loadingText }
|
|
1061
|
+
}];
|
|
1062
|
+
if (isSearchable && filteredParsed.items.length === 0) return [{
|
|
1063
|
+
type: "empty",
|
|
1064
|
+
id: "empty",
|
|
1065
|
+
props: { children: empty ?? "No actions found" }
|
|
1066
|
+
}];
|
|
1067
|
+
return filteredParsed.entries;
|
|
1068
|
+
}, [
|
|
1069
|
+
empty,
|
|
1070
|
+
filteredParsed.entries,
|
|
1071
|
+
filteredParsed.items.length,
|
|
1072
|
+
isSearchable,
|
|
1073
|
+
loading,
|
|
1074
|
+
loadingText
|
|
1075
|
+
])
|
|
1076
|
+
};
|
|
1077
|
+
};
|
|
1078
|
+
//#endregion
|
|
1079
|
+
//#region src/components/Dropdown/internal/DropdownUtils.ts
|
|
1080
|
+
function createDropdownSelectEvent() {
|
|
1081
|
+
let defaultPrevented = false;
|
|
1082
|
+
return {
|
|
1083
|
+
preventDefault: () => {
|
|
1084
|
+
defaultPrevented = true;
|
|
1085
|
+
},
|
|
1086
|
+
get defaultPrevented() {
|
|
1087
|
+
return defaultPrevented;
|
|
1088
|
+
}
|
|
1089
|
+
};
|
|
1090
|
+
}
|
|
1091
|
+
function filterDropdownEntries(parsed, searchValue) {
|
|
1092
|
+
const normalizedSearch = searchValue.trim().toLocaleLowerCase();
|
|
1093
|
+
const matchedItems = new Set(parsed.items.filter((item) => item.label.toLocaleLowerCase().includes(normalizedSearch)).map((item) => item.id));
|
|
1094
|
+
return {
|
|
1095
|
+
...parsed,
|
|
1096
|
+
items: parsed.items.filter((item) => matchedItems.has(item.id)),
|
|
1097
|
+
entries: parsed.entries.filter((entry) => entry.type !== "item" || matchedItems.has(entry.id))
|
|
1098
|
+
};
|
|
1099
|
+
}
|
|
1100
|
+
//#endregion
|
|
1101
|
+
//#region src/hooks/behavior/dropdown/useDropdownSearch.ts
|
|
1102
|
+
const useDropdownSearch = ({ parsed, searchable, command, searchValue, defaultSearchValue, onSearch }) => {
|
|
1103
|
+
const [uncontrolledSearchValue, setUncontrolledSearchValue] = useState(defaultSearchValue);
|
|
1104
|
+
const resolvedSearchValue = searchValue ?? uncontrolledSearchValue;
|
|
1105
|
+
const contentCommand = parsed.contentProps?.command ?? false;
|
|
1106
|
+
const isSearchable = searchable || command || contentCommand || Boolean(parsed.searchProps);
|
|
1107
|
+
return {
|
|
1108
|
+
contentCommand,
|
|
1109
|
+
filteredParsed: useMemo(() => {
|
|
1110
|
+
if (!isSearchable || !resolvedSearchValue.trim()) return parsed;
|
|
1111
|
+
return filterDropdownEntries(parsed, resolvedSearchValue);
|
|
1112
|
+
}, [
|
|
1113
|
+
isSearchable,
|
|
1114
|
+
parsed,
|
|
1115
|
+
resolvedSearchValue
|
|
1116
|
+
]),
|
|
1117
|
+
handleSearchChange: useCallback((value) => {
|
|
1118
|
+
if (searchValue === void 0) setUncontrolledSearchValue(value);
|
|
1119
|
+
onSearch?.(value);
|
|
1120
|
+
}, [onSearch, searchValue]),
|
|
1121
|
+
isSearchable,
|
|
1122
|
+
resolvedSearchValue
|
|
1123
|
+
};
|
|
1124
|
+
};
|
|
1125
|
+
//#endregion
|
|
1126
|
+
//#region src/managers/FloatingManager/computeFloatingPosition.ts
|
|
1127
|
+
function clamp(value, min, max) {
|
|
1128
|
+
return Math.min(Math.max(value, min), Math.max(min, max));
|
|
1129
|
+
}
|
|
1130
|
+
function parsePlacement(placement) {
|
|
1131
|
+
const [side, align = "center"] = placement.split("-");
|
|
1132
|
+
return {
|
|
1133
|
+
side,
|
|
1134
|
+
align
|
|
1135
|
+
};
|
|
1136
|
+
}
|
|
1137
|
+
function createPlacement(side, align) {
|
|
1138
|
+
return align === "center" ? side : `${side}-${align}`;
|
|
1139
|
+
}
|
|
1140
|
+
function getOppositeSide(side) {
|
|
1141
|
+
switch (side) {
|
|
1142
|
+
case "top": return "bottom";
|
|
1143
|
+
case "right": return "left";
|
|
1144
|
+
case "bottom": return "top";
|
|
1145
|
+
case "left": return "right";
|
|
1146
|
+
}
|
|
1147
|
+
}
|
|
1148
|
+
function computeBasePosition({ reference, floating, side, align, offset }) {
|
|
1149
|
+
const referenceCenterX = reference.x + reference.width / 2;
|
|
1150
|
+
const referenceCenterY = reference.y + reference.height / 2;
|
|
1151
|
+
const alignedLeft = align === "start" ? reference.x : align === "end" ? reference.x + reference.width - floating.width : referenceCenterX - floating.width / 2;
|
|
1152
|
+
const alignedTop = align === "start" ? reference.y : align === "end" ? reference.y + reference.height - floating.height : referenceCenterY - floating.height / 2;
|
|
1153
|
+
switch (side) {
|
|
1154
|
+
case "top": return {
|
|
1155
|
+
top: reference.y - floating.height - offset,
|
|
1156
|
+
left: alignedLeft
|
|
1157
|
+
};
|
|
1158
|
+
case "right": return {
|
|
1159
|
+
top: alignedTop,
|
|
1160
|
+
left: reference.x + reference.width + offset
|
|
1161
|
+
};
|
|
1162
|
+
case "bottom": return {
|
|
1163
|
+
top: reference.y + reference.height + offset,
|
|
1164
|
+
left: alignedLeft
|
|
1165
|
+
};
|
|
1166
|
+
case "left": return {
|
|
1167
|
+
top: alignedTop,
|
|
1168
|
+
left: reference.x - floating.width - offset
|
|
1169
|
+
};
|
|
1170
|
+
}
|
|
1171
|
+
}
|
|
1172
|
+
function getMainAxisOverflow({ side, position, floating, boundary, padding }) {
|
|
1173
|
+
switch (side) {
|
|
1174
|
+
case "top": return padding - position.top;
|
|
1175
|
+
case "right": return position.left + floating.width + padding - boundary.width;
|
|
1176
|
+
case "bottom": return position.top + floating.height + padding - boundary.height;
|
|
1177
|
+
case "left": return padding - position.left;
|
|
1178
|
+
}
|
|
1179
|
+
}
|
|
1180
|
+
function computeFloatingPosition({ reference, floating, boundary, placement, offset = 8, padding = 12, arrowPadding = 16, flip = true, shift = true }) {
|
|
1181
|
+
const parsed = parsePlacement(placement);
|
|
1182
|
+
let resolvedSide = parsed.side;
|
|
1183
|
+
let position = computeBasePosition({
|
|
1184
|
+
reference,
|
|
1185
|
+
floating,
|
|
1186
|
+
side: resolvedSide,
|
|
1187
|
+
align: parsed.align,
|
|
1188
|
+
offset
|
|
1189
|
+
});
|
|
1190
|
+
if (flip && getMainAxisOverflow({
|
|
1191
|
+
side: resolvedSide,
|
|
1192
|
+
position,
|
|
1193
|
+
floating,
|
|
1194
|
+
boundary,
|
|
1195
|
+
padding
|
|
1196
|
+
}) > 0) {
|
|
1197
|
+
const oppositeSide = getOppositeSide(resolvedSide);
|
|
1198
|
+
const oppositePosition = computeBasePosition({
|
|
1199
|
+
reference,
|
|
1200
|
+
floating,
|
|
1201
|
+
side: oppositeSide,
|
|
1202
|
+
align: parsed.align,
|
|
1203
|
+
offset
|
|
1204
|
+
});
|
|
1205
|
+
if (getMainAxisOverflow({
|
|
1206
|
+
side: oppositeSide,
|
|
1207
|
+
position: oppositePosition,
|
|
1208
|
+
floating,
|
|
1209
|
+
boundary,
|
|
1210
|
+
padding
|
|
1211
|
+
}) <= 0) {
|
|
1212
|
+
resolvedSide = oppositeSide;
|
|
1213
|
+
position = oppositePosition;
|
|
1214
|
+
}
|
|
1215
|
+
}
|
|
1216
|
+
if (shift) position = {
|
|
1217
|
+
top: clamp(position.top, padding, boundary.height - floating.height - padding),
|
|
1218
|
+
left: clamp(position.left, padding, boundary.width - floating.width - padding)
|
|
1219
|
+
};
|
|
1220
|
+
const referenceCenterX = reference.x + reference.width / 2;
|
|
1221
|
+
const referenceCenterY = reference.y + reference.height / 2;
|
|
1222
|
+
const arrowPosition = resolvedSide === "top" || resolvedSide === "bottom" ? { left: clamp(referenceCenterX - position.left, arrowPadding, floating.width - arrowPadding) } : { top: clamp(referenceCenterY - position.top, arrowPadding, floating.height - arrowPadding) };
|
|
1223
|
+
return {
|
|
1224
|
+
position,
|
|
1225
|
+
arrowPosition,
|
|
1226
|
+
placement: createPlacement(resolvedSide, parsed.align)
|
|
1227
|
+
};
|
|
1228
|
+
}
|
|
1229
|
+
//#endregion
|
|
1230
|
+
//#region src/managers/FloatingManager/useNativeFloatingPosition.ts
|
|
1231
|
+
function useNativeFloatingPosition(placement = "top", offset = 8) {
|
|
1232
|
+
const [result, setResult] = useState({
|
|
1233
|
+
position: {
|
|
1234
|
+
top: 0,
|
|
1235
|
+
left: 0
|
|
1236
|
+
},
|
|
1237
|
+
arrowPosition: {},
|
|
1238
|
+
placement
|
|
1239
|
+
});
|
|
1240
|
+
const floatingSizeRef = useRef({
|
|
1241
|
+
width: 0,
|
|
1242
|
+
height: 0
|
|
1243
|
+
});
|
|
1244
|
+
const lastTriggerRef = useRef(null);
|
|
1245
|
+
const lastContainerRef = useRef(null);
|
|
1246
|
+
const updatePosition = useCallback((triggerRef, containerRef, measuredSize = floatingSizeRef.current) => {
|
|
1247
|
+
lastTriggerRef.current = triggerRef;
|
|
1248
|
+
lastContainerRef.current = containerRef ?? null;
|
|
1249
|
+
const triggerNode = triggerRef.current;
|
|
1250
|
+
const containerNode = containerRef?.current;
|
|
1251
|
+
if (!triggerNode || typeof triggerNode.measureInWindow !== "function") {
|
|
1252
|
+
setResult((current) => ({
|
|
1253
|
+
...current,
|
|
1254
|
+
position: {
|
|
1255
|
+
top: 0,
|
|
1256
|
+
left: 0
|
|
1257
|
+
}
|
|
1258
|
+
}));
|
|
1259
|
+
return;
|
|
1260
|
+
}
|
|
1261
|
+
triggerNode.measureInWindow((x, y, width, height) => {
|
|
1262
|
+
const commitPosition = (containerX, containerY, containerWidth, containerHeight) => {
|
|
1263
|
+
const nextResult = computeFloatingPosition({
|
|
1264
|
+
reference: {
|
|
1265
|
+
x: x - containerX,
|
|
1266
|
+
y: y - containerY,
|
|
1267
|
+
width,
|
|
1268
|
+
height
|
|
1269
|
+
},
|
|
1270
|
+
floating: measuredSize,
|
|
1271
|
+
boundary: {
|
|
1272
|
+
width: containerWidth,
|
|
1273
|
+
height: containerHeight
|
|
1274
|
+
},
|
|
1275
|
+
placement,
|
|
1276
|
+
offset
|
|
1277
|
+
});
|
|
1278
|
+
setResult(nextResult);
|
|
1279
|
+
};
|
|
1280
|
+
if (!containerNode || typeof containerNode.measureInWindow !== "function") {
|
|
1281
|
+
const window = Dimensions.get("window");
|
|
1282
|
+
commitPosition(0, 0, window.width, window.height);
|
|
1283
|
+
return;
|
|
1284
|
+
}
|
|
1285
|
+
containerNode.measureInWindow((containerX, containerY, containerWidth, containerHeight) => {
|
|
1286
|
+
commitPosition(containerX, containerY, containerWidth, containerHeight);
|
|
1287
|
+
});
|
|
1288
|
+
});
|
|
1289
|
+
}, [placement, offset]);
|
|
1290
|
+
const onFloatingLayout = useCallback((event) => {
|
|
1291
|
+
const { width, height } = event.nativeEvent.layout;
|
|
1292
|
+
const nextSize = {
|
|
1293
|
+
width,
|
|
1294
|
+
height
|
|
1295
|
+
};
|
|
1296
|
+
floatingSizeRef.current = nextSize;
|
|
1297
|
+
if (lastTriggerRef.current) updatePosition(lastTriggerRef.current, lastContainerRef.current ?? void 0, nextSize);
|
|
1298
|
+
}, [updatePosition]);
|
|
1299
|
+
return {
|
|
1300
|
+
position: result.position,
|
|
1301
|
+
arrowPosition: result.arrowPosition,
|
|
1302
|
+
placement: result.placement,
|
|
1303
|
+
updatePosition,
|
|
1304
|
+
onFloatingLayout
|
|
1305
|
+
};
|
|
1306
|
+
}
|
|
1307
|
+
//#endregion
|
|
1071
1308
|
//#region src/components/Dropdown/Dropdown.styles.ts
|
|
1072
1309
|
const createStyles$20 = (theme) => StyleSheet.create({
|
|
1073
1310
|
root: { alignSelf: "flex-start" },
|
|
@@ -1103,28 +1340,6 @@ function DropdownGroup({ label }) {
|
|
|
1103
1340
|
}
|
|
1104
1341
|
DropdownGroup.displayName = "DropdownGroup";
|
|
1105
1342
|
//#endregion
|
|
1106
|
-
//#region src/components/Dropdown/internal/DropdownUtils.ts
|
|
1107
|
-
function createDropdownSelectEvent() {
|
|
1108
|
-
let defaultPrevented = false;
|
|
1109
|
-
return {
|
|
1110
|
-
preventDefault: () => {
|
|
1111
|
-
defaultPrevented = true;
|
|
1112
|
-
},
|
|
1113
|
-
get defaultPrevented() {
|
|
1114
|
-
return defaultPrevented;
|
|
1115
|
-
}
|
|
1116
|
-
};
|
|
1117
|
-
}
|
|
1118
|
-
function filterDropdownEntries(parsed, searchValue) {
|
|
1119
|
-
const normalizedSearch = searchValue.trim().toLocaleLowerCase();
|
|
1120
|
-
const matchedItems = new Set(parsed.items.filter((item) => item.label.toLocaleLowerCase().includes(normalizedSearch)).map((item) => item.id));
|
|
1121
|
-
return {
|
|
1122
|
-
...parsed,
|
|
1123
|
-
items: parsed.items.filter((item) => matchedItems.has(item.id)),
|
|
1124
|
-
entries: parsed.entries.filter((entry) => entry.type !== "item" || matchedItems.has(entry.id))
|
|
1125
|
-
};
|
|
1126
|
-
}
|
|
1127
|
-
//#endregion
|
|
1128
1343
|
//#region src/components/Dropdown/Item/DropdownItem.styles.ts
|
|
1129
1344
|
const createStyles$18 = (theme) => StyleSheet.create({
|
|
1130
1345
|
item: {
|
|
@@ -1149,7 +1364,8 @@ const createStyles$18 = (theme) => StyleSheet.create({
|
|
|
1149
1364
|
});
|
|
1150
1365
|
//#endregion
|
|
1151
1366
|
//#region src/components/Dropdown/Item/DropdownItem.tsx
|
|
1152
|
-
function DropdownItem({ label, value,
|
|
1367
|
+
function DropdownItem({ label, value, color = "default", icon, disabled = false, textWrap = "truncate", onSelect }) {
|
|
1368
|
+
const { color: rootColor, itemStyle, textStyle } = useDropdownContext();
|
|
1153
1369
|
const { theme } = useTheme();
|
|
1154
1370
|
const styles = useThemeStyles(createStyles$18);
|
|
1155
1371
|
const rootColorPalette = theme.components.dropdown[rootColor];
|
|
@@ -1303,7 +1519,8 @@ const createStyles$16 = (theme) => StyleSheet.create({
|
|
|
1303
1519
|
});
|
|
1304
1520
|
//#endregion
|
|
1305
1521
|
//#region src/components/Dropdown/Trigger/DropdownTrigger.tsx
|
|
1306
|
-
function DropdownTrigger({ asChild = false, label, trigger, children, icon, arrowIcon, showArrow = true,
|
|
1522
|
+
function DropdownTrigger({ asChild = false, label, trigger, children, icon, arrowIcon, showArrow = true, triggerStyle, triggerRef, accessibilityLabel, accessibilityHint }) {
|
|
1523
|
+
const { open, color, disabled, size, toggle } = useDropdownContext();
|
|
1307
1524
|
const { theme } = useTheme();
|
|
1308
1525
|
const styles = useThemeStyles(createStyles$16);
|
|
1309
1526
|
const colorPalette = theme.components.dropdown[color];
|
|
@@ -1320,14 +1537,14 @@ function DropdownTrigger({ asChild = false, label, trigger, children, icon, arro
|
|
|
1320
1537
|
const hasIcon = Boolean(icon);
|
|
1321
1538
|
const isIconOnly = !trigger && hasIcon && !showArrow;
|
|
1322
1539
|
const [isPressed, setIsPressed] = useState(false);
|
|
1323
|
-
const rotateAnim = useRef(new Animated.Value(
|
|
1540
|
+
const rotateAnim = useRef(new Animated.Value(open ? 1 : 0)).current;
|
|
1324
1541
|
useEffect(() => {
|
|
1325
1542
|
Animated.timing(rotateAnim, {
|
|
1326
|
-
toValue:
|
|
1543
|
+
toValue: open ? 1 : 0,
|
|
1327
1544
|
duration: 180,
|
|
1328
1545
|
useNativeDriver: Platform.OS !== "web"
|
|
1329
1546
|
}).start();
|
|
1330
|
-
}, [
|
|
1547
|
+
}, [open, rotateAnim]);
|
|
1331
1548
|
const arrowRotate = rotateAnim.interpolate({
|
|
1332
1549
|
inputRange: [0, 1],
|
|
1333
1550
|
outputRange: ["0deg", "180deg"]
|
|
@@ -1363,12 +1580,12 @@ function DropdownTrigger({ asChild = false, label, trigger, children, icon, arro
|
|
|
1363
1580
|
accessibilityLabel: accessibilityLabel ?? (typeof label === "string" ? label : void 0),
|
|
1364
1581
|
accessibilityHint,
|
|
1365
1582
|
accessibilityState: {
|
|
1366
|
-
expanded:
|
|
1583
|
+
expanded: open,
|
|
1367
1584
|
disabled: isChildDisabled
|
|
1368
1585
|
},
|
|
1369
1586
|
onPress: () => {
|
|
1370
1587
|
child.props.onPress?.();
|
|
1371
|
-
if (!isChildDisabled)
|
|
1588
|
+
if (!isChildDisabled) toggle();
|
|
1372
1589
|
}
|
|
1373
1590
|
});
|
|
1374
1591
|
}
|
|
@@ -1379,10 +1596,10 @@ function DropdownTrigger({ asChild = false, label, trigger, children, icon, arro
|
|
|
1379
1596
|
accessibilityLabel: accessibilityLabel ?? (typeof label === "string" ? label : void 0),
|
|
1380
1597
|
accessibilityHint,
|
|
1381
1598
|
accessibilityState: {
|
|
1382
|
-
expanded:
|
|
1599
|
+
expanded: open,
|
|
1383
1600
|
disabled
|
|
1384
1601
|
},
|
|
1385
|
-
onPress,
|
|
1602
|
+
onPress: toggle,
|
|
1386
1603
|
onPressIn: () => setIsPressed(true),
|
|
1387
1604
|
onPressOut: () => setIsPressed(false),
|
|
1388
1605
|
style: [
|
|
@@ -1429,8 +1646,6 @@ DropdownTrigger.displayName = "DropdownTrigger";
|
|
|
1429
1646
|
function DropdownRoot({ children, label = "Menu", trigger, icon, arrowIcon, showArrow = true, open, defaultOpen = false, onOpenChange, presentation = "auto", placement = "bottom-start", offset = 8, closeOnSelect = true, color = "primary", disabled = false, loading = false, loadingText = "Loading actions...", searchable = false, command = false, searchValue, defaultSearchValue = "", searchPlaceholder, onSearch, empty, size = "md", style, triggerStyle, contentStyle, itemStyle, textStyle, accessibilityLabel, accessibilityHint }) {
|
|
1430
1647
|
const styles = useThemeStyles(createStyles$20);
|
|
1431
1648
|
const overlayId = useId();
|
|
1432
|
-
const [uncontrolledSearchValue, setUncontrolledSearchValue] = useState(defaultSearchValue);
|
|
1433
|
-
const resolvedSearchValue = searchValue ?? uncontrolledSearchValue;
|
|
1434
1649
|
const triggerRef = useRef(null);
|
|
1435
1650
|
const setTriggerRef = useCallback((node) => {
|
|
1436
1651
|
if (node && typeof node === "object" && "measureInWindow" in node && typeof node.measureInWindow === "function") {
|
|
@@ -1440,29 +1655,26 @@ function DropdownRoot({ children, label = "Menu", trigger, icon, arrowIcon, show
|
|
|
1440
1655
|
triggerRef.current = null;
|
|
1441
1656
|
}, []);
|
|
1442
1657
|
const parsed = useMemo(() => parseDropdownChildren(children), [children]);
|
|
1443
|
-
const contentCommand
|
|
1444
|
-
|
|
1658
|
+
const { contentCommand, filteredParsed, handleSearchChange, isSearchable, resolvedSearchValue } = useDropdownSearch({
|
|
1659
|
+
parsed,
|
|
1660
|
+
searchable,
|
|
1661
|
+
command,
|
|
1662
|
+
searchValue,
|
|
1663
|
+
defaultSearchValue,
|
|
1664
|
+
onSearch
|
|
1665
|
+
});
|
|
1666
|
+
const { navigableItems, data } = useDropdownEntries({
|
|
1667
|
+
parsed,
|
|
1668
|
+
filteredParsed,
|
|
1669
|
+
loading,
|
|
1670
|
+
loadingText,
|
|
1671
|
+
isSearchable,
|
|
1672
|
+
empty
|
|
1673
|
+
});
|
|
1445
1674
|
const resolvedPresentation = useOverlayPresentation(presentation);
|
|
1446
1675
|
const contentStyleFromSlot = parsed.contentProps?.style;
|
|
1447
1676
|
const contentPresentation = (parsed.contentProps?.presentation === "auto" ? void 0 : parsed.contentProps?.presentation) ?? resolvedPresentation;
|
|
1448
1677
|
const { position, updatePosition, onFloatingLayout } = useNativeFloatingPosition(placement, offset);
|
|
1449
|
-
const menuAccessibilityLabel = useMemo(() => {
|
|
1450
|
-
if (accessibilityLabel) return accessibilityLabel;
|
|
1451
|
-
return typeof label === "string" ? label : "Menu";
|
|
1452
|
-
}, [accessibilityLabel, label]);
|
|
1453
|
-
const navigableItems = useMemo(() => parsed.items.map((item) => ({
|
|
1454
|
-
disabled: item.disabled,
|
|
1455
|
-
label: item.label,
|
|
1456
|
-
value: item.id
|
|
1457
|
-
})), [parsed.items]);
|
|
1458
|
-
const filteredParsed = useMemo(() => {
|
|
1459
|
-
if (!isSearchable || !resolvedSearchValue.trim()) return parsed;
|
|
1460
|
-
return filterDropdownEntries(parsed, resolvedSearchValue);
|
|
1461
|
-
}, [
|
|
1462
|
-
isSearchable,
|
|
1463
|
-
parsed,
|
|
1464
|
-
resolvedSearchValue
|
|
1465
|
-
]);
|
|
1466
1678
|
const { isOpen, closeDropdown, toggleDropdown } = useDropdown({
|
|
1467
1679
|
items: navigableItems,
|
|
1468
1680
|
open,
|
|
@@ -1472,6 +1684,11 @@ function DropdownRoot({ children, label = "Menu", trigger, icon, arrowIcon, show
|
|
|
1472
1684
|
getItemValue: (item) => item.value,
|
|
1473
1685
|
getItemText: (item) => typeof item.label === "string" ? item.label : item.value
|
|
1474
1686
|
});
|
|
1687
|
+
const { menuAccessibilityLabel } = useDropdownAccessibility({
|
|
1688
|
+
accessibilityLabel,
|
|
1689
|
+
label,
|
|
1690
|
+
open: isOpen
|
|
1691
|
+
});
|
|
1475
1692
|
useEffect(() => {
|
|
1476
1693
|
if (!isOpen || contentPresentation !== "popover") return;
|
|
1477
1694
|
updatePosition(triggerRef);
|
|
@@ -1480,11 +1697,10 @@ function DropdownRoot({ children, label = "Menu", trigger, icon, arrowIcon, show
|
|
|
1480
1697
|
contentPresentation,
|
|
1481
1698
|
updatePosition
|
|
1482
1699
|
]);
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
}
|
|
1487
|
-
const { restoreFocusAfterClose } = useOverlayFocusRestore({ triggerRef });
|
|
1700
|
+
const { restoreFocusAfterClose } = useOverlayFocusRestore({
|
|
1701
|
+
active: isOpen,
|
|
1702
|
+
triggerRef
|
|
1703
|
+
});
|
|
1488
1704
|
const closeAndFocusTrigger = useCallback(() => {
|
|
1489
1705
|
closeDropdown();
|
|
1490
1706
|
restoreFocusAfterClose();
|
|
@@ -1508,10 +1724,6 @@ function DropdownRoot({ children, label = "Menu", trigger, icon, arrowIcon, show
|
|
|
1508
1724
|
const handleTriggerPress = useCallback(() => {
|
|
1509
1725
|
toggleDropdown();
|
|
1510
1726
|
}, [toggleDropdown]);
|
|
1511
|
-
const handleSearchChange = useCallback((value) => {
|
|
1512
|
-
if (searchValue === void 0) setUncontrolledSearchValue(value);
|
|
1513
|
-
onSearch?.(value);
|
|
1514
|
-
}, [onSearch, searchValue]);
|
|
1515
1727
|
const renderEntry = useCallback(({ item }) => {
|
|
1516
1728
|
if (item.type === "label") return /* @__PURE__ */ jsx(DropdownGroup, { label: item.props.children });
|
|
1517
1729
|
if (item.type === "separator") return /* @__PURE__ */ jsx(DropdownSeparator, {});
|
|
@@ -1526,71 +1738,82 @@ function DropdownRoot({ children, label = "Menu", trigger, icon, arrowIcon, show
|
|
|
1526
1738
|
return /* @__PURE__ */ jsx(DropdownItem, {
|
|
1527
1739
|
label: item.props.children,
|
|
1528
1740
|
value: item.props.value ?? item.id,
|
|
1529
|
-
rootColor: color,
|
|
1530
1741
|
color: item.props.color,
|
|
1531
1742
|
icon: item.props.icon,
|
|
1532
1743
|
disabled: item.props.disabled,
|
|
1533
1744
|
textWrap: item.props.textWrap,
|
|
1534
|
-
itemStyle,
|
|
1535
|
-
textStyle,
|
|
1536
1745
|
onSelect: () => handleSelect(item)
|
|
1537
1746
|
});
|
|
1538
|
-
}, [
|
|
1539
|
-
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
type: "loading",
|
|
1547
|
-
id: "loading",
|
|
1548
|
-
props: { children: loadingText }
|
|
1549
|
-
}] : isSearchable && filteredParsed.items.length === 0 ? [{
|
|
1550
|
-
type: "empty",
|
|
1551
|
-
id: "empty",
|
|
1552
|
-
props: { children: empty ?? "No actions found" }
|
|
1553
|
-
}] : filteredParsed.entries;
|
|
1554
|
-
return /* @__PURE__ */ jsxs(View, {
|
|
1555
|
-
style: [styles.root, style],
|
|
1556
|
-
children: [/* @__PURE__ */ jsx(DropdownTrigger, {
|
|
1557
|
-
asChild: Boolean(parsed.trigger),
|
|
1558
|
-
label,
|
|
1559
|
-
trigger: trigger ?? parsed.trigger,
|
|
1560
|
-
icon,
|
|
1561
|
-
arrowIcon,
|
|
1562
|
-
showArrow,
|
|
1747
|
+
}, [handleSelect, styles.emptyText]);
|
|
1748
|
+
const resolvedSearchPlaceholder = parsed.searchProps?.placeholder ?? searchPlaceholder ?? (command || contentCommand ? "Type a command..." : "Search actions...");
|
|
1749
|
+
const searchAccessibilityLabel = parsed.searchProps?.accessibilityLabel;
|
|
1750
|
+
return /* @__PURE__ */ jsx(DropdownProvider, {
|
|
1751
|
+
value: useMemo(() => ({
|
|
1752
|
+
open: isOpen,
|
|
1753
|
+
disabled,
|
|
1754
|
+
loading,
|
|
1563
1755
|
color,
|
|
1564
|
-
disabled: disabled || parsed.triggerProps?.disabled,
|
|
1565
|
-
isOpen,
|
|
1566
1756
|
size,
|
|
1567
|
-
triggerRef: setTriggerRef,
|
|
1568
|
-
triggerStyle,
|
|
1569
|
-
accessibilityLabel,
|
|
1570
|
-
accessibilityHint,
|
|
1571
|
-
onPress: handleTriggerPress
|
|
1572
|
-
}), /* @__PURE__ */ jsx(DropdownContent, {
|
|
1573
|
-
isOpen,
|
|
1574
|
-
onClose: dismiss.requestClose,
|
|
1575
|
-
color,
|
|
1576
|
-
contentStyle: [contentStyle, contentStyleFromSlot],
|
|
1577
|
-
accessibilityLabel: menuAccessibilityLabel,
|
|
1578
1757
|
presentation: contentPresentation,
|
|
1579
1758
|
position,
|
|
1580
|
-
|
|
1759
|
+
zIndex: dismiss.zIndex,
|
|
1581
1760
|
searchable: isSearchable,
|
|
1582
1761
|
searchValue: resolvedSearchValue,
|
|
1583
|
-
searchPlaceholder:
|
|
1584
|
-
searchAccessibilityLabel
|
|
1762
|
+
searchPlaceholder: resolvedSearchPlaceholder,
|
|
1763
|
+
searchAccessibilityLabel,
|
|
1764
|
+
itemStyle,
|
|
1765
|
+
textStyle,
|
|
1766
|
+
requestClose: dismiss.requestClose,
|
|
1767
|
+
requestOutsideClose: dismiss.requestOutsideClose,
|
|
1768
|
+
toggle: handleTriggerPress,
|
|
1585
1769
|
onSearchChange: handleSearchChange,
|
|
1586
|
-
|
|
1587
|
-
|
|
1588
|
-
|
|
1589
|
-
|
|
1590
|
-
|
|
1591
|
-
|
|
1592
|
-
|
|
1593
|
-
|
|
1770
|
+
onFloatingLayout
|
|
1771
|
+
}), [
|
|
1772
|
+
color,
|
|
1773
|
+
contentPresentation,
|
|
1774
|
+
disabled,
|
|
1775
|
+
dismiss.zIndex,
|
|
1776
|
+
dismiss.requestClose,
|
|
1777
|
+
dismiss.requestOutsideClose,
|
|
1778
|
+
handleSearchChange,
|
|
1779
|
+
handleTriggerPress,
|
|
1780
|
+
isOpen,
|
|
1781
|
+
isSearchable,
|
|
1782
|
+
itemStyle,
|
|
1783
|
+
loading,
|
|
1784
|
+
onFloatingLayout,
|
|
1785
|
+
position,
|
|
1786
|
+
resolvedSearchPlaceholder,
|
|
1787
|
+
resolvedSearchValue,
|
|
1788
|
+
searchAccessibilityLabel,
|
|
1789
|
+
size,
|
|
1790
|
+
textStyle
|
|
1791
|
+
]),
|
|
1792
|
+
children: /* @__PURE__ */ jsxs(View, {
|
|
1793
|
+
style: [styles.root, style],
|
|
1794
|
+
children: [/* @__PURE__ */ jsx(DropdownTrigger, {
|
|
1795
|
+
asChild: Boolean(parsed.trigger),
|
|
1796
|
+
label,
|
|
1797
|
+
trigger: trigger ?? parsed.trigger,
|
|
1798
|
+
icon,
|
|
1799
|
+
arrowIcon,
|
|
1800
|
+
showArrow,
|
|
1801
|
+
triggerRef: setTriggerRef,
|
|
1802
|
+
triggerStyle,
|
|
1803
|
+
accessibilityLabel,
|
|
1804
|
+
accessibilityHint
|
|
1805
|
+
}), /* @__PURE__ */ jsx(DropdownContent, {
|
|
1806
|
+
contentStyle: [contentStyle, contentStyleFromSlot],
|
|
1807
|
+
accessibilityLabel: menuAccessibilityLabel,
|
|
1808
|
+
children: /* @__PURE__ */ jsx(FlatList, {
|
|
1809
|
+
data,
|
|
1810
|
+
keyExtractor: (item) => item.id,
|
|
1811
|
+
renderItem: renderEntry,
|
|
1812
|
+
keyboardShouldPersistTaps: "handled",
|
|
1813
|
+
removeClippedSubviews: data.length > 24
|
|
1814
|
+
})
|
|
1815
|
+
})]
|
|
1816
|
+
})
|
|
1594
1817
|
});
|
|
1595
1818
|
}
|
|
1596
1819
|
DropdownRoot.displayName = "Dropdown";
|
|
@@ -1682,13 +1905,14 @@ const createStyles$14 = (theme) => StyleSheet.create({
|
|
|
1682
1905
|
});
|
|
1683
1906
|
//#endregion
|
|
1684
1907
|
//#region src/components/Modal/internal/ModalContext.tsx
|
|
1685
|
-
const ModalContext = createContext(
|
|
1686
|
-
|
|
1908
|
+
const ModalContext = createContext(null);
|
|
1909
|
+
const ModalProvider = ModalContext.Provider;
|
|
1687
1910
|
const useModalContext = () => {
|
|
1688
1911
|
const context = useContext(ModalContext);
|
|
1689
1912
|
if (!context) throw new Error("Modal compound components must be used inside Modal");
|
|
1690
1913
|
return context;
|
|
1691
1914
|
};
|
|
1915
|
+
ModalContext.displayName = "ModalContext";
|
|
1692
1916
|
//#endregion
|
|
1693
1917
|
//#region src/components/Modal/Close/ModalClose.tsx
|
|
1694
1918
|
const ModalClose = ({ children, accessibilityLabel, style }) => {
|
|
@@ -1818,7 +2042,7 @@ const createStyles$11 = (theme) => StyleSheet.create({
|
|
|
1818
2042
|
//#region src/components/Modal/Overlay/ModalOverlay.tsx
|
|
1819
2043
|
const ModalOverlay = ({ children, overlayStyle }) => {
|
|
1820
2044
|
const styles = useThemeStyles(createStyles$11);
|
|
1821
|
-
const { animation, animationProgress, closeOnOutsidePress, onClose, onOutsideClose, shouldRender } = useModalContext();
|
|
2045
|
+
const { animation, animationProgress, closeOnOutsidePress, zIndex, onClose, onOutsideClose, shouldRender } = useModalContext();
|
|
1822
2046
|
const backdropStyle = animation === "none" ? void 0 : { opacity: animationProgress };
|
|
1823
2047
|
return /* @__PURE__ */ jsx(Modal$1, {
|
|
1824
2048
|
visible: shouldRender,
|
|
@@ -1826,7 +2050,11 @@ const ModalOverlay = ({ children, overlayStyle }) => {
|
|
|
1826
2050
|
animationType: "none",
|
|
1827
2051
|
onRequestClose: onClose,
|
|
1828
2052
|
children: /* @__PURE__ */ jsxs(View, {
|
|
1829
|
-
style: [
|
|
2053
|
+
style: [
|
|
2054
|
+
styles.overlay,
|
|
2055
|
+
Platform.OS === "web" && { zIndex },
|
|
2056
|
+
overlayStyle
|
|
2057
|
+
],
|
|
1830
2058
|
children: [/* @__PURE__ */ jsx(Animated.View, {
|
|
1831
2059
|
style: [styles.backdrop, backdropStyle],
|
|
1832
2060
|
children: /* @__PURE__ */ jsx(Pressable, {
|
|
@@ -1865,6 +2093,7 @@ const resolveDuration = (duration) => {
|
|
|
1865
2093
|
const ModalRoot = ({ open, defaultOpen = false, onOpenChange, animation = "scale", duration, easing = "standard", closeOnOutsidePress = true, children }) => {
|
|
1866
2094
|
const initialOpen = open ?? defaultOpen;
|
|
1867
2095
|
const animationProgress = useRef(new Animated.Value(initialOpen ? 1 : 0));
|
|
2096
|
+
const triggerRef = useRef(null);
|
|
1868
2097
|
const [shouldRender, setShouldRender] = useState(initialOpen);
|
|
1869
2098
|
const [reduceMotion, setReduceMotion] = useState(false);
|
|
1870
2099
|
const modal = useModal({
|
|
@@ -1873,6 +2102,15 @@ const ModalRoot = ({ open, defaultOpen = false, onOpenChange, animation = "scale
|
|
|
1873
2102
|
onOpenChange,
|
|
1874
2103
|
closeOnOutsidePress
|
|
1875
2104
|
});
|
|
2105
|
+
const { restoreFocusAfterClose } = useOverlayFocusRestore({
|
|
2106
|
+
active: modal.open,
|
|
2107
|
+
triggerRef
|
|
2108
|
+
});
|
|
2109
|
+
const previousOpenRef = useRef(modal.open);
|
|
2110
|
+
useEffect(() => {
|
|
2111
|
+
if (previousOpenRef.current && !modal.open) restoreFocusAfterClose();
|
|
2112
|
+
previousOpenRef.current = modal.open;
|
|
2113
|
+
}, [modal.open, restoreFocusAfterClose]);
|
|
1876
2114
|
const dismiss = useOverlayDismiss({
|
|
1877
2115
|
id: modal.contentId,
|
|
1878
2116
|
active: modal.open,
|
|
@@ -1925,16 +2163,18 @@ const ModalRoot = ({ open, defaultOpen = false, onOpenChange, animation = "scale
|
|
|
1925
2163
|
modal.open,
|
|
1926
2164
|
shouldAnimate
|
|
1927
2165
|
]);
|
|
1928
|
-
return /* @__PURE__ */ jsx(
|
|
2166
|
+
return /* @__PURE__ */ jsx(ModalProvider, {
|
|
1929
2167
|
value: {
|
|
1930
2168
|
animation,
|
|
1931
2169
|
animationProgress: animationProgress.current,
|
|
1932
2170
|
closeOnOutsidePress: modal.closeOnOutsidePress,
|
|
2171
|
+
zIndex: dismiss.zIndex,
|
|
1933
2172
|
onClose: dismiss.requestClose,
|
|
1934
2173
|
onOutsideClose: dismiss.requestOutsideClose,
|
|
1935
2174
|
open: modal.open,
|
|
1936
2175
|
setOpen: modal.setOpen,
|
|
1937
|
-
shouldRender
|
|
2176
|
+
shouldRender,
|
|
2177
|
+
triggerRef
|
|
1938
2178
|
},
|
|
1939
2179
|
children
|
|
1940
2180
|
});
|
|
@@ -1942,15 +2182,26 @@ const ModalRoot = ({ open, defaultOpen = false, onOpenChange, animation = "scale
|
|
|
1942
2182
|
ModalRoot.displayName = "ModalRoot";
|
|
1943
2183
|
//#endregion
|
|
1944
2184
|
//#region src/components/Modal/Trigger/ModalTrigger.tsx
|
|
2185
|
+
const composeRefs = (...refs) => (node) => {
|
|
2186
|
+
for (const ref of refs) {
|
|
2187
|
+
if (typeof ref === "function") {
|
|
2188
|
+
ref(node);
|
|
2189
|
+
continue;
|
|
2190
|
+
}
|
|
2191
|
+
if (ref) ref.current = node;
|
|
2192
|
+
}
|
|
2193
|
+
};
|
|
1945
2194
|
const ModalTrigger = ({ children, asChild = false, disabled = false, accessibilityLabel, style, testID }) => {
|
|
1946
2195
|
const root = useModalContext();
|
|
1947
2196
|
const child = asChild && isValidElement(children) ? children : void 0;
|
|
2197
|
+
const composedTriggerRef = child ? composeRefs(root.triggerRef, child.props.ref) : root.triggerRef;
|
|
1948
2198
|
const handlePress = (event) => {
|
|
1949
2199
|
if (disabled || child?.props.disabled) return;
|
|
1950
2200
|
child?.props.onPress?.(event);
|
|
1951
2201
|
root.setOpen(true);
|
|
1952
2202
|
};
|
|
1953
2203
|
if (child) return cloneElement(child, {
|
|
2204
|
+
ref: composedTriggerRef,
|
|
1954
2205
|
onPress: handlePress,
|
|
1955
2206
|
accessibilityRole: child.props.accessibilityRole ?? "button",
|
|
1956
2207
|
accessibilityState: {
|
|
@@ -1963,6 +2214,7 @@ const ModalTrigger = ({ children, asChild = false, disabled = false, accessibili
|
|
|
1963
2214
|
style: child.props.style
|
|
1964
2215
|
});
|
|
1965
2216
|
return /* @__PURE__ */ jsx(Pressable, {
|
|
2217
|
+
ref: root.triggerRef,
|
|
1966
2218
|
accessibilityRole: "button",
|
|
1967
2219
|
accessibilityState: {
|
|
1968
2220
|
expanded: root.open,
|
|
@@ -2132,7 +2384,7 @@ PortalProvider.displayName = "PortalProvider";
|
|
|
2132
2384
|
//#endregion
|
|
2133
2385
|
//#region src/components/Popover/Content/PopoverContent.styles.ts
|
|
2134
2386
|
const styles = StyleSheet.create({
|
|
2135
|
-
|
|
2387
|
+
root: { flex: 1 },
|
|
2136
2388
|
backdrop: StyleSheet.absoluteFill,
|
|
2137
2389
|
content: { position: "absolute" }
|
|
2138
2390
|
});
|
|
@@ -2164,7 +2416,7 @@ function PopoverContent({ children, style, ...contentProps }) {
|
|
|
2164
2416
|
const { theme } = useTheme();
|
|
2165
2417
|
const layerRef = useRef(null);
|
|
2166
2418
|
const themedStyles = useMemo(() => createPopoverContentStyles(theme), [theme]);
|
|
2167
|
-
const { open, position, onFloatingLayout, updatePosition,
|
|
2419
|
+
const { open, zIndex, position, onFloatingLayout, updatePosition, requestClose, requestOutsideClose, closeOnOutsidePress } = usePopoverContext("Popover.Content");
|
|
2168
2420
|
useEffect(() => {
|
|
2169
2421
|
if (!open) return;
|
|
2170
2422
|
requestAnimationFrame(() => {
|
|
@@ -2173,20 +2425,16 @@ function PopoverContent({ children, style, ...contentProps }) {
|
|
|
2173
2425
|
}, [open, updatePosition]);
|
|
2174
2426
|
return /* @__PURE__ */ jsx(Portal, {
|
|
2175
2427
|
visible: open,
|
|
2176
|
-
onRequestClose:
|
|
2177
|
-
setOpen(false, { reason: "escape-key" });
|
|
2178
|
-
},
|
|
2428
|
+
onRequestClose: requestClose,
|
|
2179
2429
|
children: /* @__PURE__ */ jsxs(View, {
|
|
2180
2430
|
ref: layerRef,
|
|
2181
2431
|
pointerEvents: "box-none",
|
|
2182
|
-
style: styles.
|
|
2432
|
+
style: [styles.root, { zIndex }],
|
|
2183
2433
|
children: [/* @__PURE__ */ jsx(Pressable, {
|
|
2184
2434
|
testID: "popover-backdrop",
|
|
2185
2435
|
accessibilityLabel: closeOnOutsidePress ? "Close popover" : void 0,
|
|
2186
2436
|
accessibilityRole: closeOnOutsidePress ? "button" : void 0,
|
|
2187
|
-
onPress: closeOnOutsidePress ?
|
|
2188
|
-
setOpen(false, { reason: "outside-press" });
|
|
2189
|
-
} : void 0,
|
|
2437
|
+
onPress: closeOnOutsidePress ? requestOutsideClose : void 0,
|
|
2190
2438
|
style: styles.backdrop
|
|
2191
2439
|
}), /* @__PURE__ */ jsx(View, {
|
|
2192
2440
|
...contentProps,
|
|
@@ -2232,6 +2480,7 @@ function getNativePlacement(side, align) {
|
|
|
2232
2480
|
function PopoverRoot({ children, open: openProp, defaultOpen = false, onOpenChange, side = "bottom", align = "center", sideOffset = 8, closeOnOutsidePress = true }) {
|
|
2233
2481
|
const triggerRef = useRef(null);
|
|
2234
2482
|
const anchorRef = useRef(null);
|
|
2483
|
+
const overlayId = useId();
|
|
2235
2484
|
const getReferenceRef = useCallback(() => anchorRef.current ? anchorRef : triggerRef, []);
|
|
2236
2485
|
const openChangeDetailsRef = useRef({ reason: "programmatic" });
|
|
2237
2486
|
const [open, setOpenState] = useControllableState({
|
|
@@ -2241,11 +2490,30 @@ function PopoverRoot({ children, open: openProp, defaultOpen = false, onOpenChan
|
|
|
2241
2490
|
onOpenChange?.(nextOpen, openChangeDetailsRef.current);
|
|
2242
2491
|
}
|
|
2243
2492
|
});
|
|
2493
|
+
const { restoreFocusAfterClose } = useOverlayFocusRestore({
|
|
2494
|
+
active: open,
|
|
2495
|
+
triggerRef
|
|
2496
|
+
});
|
|
2244
2497
|
const { position, arrowPosition, placement, updatePosition: updateFloatingPosition, onFloatingLayout } = useNativeFloatingPosition(getNativePlacement(side, align), sideOffset);
|
|
2245
2498
|
const setOpen = useCallback((nextOpen, details) => {
|
|
2246
2499
|
openChangeDetailsRef.current = details;
|
|
2247
2500
|
setOpenState(nextOpen);
|
|
2248
|
-
|
|
2501
|
+
if (!nextOpen) restoreFocusAfterClose();
|
|
2502
|
+
}, [restoreFocusAfterClose, setOpenState]);
|
|
2503
|
+
const dismiss = useOverlayDismiss({
|
|
2504
|
+
id: overlayId,
|
|
2505
|
+
active: open,
|
|
2506
|
+
closeOnOutsidePress,
|
|
2507
|
+
requestClose: () => {
|
|
2508
|
+
setOpen(false, { reason: "escape-key" });
|
|
2509
|
+
},
|
|
2510
|
+
requestOutsideClose: () => {
|
|
2511
|
+
setOpen(false, { reason: "outside-press" });
|
|
2512
|
+
}
|
|
2513
|
+
});
|
|
2514
|
+
const updatePosition = useCallback((containerRef) => {
|
|
2515
|
+
updateFloatingPosition(getReferenceRef(), containerRef);
|
|
2516
|
+
}, [getReferenceRef, updateFloatingPosition]);
|
|
2249
2517
|
return /* @__PURE__ */ jsx(PopoverProvider, {
|
|
2250
2518
|
value: {
|
|
2251
2519
|
open,
|
|
@@ -2255,12 +2523,13 @@ function PopoverRoot({ children, open: openProp, defaultOpen = false, onOpenChan
|
|
|
2255
2523
|
side,
|
|
2256
2524
|
align,
|
|
2257
2525
|
placement,
|
|
2526
|
+
zIndex: dismiss.zIndex,
|
|
2258
2527
|
position,
|
|
2259
2528
|
arrowPosition,
|
|
2529
|
+
requestClose: dismiss.requestClose,
|
|
2530
|
+
requestOutsideClose: dismiss.requestOutsideClose,
|
|
2260
2531
|
onFloatingLayout,
|
|
2261
|
-
updatePosition
|
|
2262
|
-
updateFloatingPosition(getReferenceRef(), containerRef);
|
|
2263
|
-
}, [getReferenceRef, updateFloatingPosition]),
|
|
2532
|
+
updatePosition,
|
|
2264
2533
|
setOpen
|
|
2265
2534
|
},
|
|
2266
2535
|
children
|
|
@@ -2384,8 +2653,8 @@ const createStyles$10 = (theme) => StyleSheet.create({
|
|
|
2384
2653
|
});
|
|
2385
2654
|
//#endregion
|
|
2386
2655
|
//#region src/primitives/Radio/Radio.tsx
|
|
2387
|
-
const nativePointerEventsNone$
|
|
2388
|
-
const webPointerEventsNone$
|
|
2656
|
+
const nativePointerEventsNone$3 = Platform.OS === "web" ? void 0 : { pointerEvents: "none" };
|
|
2657
|
+
const webPointerEventsNone$3 = Platform.OS === "web" ? { pointerEvents: "none" } : void 0;
|
|
2389
2658
|
const Radio = forwardRef(({ value, checked, defaultChecked = false, disabled: disabledProp = false, required: requiredProp = false, size: sizeProp, color: colorProp, onCheckedChange, label, description, icon, error, accessibilityLabel, accessibilityHint, containerStyle, labelStyle, descriptionStyle, errorStyle, style, ...rest }, ref) => {
|
|
2390
2659
|
const { theme } = useTheme();
|
|
2391
2660
|
const styles = createStyles$10(theme);
|
|
@@ -2444,10 +2713,10 @@ const Radio = forwardRef(({ value, checked, defaultChecked = false, disabled: di
|
|
|
2444
2713
|
onPress: handlePress,
|
|
2445
2714
|
style: resolvePressableStyle,
|
|
2446
2715
|
children: (state) => /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(View, {
|
|
2447
|
-
...nativePointerEventsNone$
|
|
2716
|
+
...nativePointerEventsNone$3,
|
|
2448
2717
|
style: [
|
|
2449
2718
|
styles.control,
|
|
2450
|
-
webPointerEventsNone$
|
|
2719
|
+
webPointerEventsNone$3,
|
|
2451
2720
|
{
|
|
2452
2721
|
width: radioSize.controlSize,
|
|
2453
2722
|
height: radioSize.controlSize,
|
|
@@ -2476,8 +2745,8 @@ const Radio = forwardRef(({ value, checked, defaultChecked = false, disabled: di
|
|
|
2476
2745
|
resolvedDisabled && styles.indicatorDisabled
|
|
2477
2746
|
] }))
|
|
2478
2747
|
}), (label || description) && /* @__PURE__ */ jsxs(View, {
|
|
2479
|
-
...nativePointerEventsNone$
|
|
2480
|
-
style: [styles.content, webPointerEventsNone$
|
|
2748
|
+
...nativePointerEventsNone$3,
|
|
2749
|
+
style: [styles.content, webPointerEventsNone$3],
|
|
2481
2750
|
children: [label && (typeof label === "string" ? /* @__PURE__ */ jsx(Text, {
|
|
2482
2751
|
style: [
|
|
2483
2752
|
styles.label,
|
|
@@ -2890,6 +3159,78 @@ RadioGroupRoot.displayName = "RadioGroup.Root";
|
|
|
2890
3159
|
const RadioGroup = Object.assign(RadioGroupRoot, { Item: RadioGroupItem });
|
|
2891
3160
|
RadioGroup.displayName = "RadioGroup";
|
|
2892
3161
|
//#endregion
|
|
3162
|
+
//#region src/components/Select/Content/SelectContent.styles.ts
|
|
3163
|
+
const createContentStyles = (theme) => StyleSheet.create({
|
|
3164
|
+
toolbar: {
|
|
3165
|
+
minHeight: 52,
|
|
3166
|
+
flexDirection: "row",
|
|
3167
|
+
alignItems: "center",
|
|
3168
|
+
justifyContent: "space-between",
|
|
3169
|
+
paddingHorizontal: theme.tokens.spacing[4],
|
|
3170
|
+
borderBottomColor: theme.components.select.dropdown.separator.bg,
|
|
3171
|
+
borderBottomWidth: 1
|
|
3172
|
+
},
|
|
3173
|
+
title: {
|
|
3174
|
+
flex: 1,
|
|
3175
|
+
marginHorizontal: theme.tokens.spacing[3],
|
|
3176
|
+
color: theme.components.select.dropdown.fg,
|
|
3177
|
+
fontFamily: theme.tokens.typography.family.medium,
|
|
3178
|
+
fontSize: theme.tokens.typography.size.md,
|
|
3179
|
+
lineHeight: theme.tokens.typography.lineHeight.md,
|
|
3180
|
+
textAlign: "center"
|
|
3181
|
+
},
|
|
3182
|
+
toolbarAction: {
|
|
3183
|
+
minWidth: 64,
|
|
3184
|
+
minHeight: 44,
|
|
3185
|
+
alignItems: "center",
|
|
3186
|
+
justifyContent: "center"
|
|
3187
|
+
},
|
|
3188
|
+
cancelText: {
|
|
3189
|
+
color: theme.components.select.trigger.placeholder.fg,
|
|
3190
|
+
fontFamily: theme.tokens.typography.family.medium,
|
|
3191
|
+
fontSize: theme.tokens.typography.size.md,
|
|
3192
|
+
lineHeight: theme.tokens.typography.lineHeight.md
|
|
3193
|
+
},
|
|
3194
|
+
doneText: {
|
|
3195
|
+
color: theme.semantic.text.interactive,
|
|
3196
|
+
fontFamily: theme.tokens.typography.family.medium,
|
|
3197
|
+
fontSize: theme.tokens.typography.size.md,
|
|
3198
|
+
lineHeight: theme.tokens.typography.lineHeight.md
|
|
3199
|
+
},
|
|
3200
|
+
list: { maxHeight: 420 },
|
|
3201
|
+
listContent: {
|
|
3202
|
+
paddingHorizontal: theme.tokens.spacing[2],
|
|
3203
|
+
paddingVertical: theme.tokens.spacing[2]
|
|
3204
|
+
},
|
|
3205
|
+
empty: {
|
|
3206
|
+
minHeight: 72,
|
|
3207
|
+
alignItems: "center",
|
|
3208
|
+
justifyContent: "center",
|
|
3209
|
+
padding: theme.tokens.spacing[4]
|
|
3210
|
+
},
|
|
3211
|
+
emptyText: {
|
|
3212
|
+
color: theme.components.select.dropdown.empty.fg,
|
|
3213
|
+
fontFamily: theme.tokens.typography.family.regular,
|
|
3214
|
+
fontSize: theme.tokens.typography.size.md,
|
|
3215
|
+
lineHeight: theme.tokens.typography.lineHeight.md,
|
|
3216
|
+
textAlign: "center"
|
|
3217
|
+
},
|
|
3218
|
+
loading: {
|
|
3219
|
+
minHeight: 72,
|
|
3220
|
+
flexDirection: "row",
|
|
3221
|
+
alignItems: "center",
|
|
3222
|
+
justifyContent: "center",
|
|
3223
|
+
gap: theme.tokens.spacing[2],
|
|
3224
|
+
padding: theme.tokens.spacing[4]
|
|
3225
|
+
},
|
|
3226
|
+
loadingText: {
|
|
3227
|
+
color: theme.components.select.dropdown.fg,
|
|
3228
|
+
fontFamily: theme.tokens.typography.family.regular,
|
|
3229
|
+
fontSize: theme.tokens.typography.size.md,
|
|
3230
|
+
lineHeight: theme.tokens.typography.lineHeight.md
|
|
3231
|
+
}
|
|
3232
|
+
});
|
|
3233
|
+
//#endregion
|
|
2893
3234
|
//#region src/components/Select/internal/types.ts
|
|
2894
3235
|
const selectSlotName = Symbol("VelliraNativeSelectSlot");
|
|
2895
3236
|
//#endregion
|
|
@@ -3017,6 +3358,33 @@ const parseSelectChildren = (children) => {
|
|
|
3017
3358
|
};
|
|
3018
3359
|
};
|
|
3019
3360
|
//#endregion
|
|
3361
|
+
//#region src/components/Select/internal/SelectContext.tsx
|
|
3362
|
+
const SelectContext = createContext(null);
|
|
3363
|
+
const useSelectContext = () => {
|
|
3364
|
+
const context = useContext(SelectContext);
|
|
3365
|
+
if (!context) throw new Error("Select compound components must be used inside Select");
|
|
3366
|
+
return context;
|
|
3367
|
+
};
|
|
3368
|
+
//#endregion
|
|
3369
|
+
//#region src/components/Select/Empty/SelectEmpty.tsx
|
|
3370
|
+
const renderText$1 = (node, style) => {
|
|
3371
|
+
if (typeof node === "string" || typeof node === "number") return /* @__PURE__ */ jsx(Text, {
|
|
3372
|
+
style,
|
|
3373
|
+
children: node
|
|
3374
|
+
});
|
|
3375
|
+
return node;
|
|
3376
|
+
};
|
|
3377
|
+
const SelectEmpty = createSelectSlot("empty", "Select.Empty");
|
|
3378
|
+
const SelectEmptyState = () => {
|
|
3379
|
+
const styles = useThemeStyles(createContentStyles);
|
|
3380
|
+
const { empty } = useSelectContext();
|
|
3381
|
+
return /* @__PURE__ */ jsx(View, {
|
|
3382
|
+
style: styles.empty,
|
|
3383
|
+
children: renderText$1(empty, styles.emptyText)
|
|
3384
|
+
});
|
|
3385
|
+
};
|
|
3386
|
+
SelectEmptyState.displayName = "Select.EmptyState";
|
|
3387
|
+
//#endregion
|
|
3020
3388
|
//#region src/components/Select/Group/SelectGroup.styles.ts
|
|
3021
3389
|
const createGroupStyles = (theme) => StyleSheet.create({
|
|
3022
3390
|
groupLabel: {
|
|
@@ -3100,24 +3468,6 @@ const SelectGroupActionRow = ({ label, selectLabel, selectedCount, itemCount, on
|
|
|
3100
3468
|
SelectGroupLabelRow.displayName = "Select.GroupLabelRow";
|
|
3101
3469
|
SelectGroupActionRow.displayName = "Select.GroupActionRow";
|
|
3102
3470
|
//#endregion
|
|
3103
|
-
//#region src/components/Select/Group/SelectLabel.tsx
|
|
3104
|
-
const SelectLabel = createSelectSlot("label", "Select.Label");
|
|
3105
|
-
//#endregion
|
|
3106
|
-
//#region src/components/Select/Group/SelectSeparator.tsx
|
|
3107
|
-
const SelectSeparator = createSelectSlot("separator", "Select.Separator");
|
|
3108
|
-
const SelectSeparatorRow = () => {
|
|
3109
|
-
return /* @__PURE__ */ jsx(View, { style: useThemeStyles(createGroupStyles).separator });
|
|
3110
|
-
};
|
|
3111
|
-
SelectSeparatorRow.displayName = "Select.SeparatorRow";
|
|
3112
|
-
//#endregion
|
|
3113
|
-
//#region src/components/Select/internal/SelectContext.tsx
|
|
3114
|
-
const SelectContext = createContext(null);
|
|
3115
|
-
const useSelectContext = () => {
|
|
3116
|
-
const context = useContext(SelectContext);
|
|
3117
|
-
if (!context) throw new Error("Select compound components must be used inside Select");
|
|
3118
|
-
return context;
|
|
3119
|
-
};
|
|
3120
|
-
//#endregion
|
|
3121
3471
|
//#region src/components/Select/Item/SelectItem.styles.ts
|
|
3122
3472
|
const createItemStyles = (theme) => StyleSheet.create({
|
|
3123
3473
|
option: {
|
|
@@ -3269,14 +3619,29 @@ const SelectItemRow = ({ option, isSelected, isDisabled, optionStyle, onSelect }
|
|
|
3269
3619
|
};
|
|
3270
3620
|
SelectItemRow.displayName = "Select.ItemRow";
|
|
3271
3621
|
//#endregion
|
|
3272
|
-
//#region src/components/Select/
|
|
3273
|
-
const
|
|
3274
|
-
|
|
3275
|
-
|
|
3276
|
-
|
|
3277
|
-
|
|
3278
|
-
|
|
3279
|
-
|
|
3622
|
+
//#region src/components/Select/Loading/SelectLoading.tsx
|
|
3623
|
+
const renderText = (node, style) => {
|
|
3624
|
+
if (typeof node === "string" || typeof node === "number") return /* @__PURE__ */ jsx(Text, {
|
|
3625
|
+
style,
|
|
3626
|
+
children: node
|
|
3627
|
+
});
|
|
3628
|
+
return node;
|
|
3629
|
+
};
|
|
3630
|
+
const SelectLoading = createSelectSlot("loading", "Select.Loading");
|
|
3631
|
+
const SelectLoadingState = () => {
|
|
3632
|
+
const { theme } = useTheme();
|
|
3633
|
+
const styles = useThemeStyles(createContentStyles);
|
|
3634
|
+
const { loadingContent } = useSelectContext();
|
|
3635
|
+
return /* @__PURE__ */ jsxs(View, {
|
|
3636
|
+
style: styles.loading,
|
|
3637
|
+
children: [/* @__PURE__ */ jsx(ActivityIndicator, {
|
|
3638
|
+
testID: "select-content-loading-indicator",
|
|
3639
|
+
size: "small",
|
|
3640
|
+
color: theme.components.select.dropdown.fg
|
|
3641
|
+
}), renderText(loadingContent, styles.loadingText)]
|
|
3642
|
+
});
|
|
3643
|
+
};
|
|
3644
|
+
SelectLoadingState.displayName = "Select.LoadingState";
|
|
3280
3645
|
//#endregion
|
|
3281
3646
|
//#region src/components/Select/Presentation/SelectPresentation.styles.ts
|
|
3282
3647
|
const createPresentationStyles = (theme) => StyleSheet.create({
|
|
@@ -3350,7 +3715,7 @@ const SelectHandle = () => {
|
|
|
3350
3715
|
SelectHandle.displayName = "Select.Handle";
|
|
3351
3716
|
//#endregion
|
|
3352
3717
|
//#region src/components/Select/Presentation/SelectModal.tsx
|
|
3353
|
-
const SelectModal = ({ visible, onClose, dismissOnBackdropPress, contentStyle, children }) => {
|
|
3718
|
+
const SelectModal = ({ visible, onClose, dismissOnBackdropPress, zIndex, contentStyle, children }) => {
|
|
3354
3719
|
const styles = useThemeStyles(createPresentationStyles);
|
|
3355
3720
|
return /* @__PURE__ */ jsx(Modal$1, {
|
|
3356
3721
|
transparent: true,
|
|
@@ -3358,7 +3723,11 @@ const SelectModal = ({ visible, onClose, dismissOnBackdropPress, contentStyle, c
|
|
|
3358
3723
|
animationType: "slide",
|
|
3359
3724
|
onRequestClose: onClose,
|
|
3360
3725
|
children: /* @__PURE__ */ jsxs(View, {
|
|
3361
|
-
style: [
|
|
3726
|
+
style: [
|
|
3727
|
+
styles.modalRoot,
|
|
3728
|
+
styles.modalPresentationRoot,
|
|
3729
|
+
Platform.OS === "web" && { zIndex }
|
|
3730
|
+
],
|
|
3362
3731
|
testID: "select-content-root",
|
|
3363
3732
|
children: [/* @__PURE__ */ jsx(SelectBackdrop, {
|
|
3364
3733
|
onClose,
|
|
@@ -3369,193 +3738,82 @@ const SelectModal = ({ visible, onClose, dismissOnBackdropPress, contentStyle, c
|
|
|
3369
3738
|
styles.modalPresentation,
|
|
3370
3739
|
contentStyle
|
|
3371
3740
|
],
|
|
3372
|
-
testID: "select-modal",
|
|
3373
|
-
children
|
|
3374
|
-
})]
|
|
3375
|
-
})
|
|
3376
|
-
});
|
|
3377
|
-
};
|
|
3378
|
-
SelectModal.displayName = "Select.Modal";
|
|
3379
|
-
//#endregion
|
|
3380
|
-
//#region src/components/Select/Presentation/SelectPopover.tsx
|
|
3381
|
-
const SelectPopover = ({ visible, onClose, dismissOnBackdropPress, position, onFloatingLayout, matchTriggerWidth, triggerWidth, contentStyle, children }) => {
|
|
3382
|
-
const styles = useThemeStyles(createPresentationStyles);
|
|
3383
|
-
return /* @__PURE__ */ jsx(Modal$1, {
|
|
3384
|
-
transparent: true,
|
|
3385
|
-
visible,
|
|
3386
|
-
animationType: "fade",
|
|
3387
|
-
onRequestClose: onClose,
|
|
3388
|
-
children: /* @__PURE__ */ jsxs(View, {
|
|
3389
|
-
style: styles.modalRoot,
|
|
3390
|
-
testID: "select-content-root",
|
|
3391
|
-
children: [/* @__PURE__ */ jsx(SelectBackdrop, {
|
|
3392
|
-
onClose,
|
|
3393
|
-
dismissOnBackdropPress
|
|
3394
|
-
}), /* @__PURE__ */ jsx(View, {
|
|
3395
|
-
onLayout: onFloatingLayout,
|
|
3396
|
-
style: [
|
|
3397
|
-
styles.content,
|
|
3398
|
-
styles.popover,
|
|
3399
|
-
{
|
|
3400
|
-
position: "absolute",
|
|
3401
|
-
top: position.top,
|
|
3402
|
-
left: position.left
|
|
3403
|
-
},
|
|
3404
|
-
matchTriggerWidth && triggerWidth ? { width: triggerWidth } : null,
|
|
3405
|
-
contentStyle
|
|
3406
|
-
],
|
|
3407
|
-
testID: "select-popover",
|
|
3408
|
-
children
|
|
3409
|
-
})]
|
|
3410
|
-
})
|
|
3411
|
-
});
|
|
3412
|
-
};
|
|
3413
|
-
SelectPopover.displayName = "Select.Popover";
|
|
3414
|
-
//#endregion
|
|
3415
|
-
//#region src/components/Select/Presentation/SelectSheet.tsx
|
|
3416
|
-
const SelectSheet = ({ visible, onClose, dismissOnBackdropPress, contentStyle, children }) => {
|
|
3417
|
-
const styles = useThemeStyles(createPresentationStyles);
|
|
3418
|
-
return /* @__PURE__ */ jsx(Modal$1, {
|
|
3419
|
-
transparent: true,
|
|
3420
|
-
visible,
|
|
3421
|
-
animationType: "slide",
|
|
3422
|
-
onRequestClose: onClose,
|
|
3423
|
-
children: /* @__PURE__ */ jsxs(View, {
|
|
3424
|
-
style: [styles.modalRoot, styles.sheetRoot],
|
|
3425
|
-
testID: "select-content-root",
|
|
3426
|
-
children: [/* @__PURE__ */ jsx(SelectBackdrop, {
|
|
3427
|
-
onClose,
|
|
3428
|
-
dismissOnBackdropPress
|
|
3429
|
-
}), /* @__PURE__ */ jsxs(View, {
|
|
3430
|
-
style: [
|
|
3431
|
-
styles.content,
|
|
3432
|
-
styles.sheet,
|
|
3433
|
-
contentStyle
|
|
3434
|
-
],
|
|
3435
|
-
testID: "select-sheet",
|
|
3436
|
-
children: [/* @__PURE__ */ jsx(SelectHandle, {}), children]
|
|
3437
|
-
})]
|
|
3438
|
-
})
|
|
3439
|
-
});
|
|
3440
|
-
};
|
|
3441
|
-
SelectSheet.displayName = "Select.Sheet";
|
|
3442
|
-
//#endregion
|
|
3443
|
-
//#region src/components/Select/Content/SelectContent.styles.ts
|
|
3444
|
-
const createContentStyles = (theme) => StyleSheet.create({
|
|
3445
|
-
toolbar: {
|
|
3446
|
-
minHeight: 52,
|
|
3447
|
-
flexDirection: "row",
|
|
3448
|
-
alignItems: "center",
|
|
3449
|
-
justifyContent: "space-between",
|
|
3450
|
-
paddingHorizontal: theme.tokens.spacing[4],
|
|
3451
|
-
borderBottomColor: theme.components.select.dropdown.separator.bg,
|
|
3452
|
-
borderBottomWidth: 1
|
|
3453
|
-
},
|
|
3454
|
-
title: {
|
|
3455
|
-
flex: 1,
|
|
3456
|
-
marginHorizontal: theme.tokens.spacing[3],
|
|
3457
|
-
color: theme.components.select.dropdown.fg,
|
|
3458
|
-
fontFamily: theme.tokens.typography.family.medium,
|
|
3459
|
-
fontSize: theme.tokens.typography.size.md,
|
|
3460
|
-
lineHeight: theme.tokens.typography.lineHeight.md,
|
|
3461
|
-
textAlign: "center"
|
|
3462
|
-
},
|
|
3463
|
-
toolbarAction: {
|
|
3464
|
-
minWidth: 64,
|
|
3465
|
-
minHeight: 44,
|
|
3466
|
-
alignItems: "center",
|
|
3467
|
-
justifyContent: "center"
|
|
3468
|
-
},
|
|
3469
|
-
cancelText: {
|
|
3470
|
-
color: theme.components.select.trigger.placeholder.fg,
|
|
3471
|
-
fontFamily: theme.tokens.typography.family.medium,
|
|
3472
|
-
fontSize: theme.tokens.typography.size.md,
|
|
3473
|
-
lineHeight: theme.tokens.typography.lineHeight.md
|
|
3474
|
-
},
|
|
3475
|
-
doneText: {
|
|
3476
|
-
color: theme.semantic.text.interactive,
|
|
3477
|
-
fontFamily: theme.tokens.typography.family.medium,
|
|
3478
|
-
fontSize: theme.tokens.typography.size.md,
|
|
3479
|
-
lineHeight: theme.tokens.typography.lineHeight.md
|
|
3480
|
-
},
|
|
3481
|
-
list: { maxHeight: 420 },
|
|
3482
|
-
listContent: {
|
|
3483
|
-
paddingHorizontal: theme.tokens.spacing[2],
|
|
3484
|
-
paddingVertical: theme.tokens.spacing[2]
|
|
3485
|
-
},
|
|
3486
|
-
empty: {
|
|
3487
|
-
minHeight: 72,
|
|
3488
|
-
alignItems: "center",
|
|
3489
|
-
justifyContent: "center",
|
|
3490
|
-
padding: theme.tokens.spacing[4]
|
|
3491
|
-
},
|
|
3492
|
-
emptyText: {
|
|
3493
|
-
color: theme.components.select.dropdown.empty.fg,
|
|
3494
|
-
fontFamily: theme.tokens.typography.family.regular,
|
|
3495
|
-
fontSize: theme.tokens.typography.size.md,
|
|
3496
|
-
lineHeight: theme.tokens.typography.lineHeight.md,
|
|
3497
|
-
textAlign: "center"
|
|
3498
|
-
},
|
|
3499
|
-
loading: {
|
|
3500
|
-
minHeight: 72,
|
|
3501
|
-
flexDirection: "row",
|
|
3502
|
-
alignItems: "center",
|
|
3503
|
-
justifyContent: "center",
|
|
3504
|
-
gap: theme.tokens.spacing[2],
|
|
3505
|
-
padding: theme.tokens.spacing[4]
|
|
3506
|
-
},
|
|
3507
|
-
loadingText: {
|
|
3508
|
-
color: theme.components.select.dropdown.fg,
|
|
3509
|
-
fontFamily: theme.tokens.typography.family.regular,
|
|
3510
|
-
fontSize: theme.tokens.typography.size.md,
|
|
3511
|
-
lineHeight: theme.tokens.typography.lineHeight.md
|
|
3512
|
-
}
|
|
3513
|
-
});
|
|
3514
|
-
//#endregion
|
|
3515
|
-
//#region src/components/Select/Content/SelectEmpty.tsx
|
|
3516
|
-
const renderText$1 = (node, style) => {
|
|
3517
|
-
if (typeof node === "string" || typeof node === "number") return /* @__PURE__ */ jsx(Text, {
|
|
3518
|
-
style,
|
|
3519
|
-
children: node
|
|
3520
|
-
});
|
|
3521
|
-
return node;
|
|
3522
|
-
};
|
|
3523
|
-
const SelectEmpty = createSelectSlot("empty", "Select.Empty");
|
|
3524
|
-
const SelectEmptyState = () => {
|
|
3525
|
-
const styles = useThemeStyles(createContentStyles);
|
|
3526
|
-
const { empty } = useSelectContext();
|
|
3527
|
-
return /* @__PURE__ */ jsx(View, {
|
|
3528
|
-
style: styles.empty,
|
|
3529
|
-
children: renderText$1(empty, styles.emptyText)
|
|
3741
|
+
testID: "select-modal",
|
|
3742
|
+
children
|
|
3743
|
+
})]
|
|
3744
|
+
})
|
|
3530
3745
|
});
|
|
3531
3746
|
};
|
|
3532
|
-
|
|
3747
|
+
SelectModal.displayName = "Select.Modal";
|
|
3533
3748
|
//#endregion
|
|
3534
|
-
//#region src/components/Select/
|
|
3535
|
-
const
|
|
3536
|
-
|
|
3537
|
-
|
|
3538
|
-
|
|
3749
|
+
//#region src/components/Select/Presentation/SelectPopover.tsx
|
|
3750
|
+
const SelectPopover = ({ visible, onClose, dismissOnBackdropPress, zIndex, position, onFloatingLayout, matchTriggerWidth, triggerWidth, contentStyle, children }) => {
|
|
3751
|
+
const styles = useThemeStyles(createPresentationStyles);
|
|
3752
|
+
return /* @__PURE__ */ jsx(Modal$1, {
|
|
3753
|
+
transparent: true,
|
|
3754
|
+
visible,
|
|
3755
|
+
animationType: "fade",
|
|
3756
|
+
onRequestClose: onClose,
|
|
3757
|
+
children: /* @__PURE__ */ jsxs(View, {
|
|
3758
|
+
style: [styles.modalRoot, Platform.OS === "web" && { zIndex }],
|
|
3759
|
+
testID: "select-content-root",
|
|
3760
|
+
children: [/* @__PURE__ */ jsx(SelectBackdrop, {
|
|
3761
|
+
onClose,
|
|
3762
|
+
dismissOnBackdropPress
|
|
3763
|
+
}), /* @__PURE__ */ jsx(View, {
|
|
3764
|
+
onLayout: onFloatingLayout,
|
|
3765
|
+
style: [
|
|
3766
|
+
styles.content,
|
|
3767
|
+
styles.popover,
|
|
3768
|
+
{
|
|
3769
|
+
position: "absolute",
|
|
3770
|
+
top: position.top,
|
|
3771
|
+
left: position.left
|
|
3772
|
+
},
|
|
3773
|
+
matchTriggerWidth && triggerWidth ? { width: triggerWidth } : null,
|
|
3774
|
+
contentStyle
|
|
3775
|
+
],
|
|
3776
|
+
testID: "select-popover",
|
|
3777
|
+
children
|
|
3778
|
+
})]
|
|
3779
|
+
})
|
|
3539
3780
|
});
|
|
3540
|
-
return node;
|
|
3541
3781
|
};
|
|
3542
|
-
|
|
3543
|
-
|
|
3544
|
-
|
|
3545
|
-
|
|
3546
|
-
const
|
|
3547
|
-
return /* @__PURE__ */
|
|
3548
|
-
|
|
3549
|
-
|
|
3550
|
-
|
|
3551
|
-
|
|
3552
|
-
|
|
3553
|
-
|
|
3782
|
+
SelectPopover.displayName = "Select.Popover";
|
|
3783
|
+
//#endregion
|
|
3784
|
+
//#region src/components/Select/Presentation/SelectSheet.tsx
|
|
3785
|
+
const SelectSheet = ({ visible, onClose, dismissOnBackdropPress, zIndex, contentStyle, children }) => {
|
|
3786
|
+
const styles = useThemeStyles(createPresentationStyles);
|
|
3787
|
+
return /* @__PURE__ */ jsx(Modal$1, {
|
|
3788
|
+
transparent: true,
|
|
3789
|
+
visible,
|
|
3790
|
+
animationType: "slide",
|
|
3791
|
+
onRequestClose: onClose,
|
|
3792
|
+
children: /* @__PURE__ */ jsxs(View, {
|
|
3793
|
+
style: [
|
|
3794
|
+
styles.modalRoot,
|
|
3795
|
+
styles.sheetRoot,
|
|
3796
|
+
Platform.OS === "web" && { zIndex }
|
|
3797
|
+
],
|
|
3798
|
+
testID: "select-content-root",
|
|
3799
|
+
children: [/* @__PURE__ */ jsx(SelectBackdrop, {
|
|
3800
|
+
onClose,
|
|
3801
|
+
dismissOnBackdropPress
|
|
3802
|
+
}), /* @__PURE__ */ jsxs(View, {
|
|
3803
|
+
style: [
|
|
3804
|
+
styles.content,
|
|
3805
|
+
styles.sheet,
|
|
3806
|
+
contentStyle
|
|
3807
|
+
],
|
|
3808
|
+
testID: "select-sheet",
|
|
3809
|
+
children: [/* @__PURE__ */ jsx(SelectHandle, {}), children]
|
|
3810
|
+
})]
|
|
3811
|
+
})
|
|
3554
3812
|
});
|
|
3555
3813
|
};
|
|
3556
|
-
|
|
3814
|
+
SelectSheet.displayName = "Select.Sheet";
|
|
3557
3815
|
//#endregion
|
|
3558
|
-
//#region src/components/Select/
|
|
3816
|
+
//#region src/components/Select/Search/SelectSearch.styles.ts
|
|
3559
3817
|
const createSearchStyles = (theme) => StyleSheet.create({
|
|
3560
3818
|
searchWrap: {
|
|
3561
3819
|
flexDirection: "row",
|
|
@@ -3597,7 +3855,7 @@ const createSearchStyles = (theme) => StyleSheet.create({
|
|
|
3597
3855
|
}
|
|
3598
3856
|
});
|
|
3599
3857
|
//#endregion
|
|
3600
|
-
//#region src/components/Select/
|
|
3858
|
+
//#region src/components/Select/Search/SelectSearch.tsx
|
|
3601
3859
|
const SelectSearch = createSelectSlot("search", "Select.Search");
|
|
3602
3860
|
const SelectSearchField = () => {
|
|
3603
3861
|
const { theme } = useTheme();
|
|
@@ -3652,6 +3910,13 @@ const SelectSearchField = () => {
|
|
|
3652
3910
|
};
|
|
3653
3911
|
SelectSearchField.displayName = "Select.SearchField";
|
|
3654
3912
|
//#endregion
|
|
3913
|
+
//#region src/components/Select/Separator/SelectSeparator.tsx
|
|
3914
|
+
const SelectSeparator = createSelectSlot("separator", "Select.Separator");
|
|
3915
|
+
const SelectSeparatorRow = () => {
|
|
3916
|
+
return /* @__PURE__ */ jsx(View, { style: useThemeStyles(createGroupStyles).separator });
|
|
3917
|
+
};
|
|
3918
|
+
SelectSeparatorRow.displayName = "Select.SeparatorRow";
|
|
3919
|
+
//#endregion
|
|
3655
3920
|
//#region src/components/Select/Content/SelectContent.tsx
|
|
3656
3921
|
const SelectContent = createSelectSlot("content", "Select.Content");
|
|
3657
3922
|
const SelectContentSurface = () => {
|
|
@@ -3659,7 +3924,7 @@ const SelectContentSurface = () => {
|
|
|
3659
3924
|
const wasOpenRef = useRef(false);
|
|
3660
3925
|
const [openCycle, setOpenCycle] = useState(0);
|
|
3661
3926
|
const context = useSelectContext();
|
|
3662
|
-
const { isOpen, resolvedPresentation, position, onFloatingLayout, dismissOnBackdropPress, contentStyle, matchTriggerWidth, triggerWidth, resolvedLabel, closeContent, searchable, loading, filteredRows, selectedValues, selectedOptions, maxSelected, optionStyle, selectOption, selectGroup, itemHeight, selectedRowIndex, query } = context;
|
|
3927
|
+
const { isOpen, resolvedPresentation, zIndex, position, onFloatingLayout, dismissOnBackdropPress, contentStyle, matchTriggerWidth, triggerWidth, resolvedLabel, closeContent, searchable, loading, filteredRows, selectedValues, selectedOptions, maxSelected, optionStyle, selectOption, selectGroup, itemHeight, selectedRowIndex, query } = context;
|
|
3663
3928
|
const initialScrollIndex = Boolean(context.virtual) && selectedRowIndex > 0 && query === "" ? selectedRowIndex : void 0;
|
|
3664
3929
|
useEffect(() => {
|
|
3665
3930
|
if (isOpen && !wasOpenRef.current) setOpenCycle((cycle) => cycle + 1);
|
|
@@ -3750,6 +4015,7 @@ const SelectContentSurface = () => {
|
|
|
3750
4015
|
visible: isOpen,
|
|
3751
4016
|
onClose: closeContent,
|
|
3752
4017
|
dismissOnBackdropPress,
|
|
4018
|
+
zIndex,
|
|
3753
4019
|
contentStyle,
|
|
3754
4020
|
children: body
|
|
3755
4021
|
});
|
|
@@ -3758,6 +4024,7 @@ const SelectContentSurface = () => {
|
|
|
3758
4024
|
onClose: closeContent,
|
|
3759
4025
|
dismissOnBackdropPress,
|
|
3760
4026
|
position,
|
|
4027
|
+
zIndex,
|
|
3761
4028
|
onFloatingLayout,
|
|
3762
4029
|
matchTriggerWidth,
|
|
3763
4030
|
triggerWidth,
|
|
@@ -3768,26 +4035,29 @@ const SelectContentSurface = () => {
|
|
|
3768
4035
|
visible: isOpen,
|
|
3769
4036
|
onClose: closeContent,
|
|
3770
4037
|
dismissOnBackdropPress,
|
|
4038
|
+
zIndex,
|
|
3771
4039
|
contentStyle,
|
|
3772
4040
|
children: body
|
|
3773
4041
|
});
|
|
3774
4042
|
};
|
|
3775
4043
|
SelectContentSurface.displayName = "Select.ContentSurface";
|
|
3776
4044
|
//#endregion
|
|
3777
|
-
//#region src/components/Select/
|
|
3778
|
-
const
|
|
3779
|
-
|
|
3780
|
-
|
|
3781
|
-
|
|
3782
|
-
|
|
3783
|
-
|
|
3784
|
-
|
|
3785
|
-
|
|
3786
|
-
|
|
3787
|
-
|
|
3788
|
-
|
|
4045
|
+
//#region src/components/Select/Icon/SelectIcon.tsx
|
|
4046
|
+
const SelectIcon = createSelectSlot("icon", "Select.Icon");
|
|
4047
|
+
//#endregion
|
|
4048
|
+
//#region src/components/Select/ItemBadge/SelectItemBadge.tsx
|
|
4049
|
+
const SelectItemBadge = createSelectSlot("itemBadge", "Select.ItemBadge");
|
|
4050
|
+
//#endregion
|
|
4051
|
+
//#region src/components/Select/ItemDescription/SelectItemDescription.tsx
|
|
4052
|
+
const SelectItemDescription = createSelectSlot("itemDescription", "Select.ItemDescription");
|
|
4053
|
+
//#endregion
|
|
4054
|
+
//#region src/components/Select/ItemIcon/SelectItemIcon.tsx
|
|
4055
|
+
const SelectItemIcon = createSelectSlot("itemIcon", "Select.ItemIcon");
|
|
4056
|
+
//#endregion
|
|
4057
|
+
//#region src/components/Select/Label/SelectLabel.tsx
|
|
4058
|
+
const SelectLabel = createSelectSlot("label", "Select.Label");
|
|
3789
4059
|
//#endregion
|
|
3790
|
-
//#region src/
|
|
4060
|
+
//#region src/hooks/behavior/select/useSelectCollection.ts
|
|
3791
4061
|
const useSelectCollection = (children, optionsProp) => {
|
|
3792
4062
|
const parsedChildren = useMemo(() => parseSelectChildren(children), [children]);
|
|
3793
4063
|
const options = useMemo(() => [...optionsProp ?? [], ...parsedChildren.options], [optionsProp, parsedChildren.options]);
|
|
@@ -3808,7 +4078,7 @@ const useSelectCollection = (children, optionsProp) => {
|
|
|
3808
4078
|
};
|
|
3809
4079
|
};
|
|
3810
4080
|
//#endregion
|
|
3811
|
-
//#region src/
|
|
4081
|
+
//#region src/hooks/behavior/select/useSelectSearch.ts
|
|
3812
4082
|
const useSelectSearch = ({ rows, isOpen, searchable, searchableFromChildren, onSearch, filterOptions, filter = defaultSelectFilter }) => {
|
|
3813
4083
|
const [query, setQuery] = useState("");
|
|
3814
4084
|
const shouldSearch = searchable ?? searchableFromChildren ?? Boolean(onSearch);
|
|
@@ -3863,8 +4133,18 @@ const useSelectSearch = ({ rows, isOpen, searchable, searchableFromChildren, onS
|
|
|
3863
4133
|
};
|
|
3864
4134
|
};
|
|
3865
4135
|
//#endregion
|
|
3866
|
-
//#region src/components/Select/
|
|
3867
|
-
const
|
|
4136
|
+
//#region src/components/Select/internal/resolveSelectAccessibility.ts
|
|
4137
|
+
const resolveSelectAccessibility = ({ accessibilityLabel, accessibilityHint, label, description, error, invalid, placeholder, selectedLabel, hasFieldContext, fieldDescribedBy }) => {
|
|
4138
|
+
const descriptionText = typeof description === "string" || typeof description === "number" ? String(description) : void 0;
|
|
4139
|
+
const errorText = typeof error === "string" || typeof error === "number" ? String(error) : void 0;
|
|
4140
|
+
return {
|
|
4141
|
+
resolvedLabel: accessibilityLabel ?? label ?? selectedLabel ?? placeholder ?? "Select",
|
|
4142
|
+
resolvedHint: accessibilityHint ?? (invalid && errorText ? errorText : descriptionText ? descriptionText : hasFieldContext && fieldDescribedBy ? "Opens a list of options" : void 0),
|
|
4143
|
+
announce: (message) => {
|
|
4144
|
+
AccessibilityInfo.announceForAccessibility?.(message);
|
|
4145
|
+
}
|
|
4146
|
+
};
|
|
4147
|
+
};
|
|
3868
4148
|
//#endregion
|
|
3869
4149
|
//#region src/components/Select/Trigger/SelectTrigger.styles.ts
|
|
3870
4150
|
const createTriggerStyles = (theme) => StyleSheet.create({
|
|
@@ -3961,9 +4241,9 @@ const createTriggerStyles = (theme) => StyleSheet.create({
|
|
|
3961
4241
|
//#endregion
|
|
3962
4242
|
//#region src/components/Select/Trigger/SelectTrigger.tsx
|
|
3963
4243
|
const SelectTriggerSlot = createSelectSlot("trigger", "Select.Trigger");
|
|
3964
|
-
const nativePointerEventsNone$
|
|
4244
|
+
const nativePointerEventsNone$2 = Platform.OS === "web" ? void 0 : { pointerEvents: "none" };
|
|
3965
4245
|
const nativePointerEventsBoxNone = Platform.OS === "web" ? void 0 : { pointerEvents: "box-none" };
|
|
3966
|
-
const webPointerEventsNone$
|
|
4246
|
+
const webPointerEventsNone$2 = Platform.OS === "web" ? { pointerEvents: "none" } : void 0;
|
|
3967
4247
|
const webPointerEventsBoxNone = Platform.OS === "web" ? { pointerEvents: "box-none" } : void 0;
|
|
3968
4248
|
function SelectTrigger({ displayText, isPlaceholder, isOpen, size = "md", color = "primary", variant = "outline", disabled = false, required = false, hasError = false, hasValue = false, loading = false, clearable = false, startIcon, endIcon, prefix, suffix, accessibilityLabel, accessibilityHint, nativeID, accessibilityLabelledBy, ariaDescribedBy, triggerStyle, textStyle, onPress, onClear }) {
|
|
3969
4249
|
const { theme } = useTheme();
|
|
@@ -4058,8 +4338,8 @@ function SelectTrigger({ displayText, isPlaceholder, isOpen, size = "md", color
|
|
|
4058
4338
|
],
|
|
4059
4339
|
children: [
|
|
4060
4340
|
startIcon && /* @__PURE__ */ jsx(View, {
|
|
4061
|
-
...nativePointerEventsNone$
|
|
4062
|
-
style: [styles.startIcon, webPointerEventsNone$
|
|
4341
|
+
...nativePointerEventsNone$2,
|
|
4342
|
+
style: [styles.startIcon, webPointerEventsNone$2],
|
|
4063
4343
|
accessibilityElementsHidden: true,
|
|
4064
4344
|
importantForAccessibility: "no",
|
|
4065
4345
|
children: renderIcon(startIcon)
|
|
@@ -4081,8 +4361,8 @@ function SelectTrigger({ displayText, isPlaceholder, isOpen, size = "md", color
|
|
|
4081
4361
|
size: "small",
|
|
4082
4362
|
color: iconColor
|
|
4083
4363
|
}) : showClearButton ? null : endIcon ? /* @__PURE__ */ jsx(View, {
|
|
4084
|
-
...nativePointerEventsNone$
|
|
4085
|
-
style: [styles.endIcon, webPointerEventsNone$
|
|
4364
|
+
...nativePointerEventsNone$2,
|
|
4365
|
+
style: [styles.endIcon, webPointerEventsNone$2],
|
|
4086
4366
|
accessibilityElementsHidden: true,
|
|
4087
4367
|
importantForAccessibility: "no",
|
|
4088
4368
|
children: renderIcon(endIcon)
|
|
@@ -4121,9 +4401,6 @@ function SelectTrigger({ displayText, isPlaceholder, isOpen, size = "md", color
|
|
|
4121
4401
|
}
|
|
4122
4402
|
SelectTrigger.displayName = "SelectTrigger";
|
|
4123
4403
|
//#endregion
|
|
4124
|
-
//#region src/components/Select/Trigger/SelectValue.tsx
|
|
4125
|
-
const SelectValue = createSelectSlot("value", "Select.Value");
|
|
4126
|
-
//#endregion
|
|
4127
4404
|
//#region src/components/Select/Root/SelectRoot.tsx
|
|
4128
4405
|
function SelectRoot(props) {
|
|
4129
4406
|
const { label, description, error, invalid = false, required = false, disabled = false, placeholder = "Select...", color = "primary", variant = "outline", size, open, defaultOpen, onOpenChange, clearable = false, searchable: searchableProp, searchPlaceholder, loading = false, loadingText = "Loading...", onSearch, filterOptions, filter, empty, startIcon, endIcon, prefix, suffix, renderValue, renderOption, closeOnSelect, maxSelected, presentation = "auto", placement = "bottom-start", offset = 8, matchTriggerWidth = false, dismissOnBackdropPress = true, virtual, options: optionsProp, children, style, triggerStyle, textStyle, contentStyle, optionStyle, searchStyle, accessibilityLabel, accessibilityHint, testID } = props;
|
|
@@ -4132,7 +4409,7 @@ function SelectRoot(props) {
|
|
|
4132
4409
|
const hasOwnField = Boolean(label || description || error);
|
|
4133
4410
|
const [triggerWidth, setTriggerWidth] = useState();
|
|
4134
4411
|
const triggerRef = useRef(null);
|
|
4135
|
-
const { position,
|
|
4412
|
+
const { position, onFloatingLayout } = useNativeFloatingPosition(placement, offset);
|
|
4136
4413
|
const searchInputRef = useRef(null);
|
|
4137
4414
|
const selectedFocusValueRef = useRef(void 0);
|
|
4138
4415
|
const resolvedPresentation = useOverlayPresentation(presentation);
|
|
@@ -4160,7 +4437,18 @@ function SelectRoot(props) {
|
|
|
4160
4437
|
defaultOpen,
|
|
4161
4438
|
onOpenChange
|
|
4162
4439
|
});
|
|
4163
|
-
const
|
|
4440
|
+
const { restoreFocusAfterClose } = useOverlayFocusRestore({
|
|
4441
|
+
active: isOpen,
|
|
4442
|
+
triggerRef
|
|
4443
|
+
});
|
|
4444
|
+
const closeAndFocusTrigger = useCallback(() => {
|
|
4445
|
+
closeDropdown();
|
|
4446
|
+
restoreFocusAfterClose();
|
|
4447
|
+
}, [closeDropdown, restoreFocusAfterClose]);
|
|
4448
|
+
const selectedValues = useMemo(() => {
|
|
4449
|
+
if (props.multiple) return Array.isArray(selectedValue) ? selectedValue : [];
|
|
4450
|
+
return typeof selectedValue === "string" && selectedValue ? [selectedValue] : [];
|
|
4451
|
+
}, [props.multiple, selectedValue]);
|
|
4164
4452
|
const selectedOption = options.find((option) => selectedValues.includes(option.value));
|
|
4165
4453
|
const selectedOptions = options.filter((option) => selectedValues.includes(option.value));
|
|
4166
4454
|
const optionsByValue = useMemo(() => new Map(options.filter((option) => !option.disabled).map((option) => [option.value, option])), [options]);
|
|
@@ -4193,7 +4481,7 @@ function SelectRoot(props) {
|
|
|
4193
4481
|
selectedOption,
|
|
4194
4482
|
selectedOptions
|
|
4195
4483
|
]);
|
|
4196
|
-
const { resolvedLabel, resolvedHint, announce } =
|
|
4484
|
+
const { resolvedLabel, resolvedHint, announce } = resolveSelectAccessibility({
|
|
4197
4485
|
accessibilityLabel,
|
|
4198
4486
|
accessibilityHint,
|
|
4199
4487
|
label: !hasOwnField ? void 0 : label,
|
|
@@ -4210,22 +4498,28 @@ function SelectRoot(props) {
|
|
|
4210
4498
|
id: overlayId,
|
|
4211
4499
|
active: isOpen,
|
|
4212
4500
|
closeOnOutsidePress: dismissOnBackdropPress,
|
|
4213
|
-
requestClose:
|
|
4501
|
+
requestClose: closeAndFocusTrigger
|
|
4214
4502
|
});
|
|
4215
4503
|
const clearValue = () => {
|
|
4216
4504
|
selectedFocusValueRef.current = void 0;
|
|
4217
4505
|
selectValue("");
|
|
4218
4506
|
announce("Selection cleared");
|
|
4219
4507
|
};
|
|
4220
|
-
const selectOption = (option) => {
|
|
4508
|
+
const selectOption = useCallback((option) => {
|
|
4221
4509
|
if (option.disabled) return;
|
|
4222
4510
|
const selectedBefore = selectedValues.includes(option.value);
|
|
4223
4511
|
if (Boolean(props.multiple) && !selectedBefore && typeof maxSelected === "number" && selectedValues.length >= maxSelected) return;
|
|
4224
4512
|
selectedFocusValueRef.current = option.value;
|
|
4225
4513
|
selectValue(option.value);
|
|
4226
4514
|
announce(`${option.label} selected`);
|
|
4227
|
-
}
|
|
4228
|
-
|
|
4515
|
+
}, [
|
|
4516
|
+
announce,
|
|
4517
|
+
maxSelected,
|
|
4518
|
+
props.multiple,
|
|
4519
|
+
selectValue,
|
|
4520
|
+
selectedValues
|
|
4521
|
+
]);
|
|
4522
|
+
const selectGroup = useCallback((values) => {
|
|
4229
4523
|
if (!props.multiple || values.length === 0) return;
|
|
4230
4524
|
const enabledValues = values.filter((value) => optionsByValue.has(value));
|
|
4231
4525
|
const selectedGroupValues = enabledValues.filter((value) => selectedValues.includes(value));
|
|
@@ -4246,32 +4540,32 @@ function SelectRoot(props) {
|
|
|
4246
4540
|
setSelectedValue(nextValues);
|
|
4247
4541
|
selectedFocusValueRef.current = nextValues.at(-1);
|
|
4248
4542
|
announce("Group selected");
|
|
4249
|
-
if (closeOnSelect)
|
|
4250
|
-
}
|
|
4251
|
-
|
|
4252
|
-
|
|
4253
|
-
|
|
4254
|
-
|
|
4255
|
-
|
|
4256
|
-
|
|
4257
|
-
|
|
4258
|
-
|
|
4259
|
-
|
|
4543
|
+
if (closeOnSelect) closeAndFocusTrigger();
|
|
4544
|
+
}, [
|
|
4545
|
+
announce,
|
|
4546
|
+
closeAndFocusTrigger,
|
|
4547
|
+
closeOnSelect,
|
|
4548
|
+
maxSelected,
|
|
4549
|
+
optionsByValue,
|
|
4550
|
+
props.multiple,
|
|
4551
|
+
selectedValues,
|
|
4552
|
+
setSelectedValue
|
|
4553
|
+
]);
|
|
4554
|
+
const resolvedSearchPlaceholder = searchPlaceholder ?? searchPlaceholderFromChildren ?? "Search...";
|
|
4555
|
+
const resolvedEmpty = empty ?? emptyFromChildren ?? "Nothing found";
|
|
4556
|
+
const resolvedLoadingContent = loadingFromChildren ?? loadingText;
|
|
4557
|
+
const contextValue = useMemo(() => ({
|
|
4260
4558
|
color,
|
|
4261
4559
|
variant,
|
|
4262
|
-
size: resolvedSize,
|
|
4263
4560
|
isOpen,
|
|
4264
|
-
hasValue,
|
|
4265
4561
|
loading,
|
|
4266
|
-
clearable,
|
|
4267
4562
|
searchable: shouldSearch,
|
|
4268
4563
|
multiple: Boolean(props.multiple),
|
|
4269
4564
|
maxSelected,
|
|
4270
4565
|
virtual,
|
|
4271
4566
|
resolvedLabel,
|
|
4272
|
-
resolvedHint,
|
|
4273
4567
|
resolvedPresentation,
|
|
4274
|
-
|
|
4568
|
+
zIndex: dismiss.zIndex,
|
|
4275
4569
|
position,
|
|
4276
4570
|
onFloatingLayout,
|
|
4277
4571
|
dismissOnBackdropPress,
|
|
@@ -4280,36 +4574,59 @@ function SelectRoot(props) {
|
|
|
4280
4574
|
selectedValues,
|
|
4281
4575
|
selectedOptions,
|
|
4282
4576
|
optionsByValue,
|
|
4283
|
-
rows,
|
|
4284
4577
|
filteredRows,
|
|
4285
4578
|
selectedRowIndex,
|
|
4286
4579
|
itemHeight,
|
|
4287
4580
|
query,
|
|
4288
|
-
searchPlaceholder:
|
|
4581
|
+
searchPlaceholder: resolvedSearchPlaceholder,
|
|
4289
4582
|
searchInputRef,
|
|
4290
|
-
empty:
|
|
4291
|
-
loadingContent:
|
|
4583
|
+
empty: resolvedEmpty,
|
|
4584
|
+
loadingContent: resolvedLoadingContent,
|
|
4292
4585
|
closeContent: dismiss.requestClose,
|
|
4293
|
-
openContent,
|
|
4294
|
-
clearValue,
|
|
4295
4586
|
selectOption,
|
|
4296
4587
|
selectGroup,
|
|
4297
4588
|
setQuery,
|
|
4298
|
-
renderValue,
|
|
4299
4589
|
renderOption,
|
|
4300
|
-
startIcon,
|
|
4301
|
-
endIcon,
|
|
4302
|
-
prefix,
|
|
4303
|
-
suffix,
|
|
4304
|
-
triggerStyle,
|
|
4305
|
-
textStyle,
|
|
4306
4590
|
contentStyle,
|
|
4307
4591
|
optionStyle,
|
|
4308
|
-
searchStyle
|
|
4309
|
-
|
|
4310
|
-
|
|
4311
|
-
|
|
4312
|
-
|
|
4592
|
+
searchStyle
|
|
4593
|
+
}), [
|
|
4594
|
+
color,
|
|
4595
|
+
variant,
|
|
4596
|
+
isOpen,
|
|
4597
|
+
loading,
|
|
4598
|
+
shouldSearch,
|
|
4599
|
+
props.multiple,
|
|
4600
|
+
maxSelected,
|
|
4601
|
+
virtual,
|
|
4602
|
+
resolvedLabel,
|
|
4603
|
+
resolvedPresentation,
|
|
4604
|
+
dismiss.zIndex,
|
|
4605
|
+
position,
|
|
4606
|
+
onFloatingLayout,
|
|
4607
|
+
dismissOnBackdropPress,
|
|
4608
|
+
matchTriggerWidth,
|
|
4609
|
+
triggerWidth,
|
|
4610
|
+
selectedValues,
|
|
4611
|
+
selectedOptions,
|
|
4612
|
+
optionsByValue,
|
|
4613
|
+
filteredRows,
|
|
4614
|
+
selectedRowIndex,
|
|
4615
|
+
itemHeight,
|
|
4616
|
+
query,
|
|
4617
|
+
resolvedSearchPlaceholder,
|
|
4618
|
+
searchInputRef,
|
|
4619
|
+
resolvedEmpty,
|
|
4620
|
+
resolvedLoadingContent,
|
|
4621
|
+
dismiss.requestClose,
|
|
4622
|
+
selectOption,
|
|
4623
|
+
selectGroup,
|
|
4624
|
+
setQuery,
|
|
4625
|
+
renderOption,
|
|
4626
|
+
contentStyle,
|
|
4627
|
+
optionStyle,
|
|
4628
|
+
searchStyle
|
|
4629
|
+
]);
|
|
4313
4630
|
const control = /* @__PURE__ */ jsx(SelectContext.Provider, {
|
|
4314
4631
|
value: contextValue,
|
|
4315
4632
|
children: /* @__PURE__ */ jsxs(View, {
|
|
@@ -4360,6 +4677,9 @@ function SelectRoot(props) {
|
|
|
4360
4677
|
}
|
|
4361
4678
|
SelectRoot.displayName = "Select";
|
|
4362
4679
|
//#endregion
|
|
4680
|
+
//#region src/components/Select/Value/SelectValue.tsx
|
|
4681
|
+
const SelectValue = createSelectSlot("value", "Select.Value");
|
|
4682
|
+
//#endregion
|
|
4363
4683
|
//#region src/components/Select/Select.tsx
|
|
4364
4684
|
const Select = Object.assign(SelectRoot, {
|
|
4365
4685
|
Trigger: SelectTriggerSlot,
|
|
@@ -4378,7 +4698,7 @@ const Select = Object.assign(SelectRoot, {
|
|
|
4378
4698
|
Loading: SelectLoading
|
|
4379
4699
|
});
|
|
4380
4700
|
//#endregion
|
|
4381
|
-
//#region src/components/Tabs/TabsContext.tsx
|
|
4701
|
+
//#region src/components/Tabs/internal/TabsContext.tsx
|
|
4382
4702
|
const TabsContext = createContext(null);
|
|
4383
4703
|
const TabsProvider = TabsContext.Provider;
|
|
4384
4704
|
const useTabs = () => {
|
|
@@ -4441,8 +4761,8 @@ const COLLAPSED_SIZE = 8;
|
|
|
4441
4761
|
const LINE_ANIMATION_DURATION = 360;
|
|
4442
4762
|
const SURFACE_ANIMATION_DURATION = 220;
|
|
4443
4763
|
const easing = Easing?.bezier?.(.22, 1, .36, 1) ?? ((value) => value);
|
|
4444
|
-
const nativePointerEventsNone$
|
|
4445
|
-
const webPointerEventsNone$
|
|
4764
|
+
const nativePointerEventsNone$1 = Platform.OS === "web" ? void 0 : { pointerEvents: "none" };
|
|
4765
|
+
const webPointerEventsNone$1 = Platform.OS === "web" ? { pointerEvents: "none" } : void 0;
|
|
4446
4766
|
const animateValue = (value, toValue, duration) => Animated.timing(value, {
|
|
4447
4767
|
toValue,
|
|
4448
4768
|
duration,
|
|
@@ -4645,8 +4965,8 @@ const TabsIndicator = ({ children, style }) => {
|
|
|
4645
4965
|
return /* @__PURE__ */ jsx(Animated.View, {
|
|
4646
4966
|
accessibilityElementsHidden: true,
|
|
4647
4967
|
importantForAccessibility: "no-hide-descendants",
|
|
4648
|
-
...nativePointerEventsNone$
|
|
4649
|
-
style: [indicatorStyle, webPointerEventsNone$
|
|
4968
|
+
...nativePointerEventsNone$1,
|
|
4969
|
+
style: [indicatorStyle, webPointerEventsNone$1],
|
|
4650
4970
|
children
|
|
4651
4971
|
});
|
|
4652
4972
|
};
|
|
@@ -5148,13 +5468,45 @@ const useTooltipContext = () => {
|
|
|
5148
5468
|
};
|
|
5149
5469
|
TooltipContext.displayName = "TooltipContext";
|
|
5150
5470
|
//#endregion
|
|
5471
|
+
//#region src/components/Tooltip/Arrow/TooltipArrow.tsx
|
|
5472
|
+
function TooltipArrow() {
|
|
5473
|
+
const { theme } = useTheme();
|
|
5474
|
+
const tooltip = useTooltipContext();
|
|
5475
|
+
const size = theme.components.tooltip.arrow.size;
|
|
5476
|
+
const side = tooltip.placement.split("-")[0];
|
|
5477
|
+
const staticSide = {
|
|
5478
|
+
top: "bottom",
|
|
5479
|
+
right: "left",
|
|
5480
|
+
bottom: "top",
|
|
5481
|
+
left: "right"
|
|
5482
|
+
}[side];
|
|
5483
|
+
const crossAxisStyle = side === "left" || side === "right" ? {
|
|
5484
|
+
top: tooltip.arrowPosition.top ?? 0,
|
|
5485
|
+
marginTop: -size / 2
|
|
5486
|
+
} : {
|
|
5487
|
+
left: tooltip.arrowPosition.left ?? 0,
|
|
5488
|
+
marginLeft: -size / 2
|
|
5489
|
+
};
|
|
5490
|
+
return /* @__PURE__ */ jsx(View, {
|
|
5491
|
+
pointerEvents: "none",
|
|
5492
|
+
style: {
|
|
5493
|
+
position: "absolute",
|
|
5494
|
+
width: size,
|
|
5495
|
+
height: size,
|
|
5496
|
+
backgroundColor: theme.components.tooltip.arrow.bg,
|
|
5497
|
+
transform: [{ rotate: "45deg" }],
|
|
5498
|
+
[staticSide]: -size / 2,
|
|
5499
|
+
...crossAxisStyle
|
|
5500
|
+
}
|
|
5501
|
+
});
|
|
5502
|
+
}
|
|
5503
|
+
//#endregion
|
|
5151
5504
|
//#region src/components/Tooltip/Tooltip.styles.ts
|
|
5152
5505
|
const createStyles$3 = (theme) => StyleSheet.create({
|
|
5153
5506
|
root: { alignSelf: "flex-start" },
|
|
5154
5507
|
overlay: { ...StyleSheet.absoluteFill },
|
|
5155
5508
|
bubble: {
|
|
5156
5509
|
position: "absolute",
|
|
5157
|
-
zIndex: 1e3,
|
|
5158
5510
|
maxWidth: theme.components.tooltip.content.maxWidth,
|
|
5159
5511
|
paddingHorizontal: theme.components.tooltip.content.paddingX,
|
|
5160
5512
|
paddingVertical: theme.components.tooltip.content.paddingY,
|
|
@@ -5187,8 +5539,6 @@ const createStyles$3 = (theme) => StyleSheet.create({
|
|
|
5187
5539
|
});
|
|
5188
5540
|
//#endregion
|
|
5189
5541
|
//#region src/components/Tooltip/Content/TooltipContent.tsx
|
|
5190
|
-
const nativePointerEventsNone$1 = Platform.OS === "web" ? void 0 : { pointerEvents: "none" };
|
|
5191
|
-
const webPointerEventsNone$1 = Platform.OS === "web" ? { pointerEvents: "none" } : void 0;
|
|
5192
5542
|
const TooltipContent = ({ children, forceMount = false, withArrow = false, style, textStyle }) => {
|
|
5193
5543
|
const styles = useThemeStyles(createStyles$3);
|
|
5194
5544
|
const tooltip = useTooltipContext();
|
|
@@ -5196,13 +5546,13 @@ const TooltipContent = ({ children, forceMount = false, withArrow = false, style
|
|
|
5196
5546
|
if (!forceMount && !visible) return null;
|
|
5197
5547
|
const bubble = /* @__PURE__ */ jsxs(View, {
|
|
5198
5548
|
nativeID: tooltip.contentId,
|
|
5199
|
-
|
|
5549
|
+
pointerEvents: "none",
|
|
5200
5550
|
style: [
|
|
5201
5551
|
styles.bubble,
|
|
5202
|
-
webPointerEventsNone$1,
|
|
5203
5552
|
{
|
|
5204
5553
|
top: tooltip.position.top,
|
|
5205
|
-
left: tooltip.position.left
|
|
5554
|
+
left: tooltip.position.left,
|
|
5555
|
+
zIndex: tooltip.zIndex
|
|
5206
5556
|
},
|
|
5207
5557
|
!visible && { display: "none" },
|
|
5208
5558
|
style
|
|
@@ -5211,7 +5561,7 @@ const TooltipContent = ({ children, forceMount = false, withArrow = false, style
|
|
|
5211
5561
|
children: [Children.map(children, (child) => typeof child === "string" || typeof child === "number" ? /* @__PURE__ */ jsx(Text, {
|
|
5212
5562
|
style: [styles.text, textStyle],
|
|
5213
5563
|
children: child
|
|
5214
|
-
}) : child), withArrow && /* @__PURE__ */ jsx(
|
|
5564
|
+
}) : child), withArrow && /* @__PURE__ */ jsx(TooltipArrow, {})]
|
|
5215
5565
|
});
|
|
5216
5566
|
if (!visible) return bubble;
|
|
5217
5567
|
return /* @__PURE__ */ jsx(Modal$1, {
|
|
@@ -5227,39 +5577,8 @@ const TooltipContent = ({ children, forceMount = false, withArrow = false, style
|
|
|
5227
5577
|
});
|
|
5228
5578
|
};
|
|
5229
5579
|
TooltipContent.displayName = "Tooltip.Content";
|
|
5230
|
-
function InternalArrow() {
|
|
5231
|
-
const { theme } = useTheme();
|
|
5232
|
-
const tooltip = useTooltipContext();
|
|
5233
|
-
const size = theme.components.tooltip.arrow.size;
|
|
5234
|
-
const side = tooltip.placement.split("-")[0];
|
|
5235
|
-
const staticSide = {
|
|
5236
|
-
top: "bottom",
|
|
5237
|
-
right: "left",
|
|
5238
|
-
bottom: "top",
|
|
5239
|
-
left: "right"
|
|
5240
|
-
}[side];
|
|
5241
|
-
const crossAxisStyle = side === "left" || side === "right" ? {
|
|
5242
|
-
top: tooltip.arrowPosition.top ?? 0,
|
|
5243
|
-
marginTop: -size / 2
|
|
5244
|
-
} : {
|
|
5245
|
-
left: tooltip.arrowPosition.left ?? 0,
|
|
5246
|
-
marginLeft: -size / 2
|
|
5247
|
-
};
|
|
5248
|
-
return /* @__PURE__ */ jsx(View, {
|
|
5249
|
-
...nativePointerEventsNone$1,
|
|
5250
|
-
style: [{
|
|
5251
|
-
position: "absolute",
|
|
5252
|
-
width: size,
|
|
5253
|
-
height: size,
|
|
5254
|
-
backgroundColor: theme.components.tooltip.arrow.bg,
|
|
5255
|
-
transform: [{ rotate: "45deg" }],
|
|
5256
|
-
[staticSide]: -size / 2,
|
|
5257
|
-
...crossAxisStyle
|
|
5258
|
-
}, webPointerEventsNone$1]
|
|
5259
|
-
});
|
|
5260
|
-
}
|
|
5261
5580
|
//#endregion
|
|
5262
|
-
//#region src/components/Tooltip/internal/
|
|
5581
|
+
//#region src/components/Tooltip/internal/resolveTooltipDelay.ts
|
|
5263
5582
|
const resolveTooltipDelay = (delay) => {
|
|
5264
5583
|
if (typeof delay === "number") return {
|
|
5265
5584
|
open: delay,
|
|
@@ -5348,6 +5667,7 @@ const TooltipRoot = ({ children, open: openProp, defaultOpen = false, onOpenChan
|
|
|
5348
5667
|
setOpen,
|
|
5349
5668
|
show,
|
|
5350
5669
|
hide,
|
|
5670
|
+
zIndex: dismiss.zIndex,
|
|
5351
5671
|
requestClose: dismiss.requestClose,
|
|
5352
5672
|
requestOutsideClose: dismiss.requestOutsideClose,
|
|
5353
5673
|
onFloatingLayout
|
|
@@ -5355,6 +5675,7 @@ const TooltipRoot = ({ children, open: openProp, defaultOpen = false, onOpenChan
|
|
|
5355
5675
|
arrowPosition,
|
|
5356
5676
|
contentId,
|
|
5357
5677
|
disabled,
|
|
5678
|
+
dismiss.zIndex,
|
|
5358
5679
|
dismiss.requestClose,
|
|
5359
5680
|
dismiss.requestOutsideClose,
|
|
5360
5681
|
hide,
|