@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.
Files changed (2) hide show
  1. package/dist/index.js +1035 -714
  2. 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/FloatingManager/computeFloatingPosition.ts
27
- function clamp(value, min, max) {
28
- return Math.min(Math.max(value, min), Math.max(min, max));
29
- }
30
- function parsePlacement(placement) {
31
- const [side, align = "center"] = placement.split("-");
32
- return {
33
- side,
34
- align
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
- position,
125
- arrowPosition,
126
- placement: createPlacement(resolvedSide, parsed.align)
127
- };
128
- }
129
- //#endregion
130
- //#region src/managers/FloatingManager/useNativeFloatingPosition.ts
131
- function useNativeFloatingPosition(placement = "top", offset = 8) {
132
- const [result, setResult] = useState({
133
- position: {
134
- top: 0,
135
- left: 0
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
- arrowPosition: {},
138
- placement
139
- });
140
- const floatingSizeRef = useRef({
141
- width: 0,
142
- height: 0
143
- });
144
- const lastTriggerRef = useRef(null);
145
- const lastContainerRef = useRef(null);
146
- const updatePosition = useCallback((triggerRef, containerRef, measuredSize = floatingSizeRef.current) => {
147
- lastTriggerRef.current = triggerRef;
148
- lastContainerRef.current = containerRef ?? null;
149
- const triggerNode = triggerRef.current;
150
- const containerNode = containerRef?.current;
151
- if (!triggerNode || typeof triggerNode.measureInWindow !== "function") {
152
- setResult((current) => ({
153
- ...current,
154
- position: {
155
- top: 0,
156
- left: 0
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
- if (!containerNode || typeof containerNode.measureInWindow !== "function") {
181
- const window = Dimensions.get("window");
182
- commitPosition(0, 0, window.width, window.height);
183
- return;
184
- }
185
- containerNode.measureInWindow((containerX, containerY, containerWidth, containerHeight) => {
186
- commitPosition(containerX, containerY, containerWidth, containerHeight);
187
- });
188
- });
189
- }, [placement, offset]);
190
- const onFloatingLayout = useCallback((event) => {
191
- const { width, height } = event.nativeEvent.layout;
192
- const nextSize = {
193
- width,
194
- height
195
- };
196
- floatingSizeRef.current = nextSize;
197
- if (lastTriggerRef.current) updatePosition(lastTriggerRef.current, lastContainerRef.current ?? void 0, nextSize);
198
- }, [updatePosition]);
199
- return {
200
- position: result.position,
201
- arrowPosition: result.arrowPosition,
202
- placement: result.placement,
203
- updatePosition,
204
- onFloatingLayout
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/useNativeOverlayRegistration.ts
237
- const useNativeOverlayRegistration = ({ id, visible }) => {
238
- const [layer, setLayer] = useState(() => nativeOverlayManager.getLayer(id));
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 (!visible) return;
113
+ if (!active) return;
241
114
  const entry = nativeOverlayManager.register(id);
242
- setLayer(entry.layer);
115
+ setZIndex(entry.zIndex);
243
116
  return () => {
244
117
  nativeOverlayManager.unregister(id);
245
118
  };
246
- }, [id, visible]);
119
+ }, [
120
+ active,
121
+ id,
122
+ nativeOverlayManager
123
+ ]);
247
124
  return {
248
- layer,
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 useOverlayDismiss = ({ active, closeOnEscape = true, closeOnOutsidePress = true, id, requestClose }) => {
261
- const { isTopOverlay } = useOverlayStack({
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 requestOutsideClose = useCallback(() => {
270
- if (!closeOnOutsidePress) return;
271
- requestTopClose();
272
- }, [closeOnOutsidePress, requestTopClose]);
182
+ const requestOutsideTopClose = useCallback(() => {
183
+ nativeOverlayManager.dispatchTopOutsidePress();
184
+ }, [nativeOverlayManager]);
273
185
  useEffect(() => {
274
- if (!active || !closeOnEscape) return;
275
- if (Platform.OS === "web") {
276
- const handleKeyDown = (event) => {
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
- subscription.remove();
215
+ unregisterDismissHandler();
216
+ releaseDismissListener();
292
217
  };
293
218
  }, [
294
219
  active,
295
220
  closeOnEscape,
296
- isTopOverlay,
297
- requestClose,
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
- const useOverlayFocusRestore = ({ enabled = true, triggerRef }) => {
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 triggerNode = triggerRef.current;
313
- if (triggerNode && typeof triggerNode === "object" && "focus" in triggerNode && typeof triggerNode.focus === "function") triggerNode.focus();
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
- }, [enabled, triggerRef]);
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: useCallback(() => {
323
- if (!enabled) return;
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({ isOpen, children, onClose, color = "primary", contentStyle, accessibilityLabel, presentation, position, onFloatingLayout, searchable = false, searchValue = "", searchPlaceholder = "Search actions...", searchAccessibilityLabel, onSearchChange }) {
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(isOpen ? 1 : 0)).current;
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 (!isOpen) {
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
- isOpen,
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: isOpen,
867
+ visible: open,
908
868
  animationType: "none",
909
- onRequestClose: onClose,
869
+ onRequestClose: requestClose,
910
870
  children: /* @__PURE__ */ jsxs(View, {
911
- style: [styles.modalRoot, styles[presentation]],
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: onClose
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, rootColor = "primary", color = "default", icon, disabled = false, textWrap = "truncate", itemStyle, textStyle, onSelect }) {
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, color = "primary", size = "md", disabled = false, isOpen, triggerStyle, triggerRef, accessibilityLabel, accessibilityHint, onPress }) {
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(isOpen ? 1 : 0)).current;
1540
+ const rotateAnim = useRef(new Animated.Value(open ? 1 : 0)).current;
1324
1541
  useEffect(() => {
1325
1542
  Animated.timing(rotateAnim, {
1326
- toValue: isOpen ? 1 : 0,
1543
+ toValue: open ? 1 : 0,
1327
1544
  duration: 180,
1328
1545
  useNativeDriver: Platform.OS !== "web"
1329
1546
  }).start();
1330
- }, [isOpen, rotateAnim]);
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: isOpen,
1583
+ expanded: open,
1367
1584
  disabled: isChildDisabled
1368
1585
  },
1369
1586
  onPress: () => {
1370
1587
  child.props.onPress?.();
1371
- if (!isChildDisabled) onPress();
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: isOpen,
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 = parsed.contentProps?.command ?? false;
1444
- const isSearchable = searchable || command || contentCommand || !!parsed.searchProps;
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
- useEffect(() => {
1484
- if (!isOpen) return;
1485
- AccessibilityInfo.announceForAccessibility(`${menuAccessibilityLabel} opened`);
1486
- }, [isOpen, menuAccessibilityLabel]);
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
- color,
1540
- handleSelect,
1541
- itemStyle,
1542
- styles.emptyText,
1543
- textStyle
1544
- ]);
1545
- const data = loading ? [{
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
- onFloatingLayout,
1759
+ zIndex: dismiss.zIndex,
1581
1760
  searchable: isSearchable,
1582
1761
  searchValue: resolvedSearchValue,
1583
- searchPlaceholder: parsed.searchProps?.placeholder ?? searchPlaceholder ?? (command || contentCommand ? "Type a command..." : "Search actions..."),
1584
- searchAccessibilityLabel: parsed.searchProps?.accessibilityLabel,
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
- children: /* @__PURE__ */ jsx(FlatList, {
1587
- data,
1588
- keyExtractor: (item) => item.id,
1589
- renderItem: renderEntry,
1590
- keyboardShouldPersistTaps: "handled",
1591
- removeClippedSubviews: data.length > 24
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(void 0);
1686
- ModalContext.displayName = "ModalContext";
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: [styles.overlay, overlayStyle],
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(ModalContext.Provider, {
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
- layer: { flex: 1 },
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, setOpen, closeOnOutsidePress } = usePopoverContext("Popover.Content");
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.layer,
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
- }, [setOpenState]);
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: useCallback((containerRef) => {
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$4 = Platform.OS === "web" ? void 0 : { pointerEvents: "none" };
2388
- const webPointerEventsNone$4 = Platform.OS === "web" ? { pointerEvents: "none" } : void 0;
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$4,
2716
+ ...nativePointerEventsNone$3,
2448
2717
  style: [
2449
2718
  styles.control,
2450
- webPointerEventsNone$4,
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$4,
2480
- style: [styles.content, webPointerEventsNone$4],
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/Item/SelectItemBadge.tsx
3273
- const SelectItemBadge = createSelectSlot("itemBadge", "Select.ItemBadge");
3274
- //#endregion
3275
- //#region src/components/Select/Item/SelectItemDescription.tsx
3276
- const SelectItemDescription = createSelectSlot("itemDescription", "Select.ItemDescription");
3277
- //#endregion
3278
- //#region src/components/Select/Item/SelectItemIcon.tsx
3279
- const SelectItemIcon = createSelectSlot("itemIcon", "Select.ItemIcon");
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: [styles.modalRoot, styles.modalPresentationRoot],
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
- SelectEmptyState.displayName = "Select.EmptyState";
3747
+ SelectModal.displayName = "Select.Modal";
3533
3748
  //#endregion
3534
- //#region src/components/Select/Content/SelectLoading.tsx
3535
- const renderText = (node, style) => {
3536
- if (typeof node === "string" || typeof node === "number") return /* @__PURE__ */ jsx(Text, {
3537
- style,
3538
- children: node
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
- const SelectLoading = createSelectSlot("loading", "Select.Loading");
3543
- const SelectLoadingState = () => {
3544
- const { theme } = useTheme();
3545
- const styles = useThemeStyles(createContentStyles);
3546
- const { loadingContent } = useSelectContext();
3547
- return /* @__PURE__ */ jsxs(View, {
3548
- style: styles.loading,
3549
- children: [/* @__PURE__ */ jsx(ActivityIndicator, {
3550
- testID: "select-content-loading-indicator",
3551
- size: "small",
3552
- color: theme.components.select.dropdown.fg
3553
- }), renderText(loadingContent, styles.loadingText)]
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
- SelectLoadingState.displayName = "Select.LoadingState";
3814
+ SelectSheet.displayName = "Select.Sheet";
3557
3815
  //#endregion
3558
- //#region src/components/Select/Content/SelectSearch.styles.ts
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/Content/SelectSearch.tsx
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/internal/useSelectAccessibility.ts
3778
- const useSelectAccessibility = ({ accessibilityLabel, accessibilityHint, label, description, error, invalid, placeholder, selectedLabel, hasFieldContext, fieldDescribedBy }) => {
3779
- const descriptionText = typeof description === "string" || typeof description === "number" ? String(description) : void 0;
3780
- const errorText = typeof error === "string" || typeof error === "number" ? String(error) : void 0;
3781
- return {
3782
- resolvedLabel: accessibilityLabel ?? label ?? selectedLabel ?? placeholder ?? "Select",
3783
- resolvedHint: accessibilityHint ?? (invalid && errorText ? errorText : descriptionText ? descriptionText : hasFieldContext && fieldDescribedBy ? "Opens a list of options" : void 0),
3784
- announce: (message) => {
3785
- AccessibilityInfo.announceForAccessibility?.(message);
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/components/Select/internal/useSelectCollection.ts
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/components/Select/internal/useSelectSearch.ts
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/Trigger/SelectIcon.tsx
3867
- const SelectIcon = createSelectSlot("icon", "Select.Icon");
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$3 = Platform.OS === "web" ? void 0 : { pointerEvents: "none" };
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$3 = Platform.OS === "web" ? { pointerEvents: "none" } : void 0;
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$3,
4062
- style: [styles.startIcon, webPointerEventsNone$3],
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$3,
4085
- style: [styles.endIcon, webPointerEventsNone$3],
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, placement: resolvedPlacement, updatePosition, onFloatingLayout } = useNativeFloatingPosition(placement, offset);
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 selectedValues = Array.isArray(selectedValue) ? selectedValue : selectedValue ? [selectedValue] : [];
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 } = useSelectAccessibility({
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: closeDropdown
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
- const selectGroup = (values) => {
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) closeDropdown();
4250
- };
4251
- const openContent = () => {
4252
- updatePosition(triggerRef);
4253
- openDropdown();
4254
- };
4255
- const contextValue = {
4256
- label,
4257
- description,
4258
- error,
4259
- placeholder,
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
- placement: resolvedPlacement,
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: searchPlaceholder ?? searchPlaceholderFromChildren ?? "Search...",
4581
+ searchPlaceholder: resolvedSearchPlaceholder,
4289
4582
  searchInputRef,
4290
- empty: empty ?? emptyFromChildren ?? "Nothing found",
4291
- loadingContent: loadingFromChildren ?? loadingText,
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
- fieldControlId: !hasOwnField ? field?.controlId : void 0,
4310
- fieldLabelId: !hasOwnField ? field?.labelId : void 0,
4311
- fieldDescribedBy: !hasOwnField ? field?.ariaDescribedBy : void 0
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$2 = Platform.OS === "web" ? void 0 : { pointerEvents: "none" };
4445
- const webPointerEventsNone$2 = Platform.OS === "web" ? { pointerEvents: "none" } : void 0;
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$2,
4649
- style: [indicatorStyle, webPointerEventsNone$2],
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
- ...nativePointerEventsNone$1,
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(InternalArrow, {})]
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/useTooltipDelay.ts
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,