@vellira-ui/react-native 2.35.1 → 2.36.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,17 +1,502 @@
1
1
  // src/components/Dropdown/Content/DropdownContent.tsx
2
- import { useEffect, useMemo as useMemo3, useRef, useState } from "react";
2
+ import { useEffect as useEffect4, useMemo as useMemo4, useRef as useRef2, useState as useState4 } from "react";
3
+ import { Search } from "@vellira-ui/icons";
3
4
  import {
4
5
  AccessibilityInfo,
5
6
  Animated,
6
7
  Modal,
7
8
  Pressable,
8
9
  StyleSheet as StyleSheet2,
10
+ TextInput,
9
11
  View
10
12
  } from "react-native";
11
13
 
12
14
  // src/theme/ThemeProvider.tsx
13
- import { useMemo } from "react";
14
- import { useControllableState } from "@vellira-ui/core";
15
+ import { useMemo as useMemo2 } from "react";
16
+
17
+ // src/hooks/useControllableState.ts
18
+ import { useCallback, useState } from "react";
19
+ var useControllableState = ({
20
+ value,
21
+ defaultValue,
22
+ onChange
23
+ }) => {
24
+ const [internalValue, setInternalValue] = useState(defaultValue);
25
+ const isControlled = value !== void 0;
26
+ const currentValue = isControlled ? value : internalValue;
27
+ const setValue = useCallback(
28
+ (next) => {
29
+ if (!isControlled) {
30
+ setInternalValue(next);
31
+ }
32
+ onChange?.(next);
33
+ },
34
+ [isControlled, onChange]
35
+ );
36
+ return [currentValue, setValue];
37
+ };
38
+
39
+ // src/hooks/useDropdown.ts
40
+ import { useCallback as useCallback3, useEffect as useEffect2, useState as useState2 } from "react";
41
+
42
+ // src/hooks/useKeyboardNavigation.ts
43
+ import { useCallback as useCallback2, useEffect, useRef } from "react";
44
+ var useKeyboardNavigation = ({
45
+ activeIndex,
46
+ setActiveIndex,
47
+ items,
48
+ isOpen,
49
+ onOpen,
50
+ onSelect,
51
+ onClose,
52
+ getItemText,
53
+ loop = true
54
+ }) => {
55
+ const searchRef = useRef({
56
+ value: "",
57
+ timeoutId: void 0
58
+ });
59
+ useEffect(
60
+ () => () => {
61
+ if (searchRef.current.timeoutId) {
62
+ clearTimeout(searchRef.current.timeoutId);
63
+ }
64
+ },
65
+ []
66
+ );
67
+ const getNextEnabledIndex = useCallback2(
68
+ (current, direction) => {
69
+ if (!items.length) return current;
70
+ let index = current;
71
+ for (let i = 0; i < items.length; i++) {
72
+ const nextIndex = index + direction;
73
+ if (!loop && (nextIndex < 0 || nextIndex >= items.length)) {
74
+ return current;
75
+ }
76
+ index = (nextIndex + items.length) % items.length;
77
+ if (!items[index]?.disabled) {
78
+ return index;
79
+ }
80
+ }
81
+ return current;
82
+ },
83
+ [items, loop]
84
+ );
85
+ const getFirstEnabledIndex = useCallback2(
86
+ () => items.findIndex((item) => !item.disabled),
87
+ [items]
88
+ );
89
+ const getLastEnabledIndex = useCallback2(() => {
90
+ for (let i = items.length - 1; i >= 0; i--) {
91
+ if (!items[i].disabled) {
92
+ return i;
93
+ }
94
+ }
95
+ return -1;
96
+ }, [items]);
97
+ const getTypeaheadIndex = useCallback2(
98
+ (query) => {
99
+ if (!getItemText || !query) return -1;
100
+ const normalizedQuery = query.toLocaleLowerCase();
101
+ const startIndex = activeIndex >= 0 ? activeIndex + 1 : 0;
102
+ for (let offset = 0; offset < items.length; offset++) {
103
+ const index = (startIndex + offset) % items.length;
104
+ const item = items[index];
105
+ if (item && !item.disabled && getItemText(item).toLocaleLowerCase().startsWith(normalizedQuery)) {
106
+ return index;
107
+ }
108
+ }
109
+ return -1;
110
+ },
111
+ [activeIndex, getItemText, items]
112
+ );
113
+ const onKeyDown = useCallback2(
114
+ (event) => {
115
+ if (!isOpen) {
116
+ if (event.key === " " || event.key === "Enter" || event.key === "ArrowDown" || event.key === "ArrowUp") {
117
+ event.preventDefault();
118
+ onOpen(event);
119
+ }
120
+ return;
121
+ }
122
+ switch (event.key) {
123
+ case "ArrowDown":
124
+ event.preventDefault();
125
+ setActiveIndex(getNextEnabledIndex(activeIndex, 1));
126
+ break;
127
+ case "ArrowUp":
128
+ event.preventDefault();
129
+ setActiveIndex(getNextEnabledIndex(activeIndex, -1));
130
+ break;
131
+ case "Enter":
132
+ case " ":
133
+ event.preventDefault();
134
+ onSelect?.();
135
+ break;
136
+ case "Escape":
137
+ event.preventDefault();
138
+ onClose?.();
139
+ break;
140
+ case "Home":
141
+ event.preventDefault();
142
+ setActiveIndex(getFirstEnabledIndex());
143
+ break;
144
+ case "End":
145
+ event.preventDefault();
146
+ setActiveIndex(getLastEnabledIndex());
147
+ break;
148
+ case "Tab":
149
+ onClose?.();
150
+ break;
151
+ default:
152
+ if (event.key.length === 1 && !event.altKey && !event.ctrlKey && !event.metaKey) {
153
+ event.preventDefault();
154
+ if (searchRef.current.timeoutId) {
155
+ clearTimeout(searchRef.current.timeoutId);
156
+ }
157
+ searchRef.current.value += event.key;
158
+ searchRef.current.timeoutId = setTimeout(() => {
159
+ searchRef.current.value = "";
160
+ searchRef.current.timeoutId = void 0;
161
+ }, 700);
162
+ const nextIndex = getTypeaheadIndex(searchRef.current.value);
163
+ if (nextIndex >= 0) {
164
+ setActiveIndex(nextIndex);
165
+ }
166
+ }
167
+ break;
168
+ }
169
+ },
170
+ [
171
+ activeIndex,
172
+ isOpen,
173
+ onOpen,
174
+ onSelect,
175
+ onClose,
176
+ setActiveIndex,
177
+ getNextEnabledIndex,
178
+ getFirstEnabledIndex,
179
+ getLastEnabledIndex,
180
+ getTypeaheadIndex
181
+ ]
182
+ );
183
+ return { onKeyDown };
184
+ };
185
+
186
+ // src/hooks/useDropdown.ts
187
+ var useDropdown = ({
188
+ items,
189
+ open,
190
+ defaultOpen = false,
191
+ disabled = false,
192
+ onOpenChange,
193
+ onSelect,
194
+ getItemValue,
195
+ getItemText,
196
+ loop = true
197
+ }) => {
198
+ const [uncontrolledOpen, setUncontrolledOpen] = useState2(defaultOpen);
199
+ const [activeIndex, setActiveIndex] = useState2(-1);
200
+ const isControlled = open !== void 0;
201
+ const isOpen = open ?? uncontrolledOpen;
202
+ const getFirstEnabledIndex = useCallback3(
203
+ () => items.findIndex((item) => !item.disabled),
204
+ [items]
205
+ );
206
+ const getLastEnabledIndex = useCallback3(() => {
207
+ for (let index = items.length - 1; index >= 0; index--) {
208
+ if (!items[index]?.disabled) {
209
+ return index;
210
+ }
211
+ }
212
+ return -1;
213
+ }, [items]);
214
+ const syncActiveIndex = useCallback3(
215
+ (nextOpen, initialIndex) => {
216
+ if (nextOpen) {
217
+ setActiveIndex((currentIndex) => {
218
+ if (currentIndex >= 0 && !items[currentIndex]?.disabled) {
219
+ return currentIndex;
220
+ }
221
+ return initialIndex ?? getFirstEnabledIndex();
222
+ });
223
+ return;
224
+ }
225
+ setActiveIndex(-1);
226
+ },
227
+ [getFirstEnabledIndex, items]
228
+ );
229
+ useEffect2(() => {
230
+ syncActiveIndex(isOpen);
231
+ }, [isOpen, syncActiveIndex]);
232
+ const setOpen = useCallback3(
233
+ (nextOpen, initialIndex) => {
234
+ if (!isControlled) {
235
+ setUncontrolledOpen(nextOpen);
236
+ }
237
+ onOpenChange?.(nextOpen);
238
+ syncActiveIndex(nextOpen, initialIndex);
239
+ },
240
+ [isControlled, onOpenChange, syncActiveIndex]
241
+ );
242
+ const openDropdown = useCallback3(
243
+ (initialIndex = getFirstEnabledIndex()) => {
244
+ if (disabled) return;
245
+ setOpen(true, initialIndex);
246
+ },
247
+ [disabled, getFirstEnabledIndex, setOpen]
248
+ );
249
+ const closeDropdown = useCallback3(() => {
250
+ if (!isOpen) return;
251
+ setOpen(false);
252
+ }, [isOpen, setOpen]);
253
+ const toggleDropdown = useCallback3(() => {
254
+ if (disabled) return;
255
+ if (isOpen) {
256
+ setOpen(false);
257
+ return;
258
+ }
259
+ openDropdown();
260
+ }, [disabled, isOpen, openDropdown, setOpen]);
261
+ const selectItem = useCallback3(
262
+ (item) => {
263
+ if (item.disabled) return;
264
+ onSelect?.(getItemValue(item, items.indexOf(item)));
265
+ closeDropdown();
266
+ },
267
+ [closeDropdown, getItemValue, items, onSelect]
268
+ );
269
+ const selectActiveItem = useCallback3(() => {
270
+ const item = items[activeIndex];
271
+ if (!item) return;
272
+ selectItem(item);
273
+ }, [activeIndex, items, selectItem]);
274
+ const { onKeyDown } = useKeyboardNavigation({
275
+ activeIndex,
276
+ setActiveIndex,
277
+ items,
278
+ isOpen,
279
+ onOpen: (event) => {
280
+ openDropdown(
281
+ event.key === "ArrowUp" ? getLastEnabledIndex() : getFirstEnabledIndex()
282
+ );
283
+ },
284
+ onSelect: selectActiveItem,
285
+ onClose: closeDropdown,
286
+ getItemText,
287
+ loop
288
+ });
289
+ return {
290
+ activeIndex,
291
+ setActiveIndex,
292
+ isOpen,
293
+ open: isOpen,
294
+ setOpen,
295
+ openDropdown,
296
+ closeDropdown,
297
+ toggleDropdown,
298
+ selectItem,
299
+ select: selectItem,
300
+ selectActiveItem,
301
+ onKeyDown,
302
+ getFirstEnabledIndex,
303
+ getLastEnabledIndex
304
+ };
305
+ };
306
+
307
+ // src/hooks/useModal.ts
308
+ import { useCallback as useCallback4, useId } from "react";
309
+ var useModal = ({
310
+ open,
311
+ defaultOpen = false,
312
+ onOpenChange,
313
+ closeOnEscape,
314
+ closeOnOutsidePress
315
+ }) => {
316
+ const contentId = useId();
317
+ const titleId = useId();
318
+ const descriptionId = useId();
319
+ const [resolvedOpen, setResolvedOpen] = useControllableState({
320
+ value: open,
321
+ defaultValue: defaultOpen,
322
+ onChange: onOpenChange
323
+ });
324
+ const requestClose = useCallback4(() => {
325
+ setResolvedOpen(false);
326
+ }, [setResolvedOpen]);
327
+ return {
328
+ open: resolvedOpen,
329
+ shouldRender: resolvedOpen,
330
+ setOpen: setResolvedOpen,
331
+ requestClose,
332
+ closeOnOutsidePress: closeOnOutsidePress ?? true,
333
+ closeOnEscape: closeOnEscape ?? true,
334
+ contentId,
335
+ titleId,
336
+ descriptionId
337
+ };
338
+ };
339
+
340
+ // src/hooks/useSelect.ts
341
+ import { useCallback as useCallback5, useEffect as useEffect3, useMemo, useState as useState3 } from "react";
342
+ var useSelect = ({
343
+ value,
344
+ defaultValue,
345
+ onValueChange,
346
+ onChange,
347
+ options,
348
+ multiple = false,
349
+ maxSelected,
350
+ closeOnSelect = !multiple,
351
+ disabled = false,
352
+ open,
353
+ defaultOpen = false,
354
+ onOpenChange
355
+ }) => {
356
+ const [selectedValue, setSelectedValue] = useControllableState({
357
+ value,
358
+ defaultValue: defaultValue ?? (multiple ? [] : ""),
359
+ onChange: onValueChange ?? onChange
360
+ });
361
+ const [isOpen, setIsOpen] = useControllableState({
362
+ value: open,
363
+ defaultValue: defaultOpen,
364
+ onChange: onOpenChange
365
+ });
366
+ const [activeIndex, setActiveIndex] = useState3(-1);
367
+ const selectedValues = useMemo(
368
+ () => Array.isArray(selectedValue) ? selectedValue : selectedValue ? [selectedValue] : [],
369
+ [selectedValue]
370
+ );
371
+ const selectedOption = useMemo(
372
+ () => options.find((option) => selectedValues.includes(option.value)),
373
+ [options, selectedValues]
374
+ );
375
+ const selectedOptions = useMemo(
376
+ () => options.filter((option) => selectedValues.includes(option.value)),
377
+ [options, selectedValues]
378
+ );
379
+ const getInitialActiveIndex = useCallback5(() => {
380
+ const selectedIndex = options.findIndex(
381
+ (option) => selectedValues.includes(option.value) && !option.disabled
382
+ );
383
+ if (selectedIndex >= 0) return selectedIndex;
384
+ return options.findIndex((option) => !option.disabled);
385
+ }, [options, selectedValues]);
386
+ const openDropdown = useCallback5(() => {
387
+ if (disabled) return;
388
+ setActiveIndex(getInitialActiveIndex());
389
+ setIsOpen(true);
390
+ }, [disabled, getInitialActiveIndex, setIsOpen]);
391
+ const closeDropdown = useCallback5(() => {
392
+ setIsOpen(false);
393
+ }, [setIsOpen]);
394
+ const toggleDropdown = useCallback5(() => {
395
+ if (disabled) return;
396
+ if (isOpen) {
397
+ closeDropdown();
398
+ return;
399
+ }
400
+ openDropdown();
401
+ }, [closeDropdown, disabled, isOpen, openDropdown]);
402
+ useEffect3(() => {
403
+ if (!isOpen) return;
404
+ setActiveIndex((currentIndex) => {
405
+ const currentOption = options[currentIndex];
406
+ if (currentOption && !currentOption.disabled) {
407
+ return currentIndex;
408
+ }
409
+ return getInitialActiveIndex();
410
+ });
411
+ }, [getInitialActiveIndex, isOpen, options]);
412
+ const selectValue = useCallback5(
413
+ (nextValue) => {
414
+ if (nextValue === "") {
415
+ setSelectedValue(multiple ? [] : "");
416
+ closeDropdown();
417
+ return;
418
+ }
419
+ const nextOption = options.find((option) => option.value === nextValue);
420
+ if (!nextOption || nextOption.disabled) return;
421
+ if (multiple) {
422
+ const isSelected = selectedValues.includes(nextValue);
423
+ if (!isSelected && typeof maxSelected === "number" && selectedValues.length >= maxSelected) {
424
+ return;
425
+ }
426
+ const nextValues = selectedValues.includes(nextValue) ? selectedValues.filter((value2) => value2 !== nextValue) : [...selectedValues, nextValue];
427
+ setSelectedValue(nextValues);
428
+ if (closeOnSelect) {
429
+ closeDropdown();
430
+ }
431
+ return;
432
+ }
433
+ setSelectedValue(nextValue);
434
+ setActiveIndex(options.indexOf(nextOption));
435
+ closeDropdown();
436
+ },
437
+ [
438
+ closeDropdown,
439
+ closeOnSelect,
440
+ maxSelected,
441
+ multiple,
442
+ options,
443
+ selectedValues,
444
+ setSelectedValue
445
+ ]
446
+ );
447
+ const selectActiveOption = useCallback5(() => {
448
+ const activeOption = options[activeIndex];
449
+ if (!activeOption) return;
450
+ selectValue(activeOption.value);
451
+ }, [activeIndex, options, selectValue]);
452
+ const { onKeyDown } = useKeyboardNavigation({
453
+ activeIndex,
454
+ setActiveIndex,
455
+ items: options,
456
+ isOpen,
457
+ onOpen: openDropdown,
458
+ onClose: closeDropdown,
459
+ onSelect: selectActiveOption,
460
+ getItemText: (option) => option.label
461
+ });
462
+ return {
463
+ selectedValue,
464
+ selectedValues,
465
+ setSelectedValue,
466
+ selectedOption,
467
+ selectedOptions,
468
+ isOpen,
469
+ open: isOpen,
470
+ setIsOpen,
471
+ activeIndex,
472
+ setActiveIndex,
473
+ getInitialActiveIndex,
474
+ openDropdown,
475
+ closeDropdown,
476
+ toggleDropdown,
477
+ selectValue,
478
+ select: selectValue,
479
+ selectActiveOption,
480
+ onKeyDown
481
+ };
482
+ };
483
+
484
+ // src/hooks/useTabs.ts
485
+ var useTabs = ({
486
+ activeIndex: controlledActiveIndex,
487
+ defaultActiveIndex = 0,
488
+ onChange
489
+ }) => {
490
+ const [activeIndex, setActiveIndex] = useControllableState({
491
+ value: controlledActiveIndex,
492
+ defaultValue: defaultActiveIndex,
493
+ onChange
494
+ });
495
+ return {
496
+ activeIndex,
497
+ setActiveIndex
498
+ };
499
+ };
15
500
 
16
501
  // src/theme/ThemeContext.ts
17
502
  import { createContext } from "react";
@@ -48,7 +533,7 @@ var ThemeProvider = ({
48
533
  defaultValue: defaultTheme,
49
534
  onChange: onThemeChange
50
535
  });
51
- const value = useMemo(
536
+ const value = useMemo2(
52
537
  () => ({
53
538
  themeName: currentTheme,
54
539
  theme: nativeThemes[currentTheme],
@@ -67,10 +552,10 @@ function useTheme() {
67
552
  }
68
553
 
69
554
  // src/theme/useThemeStyles.ts
70
- import { useMemo as useMemo2 } from "react";
555
+ import { useMemo as useMemo3 } from "react";
71
556
  function useThemeStyles(createStyles23) {
72
557
  const { theme } = useTheme();
73
- return useMemo2(() => createStyles23(theme), [createStyles23, theme]);
558
+ return useMemo3(() => createStyles23(theme), [createStyles23, theme]);
74
559
  }
75
560
 
76
561
  // src/components/Dropdown/Content/DropdownContent.styles.ts
@@ -131,6 +616,30 @@ var createStyles = (theme) => StyleSheet.create({
131
616
  maxWidth: 360,
132
617
  maxHeight: "60%",
133
618
  borderRadius: theme.tokens.radius.md
619
+ },
620
+ searchWrap: {
621
+ minHeight: 40,
622
+ flexDirection: "row",
623
+ alignItems: "center",
624
+ gap: theme.tokens.spacing[2],
625
+ paddingHorizontal: theme.tokens.spacing[3],
626
+ borderBottomWidth: 1,
627
+ borderBottomColor: theme.components.dropdown.separator.bg
628
+ },
629
+ searchIcon: {
630
+ width: 16,
631
+ height: 16,
632
+ alignItems: "center",
633
+ justifyContent: "center"
634
+ },
635
+ searchInput: {
636
+ flex: 1,
637
+ minWidth: 0,
638
+ paddingVertical: theme.tokens.spacing[2],
639
+ color: theme.components.dropdown.content.fg,
640
+ fontFamily: theme.tokens.typography.family.regular,
641
+ fontSize: theme.tokens.typography.size.sm,
642
+ lineHeight: theme.tokens.typography.lineHeight.sm
134
643
  }
135
644
  });
136
645
 
@@ -142,13 +651,19 @@ function DropdownContent({
142
651
  onClose,
143
652
  contentStyle,
144
653
  accessibilityLabel,
145
- presentation
654
+ presentation,
655
+ searchable = false,
656
+ searchValue = "",
657
+ searchPlaceholder = "Search actions...",
658
+ searchAccessibilityLabel,
659
+ onSearchChange
146
660
  }) {
661
+ const { theme } = useTheme();
147
662
  const styles = useThemeStyles(createStyles);
148
663
  const isSheet = presentation === "sheet";
149
- const animation = useRef(new Animated.Value(isOpen ? 1 : 0)).current;
150
- const [reduceMotion, setReduceMotion] = useState(false);
151
- useEffect(() => {
664
+ const animation = useRef2(new Animated.Value(isOpen ? 1 : 0)).current;
665
+ const [reduceMotion, setReduceMotion] = useState4(false);
666
+ useEffect4(() => {
152
667
  AccessibilityInfo.isReduceMotionEnabled?.().then(setReduceMotion);
153
668
  const subscription = AccessibilityInfo.addEventListener?.(
154
669
  "reduceMotionChanged",
@@ -158,7 +673,7 @@ function DropdownContent({
158
673
  subscription?.remove();
159
674
  };
160
675
  }, []);
161
- useEffect(() => {
676
+ useEffect4(() => {
162
677
  if (!isOpen) {
163
678
  animation.setValue(0);
164
679
  return;
@@ -174,7 +689,7 @@ function DropdownContent({
174
689
  useNativeDriver: true
175
690
  }).start();
176
691
  }, [animation, isOpen, isSheet, reduceMotion]);
177
- const backdropAnimatedStyle = useMemo3(
692
+ const backdropAnimatedStyle = useMemo4(
178
693
  () => ({
179
694
  opacity: animation.interpolate({
180
695
  inputRange: [0, 1],
@@ -183,7 +698,7 @@ function DropdownContent({
183
698
  }),
184
699
  [animation]
185
700
  );
186
- const menuAnimatedStyle = useMemo3(() => {
701
+ const menuAnimatedStyle = useMemo4(() => {
187
702
  const translateY = animation.interpolate({
188
703
  inputRange: [0, 1],
189
704
  outputRange: isSheet ? [24, 0] : [-6, 0]
@@ -221,7 +736,7 @@ function DropdownContent({
221
736
  )
222
737
  }
223
738
  ),
224
- /* @__PURE__ */ jsx2(
739
+ /* @__PURE__ */ jsxs(
225
740
  Animated.View,
226
741
  {
227
742
  accessibilityRole: "menu",
@@ -232,7 +747,39 @@ function DropdownContent({
232
747
  contentStyle,
233
748
  menuAnimatedStyle
234
749
  ],
235
- children
750
+ children: [
751
+ searchable && /* @__PURE__ */ jsxs(View, { style: styles.searchWrap, children: [
752
+ /* @__PURE__ */ jsx2(
753
+ View,
754
+ {
755
+ style: styles.searchIcon,
756
+ accessibilityElementsHidden: true,
757
+ importantForAccessibility: "no",
758
+ children: /* @__PURE__ */ jsx2(
759
+ Search,
760
+ {
761
+ width: 16,
762
+ height: 16,
763
+ color: theme.components.dropdown.separator.fg
764
+ }
765
+ )
766
+ }
767
+ ),
768
+ /* @__PURE__ */ jsx2(
769
+ TextInput,
770
+ {
771
+ value: searchValue,
772
+ onChangeText: onSearchChange,
773
+ placeholder: searchPlaceholder,
774
+ returnKeyType: "search",
775
+ placeholderTextColor: theme.components.dropdown.separator.fg,
776
+ accessibilityLabel: searchAccessibilityLabel ?? searchPlaceholder,
777
+ style: styles.searchInput
778
+ }
779
+ )
780
+ ] }),
781
+ children
782
+ ]
236
783
  }
237
784
  )
238
785
  ] })
@@ -242,8 +789,14 @@ function DropdownContent({
242
789
  DropdownContent.displayName = "DropdownContent";
243
790
 
244
791
  // src/components/Dropdown/Dropdown.tsx
245
- import { useCallback, useEffect as useEffect3, useMemo as useMemo4, useRef as useRef3 } from "react";
246
- import { useDropdown } from "@vellira-ui/core";
792
+ import {
793
+ useCallback as useCallback9,
794
+ useEffect as useEffect7,
795
+ useId as useId2,
796
+ useMemo as useMemo5,
797
+ useRef as useRef5,
798
+ useState as useState7
799
+ } from "react";
247
800
  import {
248
801
  AccessibilityInfo as AccessibilityInfo2,
249
802
  findNodeHandle,
@@ -253,6 +806,135 @@ import {
253
806
  View as View4
254
807
  } from "react-native";
255
808
 
809
+ // src/managers/FloatingManager/useNativeFloatingPosition.ts
810
+ import { useCallback as useCallback6, useRef as useRef3, useState as useState5 } from "react";
811
+ import { Dimensions } from "react-native";
812
+ var safePadding = 12;
813
+ function useNativeFloatingPosition(placement = "top", offset = 8) {
814
+ const [position, setPosition] = useState5({ top: 0, left: 0 });
815
+ const floatingSizeRef = useRef3({
816
+ width: 0,
817
+ height: 0
818
+ });
819
+ const lastTriggerRef = useRef3(null);
820
+ const clamp = useCallback6((value, min, max) => {
821
+ return Math.min(Math.max(value, min), Math.max(min, max));
822
+ }, []);
823
+ const calculatePosition = useCallback6(
824
+ (triggerRect, size) => {
825
+ const { width: screenWidth, height: screenHeight } = Dimensions.get("window");
826
+ const [side, align = "center"] = placement.split("-");
827
+ const horizontalTop = side === "bottom" ? triggerRect.y + triggerRect.height + offset : triggerRect.y - size.height - offset;
828
+ const verticalTop = align === "start" ? triggerRect.y : align === "end" ? triggerRect.y + triggerRect.height - size.height : triggerRect.y + triggerRect.height / 2 - size.height / 2;
829
+ const horizontalLeft = align === "start" ? triggerRect.x : align === "end" ? triggerRect.x + triggerRect.width - size.width : triggerRect.x + triggerRect.width / 2 - size.width / 2;
830
+ const verticalLeft = side === "right" ? triggerRect.x + triggerRect.width + offset : triggerRect.x - size.width - offset;
831
+ const rawPosition = side === "left" || side === "right" ? { top: verticalTop, left: verticalLeft } : { top: horizontalTop, left: horizontalLeft };
832
+ return {
833
+ top: clamp(
834
+ rawPosition.top,
835
+ safePadding,
836
+ screenHeight - size.height - safePadding
837
+ ),
838
+ left: clamp(
839
+ rawPosition.left,
840
+ safePadding,
841
+ screenWidth - size.width - safePadding
842
+ )
843
+ };
844
+ },
845
+ [placement, offset, clamp]
846
+ );
847
+ const updatePosition = useCallback6(
848
+ (triggerRef, measuredSize = floatingSizeRef.current) => {
849
+ lastTriggerRef.current = triggerRef;
850
+ const node = triggerRef.current;
851
+ if (!node || typeof node.measureInWindow !== "function") {
852
+ setPosition({ top: 0, left: 0 });
853
+ return;
854
+ }
855
+ node.measureInWindow((x, y, width, height) => {
856
+ setPosition(calculatePosition({ x, y, width, height }, measuredSize));
857
+ });
858
+ },
859
+ [calculatePosition]
860
+ );
861
+ const onFloatingLayout = useCallback6(
862
+ (event) => {
863
+ const { width, height } = event.nativeEvent.layout;
864
+ const nextSize = { width, height };
865
+ floatingSizeRef.current = nextSize;
866
+ if (lastTriggerRef.current) {
867
+ updatePosition(lastTriggerRef.current, nextSize);
868
+ }
869
+ },
870
+ [updatePosition]
871
+ );
872
+ return { position, updatePosition, onFloatingLayout };
873
+ }
874
+
875
+ // src/managers/OverlayStack/useNativeDismiss.ts
876
+ import { useCallback as useCallback8 } from "react";
877
+
878
+ // src/managers/OverlayStack/useNativeOverlayStack.ts
879
+ import { useCallback as useCallback7, useEffect as useEffect5 } from "react";
880
+
881
+ // src/managers/OverlayStack/NativeOverlayStack.ts
882
+ var stack = [];
883
+ var nativeOverlayStackStore = {
884
+ add(id) {
885
+ stack = stack.filter((item) => item !== id);
886
+ stack.push(id);
887
+ },
888
+ remove(id) {
889
+ stack = stack.filter((item) => item !== id);
890
+ },
891
+ isTop(id) {
892
+ return stack[stack.length - 1] === id;
893
+ }
894
+ };
895
+
896
+ // src/managers/OverlayStack/useNativeOverlayStack.ts
897
+ var useNativeOverlayStack = ({
898
+ id,
899
+ visible
900
+ }) => {
901
+ useEffect5(() => {
902
+ if (!visible) return;
903
+ nativeOverlayStackStore.add(id);
904
+ return () => {
905
+ nativeOverlayStackStore.remove(id);
906
+ };
907
+ }, [id, visible]);
908
+ const isTopOverlay = useCallback7(
909
+ () => nativeOverlayStackStore.isTop(id),
910
+ [id]
911
+ );
912
+ return { isTopOverlay };
913
+ };
914
+
915
+ // src/managers/OverlayStack/useNativeDismiss.ts
916
+ var useNativeDismiss = ({
917
+ id,
918
+ visible,
919
+ closeOnOutsidePress = true,
920
+ onClose
921
+ }) => {
922
+ const { isTopOverlay } = useNativeOverlayStack({ id, visible });
923
+ const requestClose = useCallback8(() => {
924
+ if (!isTopOverlay()) return;
925
+ onClose();
926
+ }, [isTopOverlay, onClose]);
927
+ const requestOutsideClose = useCallback8(() => {
928
+ if (!closeOnOutsidePress) return;
929
+ requestClose();
930
+ }, [closeOnOutsidePress, requestClose]);
931
+ return {
932
+ isTopOverlay,
933
+ requestClose,
934
+ requestOutsideClose
935
+ };
936
+ };
937
+
256
938
  // src/components/Dropdown/Group/DropdownGroup.tsx
257
939
  import { Text } from "react-native";
258
940
 
@@ -291,6 +973,7 @@ function parseDropdownChildren(children) {
291
973
  let trigger;
292
974
  let triggerProps;
293
975
  let contentProps;
976
+ let searchProps;
294
977
  const entries = [];
295
978
  const items = [];
296
979
  const nextId = (prefix) => `${prefix}-${generatedId++}`;
@@ -309,6 +992,10 @@ function parseDropdownChildren(children) {
309
992
  Children.forEach(node, (child) => {
310
993
  if (!isValidElement(child)) return;
311
994
  const type = child.type;
995
+ if (type.__velliraPortal) {
996
+ visit(child.props.children);
997
+ return;
998
+ }
312
999
  switch (type.__velliraDropdownPart) {
313
1000
  case "trigger":
314
1001
  triggerProps = child.props;
@@ -318,6 +1005,9 @@ function parseDropdownChildren(children) {
318
1005
  contentProps = child.props;
319
1006
  visit(contentProps.children);
320
1007
  return;
1008
+ case "search":
1009
+ searchProps = child.props;
1010
+ return;
321
1011
  case "group":
322
1012
  visit(child.props.children);
323
1013
  return;
@@ -358,7 +1048,7 @@ function parseDropdownChildren(children) {
358
1048
  });
359
1049
  }
360
1050
  visit(children);
361
- return { contentProps, entries, items, trigger, triggerProps };
1051
+ return { contentProps, entries, items, searchProps, trigger, triggerProps };
362
1052
  }
363
1053
  function getItemLabel(children) {
364
1054
  const labelParts = [];
@@ -524,9 +1214,9 @@ DropdownSeparator.displayName = "DropdownSeparator";
524
1214
  import {
525
1215
  cloneElement as cloneElement2,
526
1216
  isValidElement as isValidElement3,
527
- useEffect as useEffect2,
528
- useRef as useRef2,
529
- useState as useState2
1217
+ useEffect as useEffect6,
1218
+ useRef as useRef4,
1219
+ useState as useState6
530
1220
  } from "react";
531
1221
  import { ChevronDown } from "@vellira-ui/icons";
532
1222
  import { Animated as Animated2, Pressable as Pressable3, Text as Text3, View as View3 } from "react-native";
@@ -661,9 +1351,9 @@ function DropdownTrigger({
661
1351
  }[size];
662
1352
  const hasIcon = Boolean(icon);
663
1353
  const isIconOnly = !trigger && hasIcon && !showArrow;
664
- const [isPressed, setIsPressed] = useState2(false);
665
- const rotateAnim = useRef2(new Animated2.Value(isOpen ? 1 : 0)).current;
666
- useEffect2(() => {
1354
+ const [isPressed, setIsPressed] = useState6(false);
1355
+ const rotateAnim = useRef4(new Animated2.Value(isOpen ? 1 : 0)).current;
1356
+ useEffect6(() => {
667
1357
  Animated2.timing(rotateAnim, {
668
1358
  toValue: isOpen ? 1 : 0,
669
1359
  duration: 180,
@@ -797,6 +1487,14 @@ function DropdownRoot({
797
1487
  disabled = false,
798
1488
  loading = false,
799
1489
  loadingText = "Loading actions...",
1490
+ searchable = false,
1491
+ command = false,
1492
+ searchValue,
1493
+ defaultSearchValue = "",
1494
+ searchPlaceholder,
1495
+ onSearch,
1496
+ empty,
1497
+ noOptionsText,
800
1498
  size = "md",
801
1499
  style,
802
1500
  triggerStyle,
@@ -807,15 +1505,20 @@ function DropdownRoot({
807
1505
  accessibilityHint
808
1506
  }) {
809
1507
  const styles = useThemeStyles(createStyles6);
1508
+ const overlayId = useId2();
1509
+ const [uncontrolledSearchValue, setUncontrolledSearchValue] = useState7(defaultSearchValue);
1510
+ const resolvedSearchValue = searchValue ?? uncontrolledSearchValue;
810
1511
  const { width } = useWindowDimensions();
811
- const triggerRef = useRef3(null);
812
- const parsed = useMemo4(() => parseDropdownChildren(children), [children]);
1512
+ const triggerRef = useRef5(null);
1513
+ const parsed = useMemo5(() => parseDropdownChildren(children), [children]);
1514
+ const contentCommand = parsed.contentProps?.command ?? false;
1515
+ const isSearchable = searchable || command || contentCommand || !!parsed.searchProps;
813
1516
  const resolvedPresentation = presentation === "auto" ? width < 768 ? "sheet" : "popover" : presentation;
814
- const menuAccessibilityLabel = useMemo4(() => {
1517
+ const menuAccessibilityLabel = useMemo5(() => {
815
1518
  if (accessibilityLabel) return accessibilityLabel;
816
1519
  return typeof label === "string" ? label : "Menu";
817
1520
  }, [accessibilityLabel, label]);
818
- const navigableItems = useMemo4(
1521
+ const navigableItems = useMemo5(
819
1522
  () => parsed.items.map((item) => ({
820
1523
  disabled: item.disabled,
821
1524
  label: item.label,
@@ -823,6 +1526,10 @@ function DropdownRoot({
823
1526
  })),
824
1527
  [parsed.items]
825
1528
  );
1529
+ const filteredParsed = useMemo5(() => {
1530
+ if (!isSearchable || !resolvedSearchValue.trim()) return parsed;
1531
+ return filterDropdownEntries(parsed, resolvedSearchValue);
1532
+ }, [isSearchable, parsed, resolvedSearchValue]);
826
1533
  const { isOpen, closeDropdown, toggleDropdown } = useDropdown({
827
1534
  items: navigableItems,
828
1535
  open,
@@ -832,24 +1539,29 @@ function DropdownRoot({
832
1539
  getItemValue: (item) => item.value,
833
1540
  getItemText: (item) => typeof item.label === "string" ? item.label : item.value
834
1541
  });
835
- useEffect3(() => {
1542
+ useEffect7(() => {
836
1543
  if (!isOpen) return;
837
1544
  AccessibilityInfo2.announceForAccessibility(
838
1545
  `${menuAccessibilityLabel} opened`
839
1546
  );
840
1547
  }, [isOpen, menuAccessibilityLabel]);
841
- const focusTrigger = useCallback(() => {
1548
+ const focusTrigger = useCallback9(() => {
842
1549
  if (typeof findNodeHandle !== "function") return;
843
1550
  const handle = findNodeHandle(triggerRef.current);
844
1551
  if (handle && AccessibilityInfo2.setAccessibilityFocus) {
845
1552
  AccessibilityInfo2.setAccessibilityFocus(handle);
846
1553
  }
847
1554
  }, []);
848
- const closeAndFocusTrigger = useCallback(() => {
1555
+ const closeAndFocusTrigger = useCallback9(() => {
849
1556
  closeDropdown();
850
1557
  requestAnimationFrame(focusTrigger);
851
1558
  }, [closeDropdown, focusTrigger]);
852
- const handleSelect = useCallback(
1559
+ const dismiss = useNativeDismiss({
1560
+ id: overlayId,
1561
+ visible: isOpen,
1562
+ onClose: closeAndFocusTrigger
1563
+ });
1564
+ const handleSelect = useCallback9(
853
1565
  (entry) => {
854
1566
  if (entry.disabled || loading) return;
855
1567
  const event = createDropdownSelectEvent();
@@ -861,10 +1573,19 @@ function DropdownRoot({
861
1573
  },
862
1574
  [closeAndFocusTrigger, closeOnSelect, loading]
863
1575
  );
864
- const handleTriggerPress = useCallback(() => {
1576
+ const handleTriggerPress = useCallback9(() => {
865
1577
  toggleDropdown();
866
1578
  }, [toggleDropdown]);
867
- const renderEntry = useCallback(
1579
+ const handleSearchChange = useCallback9(
1580
+ (value) => {
1581
+ if (searchValue === void 0) {
1582
+ setUncontrolledSearchValue(value);
1583
+ }
1584
+ onSearch?.(value);
1585
+ },
1586
+ [onSearch, searchValue]
1587
+ );
1588
+ const renderEntry = useCallback9(
868
1589
  ({ item }) => {
869
1590
  if (item.type === "label") {
870
1591
  return /* @__PURE__ */ jsx7(DropdownGroup, { label: item.props.children });
@@ -901,7 +1622,13 @@ function DropdownRoot({
901
1622
  id: "loading",
902
1623
  props: { children: loadingText }
903
1624
  }
904
- ] : parsed.entries;
1625
+ ] : isSearchable && filteredParsed.items.length === 0 ? [
1626
+ {
1627
+ type: "empty",
1628
+ id: "empty",
1629
+ props: { children: empty ?? noOptionsText ?? "No actions found" }
1630
+ }
1631
+ ] : filteredParsed.entries;
905
1632
  const contentStyleFromSlot = parsed.contentProps?.style;
906
1633
  const presentationFromSlot = parsed.contentProps?.presentation === "auto" ? void 0 : parsed.contentProps?.presentation;
907
1634
  return /* @__PURE__ */ jsxs4(View4, { style: [styles.root, style], children: [
@@ -929,10 +1656,15 @@ function DropdownRoot({
929
1656
  DropdownContent,
930
1657
  {
931
1658
  isOpen,
932
- onClose: closeAndFocusTrigger,
1659
+ onClose: dismiss.requestClose,
933
1660
  contentStyle: [contentStyle, contentStyleFromSlot],
934
1661
  accessibilityLabel: menuAccessibilityLabel,
935
1662
  presentation: presentationFromSlot ?? resolvedPresentation,
1663
+ searchable: isSearchable,
1664
+ searchValue: resolvedSearchValue,
1665
+ searchPlaceholder: parsed.searchProps?.placeholder ?? searchPlaceholder ?? (command || contentCommand ? "Type a command..." : "Search actions..."),
1666
+ searchAccessibilityLabel: parsed.searchProps?.accessibilityLabel,
1667
+ onSearchChange: handleSearchChange,
936
1668
  children: /* @__PURE__ */ jsx7(
937
1669
  FlatList,
938
1670
  {
@@ -959,6 +1691,21 @@ function createDropdownSelectEvent() {
959
1691
  }
960
1692
  };
961
1693
  }
1694
+ function filterDropdownEntries(parsed, searchValue) {
1695
+ const normalizedSearch = searchValue.trim().toLocaleLowerCase();
1696
+ const matchedItems = new Set(
1697
+ parsed.items.filter(
1698
+ (item) => item.label.toLocaleLowerCase().includes(normalizedSearch)
1699
+ ).map((item) => item.id)
1700
+ );
1701
+ return {
1702
+ ...parsed,
1703
+ items: parsed.items.filter((item) => matchedItems.has(item.id)),
1704
+ entries: parsed.entries.filter(
1705
+ (entry) => entry.type !== "item" || matchedItems.has(entry.id)
1706
+ )
1707
+ };
1708
+ }
962
1709
  var DropdownTriggerSlot = createDropdownSlot(
963
1710
  "trigger",
964
1711
  "Dropdown.Trigger"
@@ -991,9 +1738,14 @@ var DropdownLoadingSlot = createDropdownSlot(
991
1738
  "loading",
992
1739
  "Dropdown.Loading"
993
1740
  );
1741
+ var DropdownSearchSlot = createDropdownSlot(
1742
+ "search",
1743
+ "Dropdown.Search"
1744
+ );
994
1745
  var Dropdown = Object.assign(DropdownRoot, {
995
1746
  Trigger: DropdownTriggerSlot,
996
1747
  Content: DropdownContentSlot,
1748
+ Search: DropdownSearchSlot,
997
1749
  Item: DropdownItemSlot,
998
1750
  Group: DropdownGroupSlot,
999
1751
  Label: DropdownLabelSlot,
@@ -1010,7 +1762,7 @@ import { Text as Text5, View as View5 } from "react-native";
1010
1762
  import { StyleSheet as StyleSheet8 } from "react-native";
1011
1763
  var createStyles7 = (theme) => StyleSheet8.create({
1012
1764
  body: {
1013
- paddingBottom: theme.tokens.spacing[4]
1765
+ paddingBottom: theme.components.modal.body.paddingBottom
1014
1766
  },
1015
1767
  text: {
1016
1768
  color: theme.components.modal.content.fg,
@@ -1036,32 +1788,124 @@ var renderBodyChildren = (children, textStyle) => Children2.map(children, (child
1036
1788
  if (!isTextElement(child)) {
1037
1789
  return child;
1038
1790
  }
1039
- return cloneElement3(child, {
1040
- style: [textStyle, child.props.style]
1041
- });
1042
- });
1043
- var ModalBody = ({ children, style }) => {
1044
- const styles = useThemeStyles(createStyles7);
1045
- return /* @__PURE__ */ jsx8(View5, { style: [styles.body, style], children: renderBodyChildren(children, styles.text) });
1791
+ return cloneElement3(child, {
1792
+ style: [textStyle, child.props.style]
1793
+ });
1794
+ });
1795
+ var ModalBody = ({ children, style }) => {
1796
+ const styles = useThemeStyles(createStyles7);
1797
+ return /* @__PURE__ */ jsx8(View5, { style: [styles.body, style], children: renderBodyChildren(children, styles.text) });
1798
+ };
1799
+ ModalBody.displayName = "ModalBody";
1800
+
1801
+ // src/components/Modal/Close/ModalClose.tsx
1802
+ import { cloneElement as cloneElement4, isValidElement as isValidElement5 } from "react";
1803
+ import { Close } from "@vellira-ui/icons";
1804
+ import { Pressable as Pressable4 } from "react-native";
1805
+
1806
+ // src/components/Modal/Header/ModalHeader.styles.ts
1807
+ import { StyleSheet as StyleSheet9 } from "react-native";
1808
+ var createStyles8 = (theme) => StyleSheet9.create({
1809
+ header: {
1810
+ alignItems: "center",
1811
+ flexDirection: "row",
1812
+ gap: theme.components.modal.header.gap,
1813
+ justifyContent: "space-between",
1814
+ paddingBottom: theme.components.modal.header.paddingBottom
1815
+ },
1816
+ title: {
1817
+ flex: 1,
1818
+ color: theme.components.modal.title.fg,
1819
+ fontFamily: theme.tokens.typography.family.semibold,
1820
+ fontSize: theme.tokens.typography.size.lg,
1821
+ lineHeight: theme.tokens.typography.lineHeight.md
1822
+ },
1823
+ closeButton: {
1824
+ width: theme.components.modal.closeButton.size,
1825
+ height: theme.components.modal.closeButton.size,
1826
+ alignItems: "center",
1827
+ justifyContent: "center",
1828
+ backgroundColor: theme.components.modal.closeButton.default.bg,
1829
+ borderRadius: theme.components.modal.closeButton.radius
1830
+ },
1831
+ closeButtonPressed: {
1832
+ backgroundColor: theme.components.modal.closeButton.hover.bg
1833
+ },
1834
+ closeButtonDisabled: {
1835
+ backgroundColor: theme.components.modal.closeButton.disabled.bg
1836
+ }
1837
+ });
1838
+
1839
+ // src/components/Modal/internal/ModalContext.tsx
1840
+ import { createContext as createContext2, useContext as useContext2 } from "react";
1841
+ var ModalContext = createContext2(void 0);
1842
+ ModalContext.displayName = "ModalContext";
1843
+ var useModalContext = () => {
1844
+ const context = useContext2(ModalContext);
1845
+ if (!context) {
1846
+ throw new Error("Modal compound components must be used inside Modal");
1847
+ }
1848
+ return context;
1849
+ };
1850
+ var ModalContext_default = ModalContext;
1851
+
1852
+ // src/components/Modal/Close/ModalClose.tsx
1853
+ import { jsx as jsx9 } from "react/jsx-runtime";
1854
+ var ModalClose = ({
1855
+ children,
1856
+ accessibilityLabel,
1857
+ style
1858
+ }) => {
1859
+ const { theme } = useTheme();
1860
+ const styles = useThemeStyles(createStyles8);
1861
+ const { onClose } = useModalContext();
1862
+ if (isValidElement5(children)) {
1863
+ return cloneElement4(children, {
1864
+ accessibilityLabel: children.props.accessibilityLabel ?? accessibilityLabel,
1865
+ onPress: (event) => {
1866
+ children.props.onPress?.(event);
1867
+ onClose?.();
1868
+ }
1869
+ });
1870
+ }
1871
+ return /* @__PURE__ */ jsx9(
1872
+ Pressable4,
1873
+ {
1874
+ accessibilityRole: "button",
1875
+ accessibilityLabel: accessibilityLabel ?? "Close modal",
1876
+ onPress: onClose,
1877
+ style: [styles.closeButton, style],
1878
+ children: ({ pressed }) => {
1879
+ const closeIconColor = pressed ? theme.components.modal.closeButton.hover.fg : theme.components.modal.closeButton.default.fg;
1880
+ return /* @__PURE__ */ jsx9(
1881
+ Close,
1882
+ {
1883
+ size: theme.components.modal.closeButton.iconSize,
1884
+ color: closeIconColor
1885
+ }
1886
+ );
1887
+ }
1888
+ }
1889
+ );
1046
1890
  };
1047
- ModalBody.displayName = "ModalBody";
1891
+ ModalClose.displayName = "Modal.Close";
1048
1892
 
1049
1893
  // src/components/Modal/Content/ModalContent.tsx
1050
1894
  import { View as View6 } from "react-native";
1051
1895
 
1052
1896
  // src/components/Modal/Content/ModalContent.styles.ts
1053
- import { StyleSheet as StyleSheet9 } from "react-native";
1054
- var createStyles8 = (theme) => StyleSheet9.create({
1897
+ import { StyleSheet as StyleSheet10 } from "react-native";
1898
+ var createStyles9 = (theme) => StyleSheet10.create({
1055
1899
  content: {
1056
1900
  width: "100%",
1057
- maxWidth: 600,
1058
- maxHeight: "90%",
1059
- padding: theme.tokens.spacing[4],
1060
- gap: theme.tokens.spacing[4],
1901
+ maxWidth: theme.components.modal.content.size.md,
1902
+ maxHeight: theme.components.modal.content.nativeMaxHeight,
1903
+ padding: theme.components.modal.content.padding,
1904
+ gap: theme.components.modal.content.gap,
1061
1905
  backgroundColor: theme.components.modal.content.bg,
1062
1906
  borderColor: theme.components.modal.content.border,
1063
- borderRadius: theme.tokens.radius.lg,
1064
- borderWidth: 1,
1907
+ borderRadius: theme.components.modal.content.radius,
1908
+ borderWidth: theme.components.modal.content.borderWidth,
1065
1909
  shadowColor: theme.tokens.shadows.lg.color,
1066
1910
  shadowOffset: {
1067
1911
  width: theme.tokens.shadows.lg.x,
@@ -1074,10 +1918,10 @@ var createStyles8 = (theme) => StyleSheet9.create({
1074
1918
  });
1075
1919
 
1076
1920
  // src/components/Modal/Content/ModalContent.tsx
1077
- import { jsx as jsx9 } from "react/jsx-runtime";
1921
+ import { jsx as jsx10 } from "react/jsx-runtime";
1078
1922
  var ModalContent = ({ children, style }) => {
1079
- const styles = useThemeStyles(createStyles8);
1080
- return /* @__PURE__ */ jsx9(View6, { style: [styles.content, style], children });
1923
+ const styles = useThemeStyles(createStyles9);
1924
+ return /* @__PURE__ */ jsx10(View6, { style: [styles.content, style], children });
1081
1925
  };
1082
1926
  ModalContent.displayName = "ModalContent";
1083
1927
 
@@ -1085,107 +1929,41 @@ ModalContent.displayName = "ModalContent";
1085
1929
  import { View as View7 } from "react-native";
1086
1930
 
1087
1931
  // src/components/Modal/Footer/ModalFooter.styles.ts
1088
- import { StyleSheet as StyleSheet10 } from "react-native";
1089
- var createStyles9 = (theme) => StyleSheet10.create({
1932
+ import { StyleSheet as StyleSheet11 } from "react-native";
1933
+ var createStyles10 = (theme) => StyleSheet11.create({
1090
1934
  footer: {
1091
1935
  flexDirection: "row",
1092
- gap: theme.tokens.spacing[3],
1936
+ gap: theme.components.modal.footer.gap,
1093
1937
  justifyContent: "flex-end",
1094
- paddingTop: theme.tokens.spacing[4]
1938
+ paddingTop: theme.components.modal.footer.paddingTop
1095
1939
  }
1096
1940
  });
1097
1941
 
1098
1942
  // src/components/Modal/Footer/ModalFooter.tsx
1099
- import { jsx as jsx10 } from "react/jsx-runtime";
1943
+ import { jsx as jsx11 } from "react/jsx-runtime";
1100
1944
  var ModalFooter = ({ children, style }) => {
1101
- const styles = useThemeStyles(createStyles9);
1102
- return /* @__PURE__ */ jsx10(View7, { style: [styles.footer, style], children });
1945
+ const styles = useThemeStyles(createStyles10);
1946
+ return /* @__PURE__ */ jsx11(View7, { style: [styles.footer, style], children });
1103
1947
  };
1104
1948
  ModalFooter.displayName = "ModalFooter";
1105
1949
 
1106
1950
  // src/components/Modal/Header/ModalHeader.tsx
1107
- import { Close } from "@vellira-ui/icons";
1108
- import { Pressable as Pressable4, Text as Text6, View as View8 } from "react-native";
1109
-
1110
- // src/components/Modal/ModalContext.tsx
1111
- import { createContext as createContext2, useContext as useContext2 } from "react";
1112
- var ModalContext = createContext2(void 0);
1113
- ModalContext.displayName = "ModalContext";
1114
- var useModalContext = () => {
1115
- const context = useContext2(ModalContext);
1116
- if (!context) {
1117
- throw new Error("Modal compound components must be used inside Modal");
1118
- }
1119
- return context;
1120
- };
1121
- var ModalContext_default = ModalContext;
1122
-
1123
- // src/components/Modal/Header/ModalHeader.styles.ts
1124
- import { StyleSheet as StyleSheet11 } from "react-native";
1125
- var createStyles10 = (theme) => StyleSheet11.create({
1126
- header: {
1127
- alignItems: "center",
1128
- flexDirection: "row",
1129
- gap: theme.tokens.spacing[3],
1130
- justifyContent: "space-between",
1131
- paddingBottom: theme.tokens.spacing[4]
1132
- },
1133
- title: {
1134
- flex: 1,
1135
- color: theme.components.modal.title.fg,
1136
- fontFamily: theme.tokens.typography.family.semibold,
1137
- fontSize: theme.tokens.typography.size.lg,
1138
- lineHeight: theme.tokens.typography.lineHeight.md
1139
- },
1140
- closeButton: {
1141
- width: 32,
1142
- height: 32,
1143
- alignItems: "center",
1144
- justifyContent: "center",
1145
- backgroundColor: theme.components.modal.closeButton.default.bg,
1146
- borderRadius: theme.tokens.radius.full
1147
- },
1148
- closeButtonPressed: {
1149
- backgroundColor: theme.components.modal.closeButton.hover.bg
1150
- },
1151
- closeButtonDisabled: {
1152
- backgroundColor: theme.components.modal.closeButton.disabled.bg
1153
- }
1154
- });
1155
-
1156
- // src/components/Modal/Header/ModalHeader.tsx
1157
- import { jsx as jsx11, jsxs as jsxs5 } from "react/jsx-runtime";
1951
+ import { Text as Text6, View as View8 } from "react-native";
1952
+ import { jsx as jsx12, jsxs as jsxs5 } from "react/jsx-runtime";
1158
1953
  var ModalHeader = ({
1159
1954
  children,
1160
1955
  style,
1161
1956
  textStyle
1162
1957
  }) => {
1163
- const { theme } = useTheme();
1164
- const styles = useThemeStyles(createStyles10);
1165
- const { onClose } = useModalContext();
1958
+ const styles = useThemeStyles(createStyles8);
1166
1959
  return /* @__PURE__ */ jsxs5(View8, { style: [styles.header, style], children: [
1167
- /* @__PURE__ */ jsx11(Text6, { style: [styles.title, textStyle], children }),
1168
- onClose && /* @__PURE__ */ jsx11(
1169
- Pressable4,
1170
- {
1171
- accessibilityRole: "button",
1172
- accessibilityLabel: "Close modal",
1173
- onPress: onClose,
1174
- style: styles.closeButton,
1175
- children: ({ pressed }) => {
1176
- const closeIconColor = pressed ? theme.components.modal.closeButton.hover.fg : theme.components.modal.closeButton.default.fg;
1177
- return /* @__PURE__ */ jsx11(Close, { size: 16, color: closeIconColor });
1178
- }
1179
- }
1180
- )
1960
+ /* @__PURE__ */ jsx12(Text6, { style: [styles.title, textStyle], children }),
1961
+ /* @__PURE__ */ jsx12(ModalClose, {})
1181
1962
  ] });
1182
1963
  };
1183
1964
  ModalHeader.displayName = "ModalHeader";
1184
1965
 
1185
- // src/components/Modal/Modal.tsx
1186
- import { useModal } from "@vellira-ui/core";
1187
-
1188
- // src/components/Modal/ModalOverlay.tsx
1966
+ // src/components/Modal/Overlay/ModalOverlay.tsx
1189
1967
  import { Modal as RNModal, Pressable as Pressable5, View as View9 } from "react-native";
1190
1968
 
1191
1969
  // src/components/Modal/Modal.styles.ts
@@ -1195,7 +1973,7 @@ var createStyles11 = (theme) => StyleSheet12.create({
1195
1973
  alignItems: "center",
1196
1974
  flex: 1,
1197
1975
  justifyContent: "center",
1198
- padding: theme.tokens.spacing[5]
1976
+ padding: theme.components.modal.content.viewportMargin
1199
1977
  },
1200
1978
  backdrop: {
1201
1979
  ...StyleSheet12.absoluteFill,
@@ -1203,32 +1981,27 @@ var createStyles11 = (theme) => StyleSheet12.create({
1203
1981
  }
1204
1982
  });
1205
1983
 
1206
- // src/components/Modal/ModalOverlay.tsx
1207
- import { jsx as jsx12, jsxs as jsxs6 } from "react/jsx-runtime";
1208
- var ModalOverlay = ({
1209
- isOpen,
1210
- onClose,
1211
- closeOnBackdrop = true,
1212
- children,
1213
- overlayStyle
1214
- }) => {
1984
+ // src/components/Modal/Overlay/ModalOverlay.tsx
1985
+ import { jsx as jsx13, jsxs as jsxs6 } from "react/jsx-runtime";
1986
+ var ModalOverlay = ({ children, overlayStyle }) => {
1215
1987
  const styles = useThemeStyles(createStyles11);
1216
- return /* @__PURE__ */ jsx12(
1988
+ const { closeOnOutsidePress, onClose, onOutsideClose, open } = useModalContext();
1989
+ return /* @__PURE__ */ jsx13(
1217
1990
  RNModal,
1218
1991
  {
1219
- visible: isOpen,
1992
+ visible: open,
1220
1993
  transparent: true,
1221
1994
  animationType: "fade",
1222
1995
  onRequestClose: onClose,
1223
1996
  children: /* @__PURE__ */ jsxs6(View9, { style: [styles.overlay, overlayStyle], children: [
1224
- /* @__PURE__ */ jsx12(
1997
+ /* @__PURE__ */ jsx13(
1225
1998
  Pressable5,
1226
1999
  {
1227
2000
  testID: "modal-backdrop",
1228
- accessibilityRole: closeOnBackdrop ? "button" : void 0,
1229
- accessibilityLabel: closeOnBackdrop ? "Close modal" : void 0,
2001
+ accessibilityRole: closeOnOutsidePress ? "button" : void 0,
2002
+ accessibilityLabel: closeOnOutsidePress ? "Close modal" : void 0,
1230
2003
  style: styles.backdrop,
1231
- onPress: closeOnBackdrop ? onClose : void 0
2004
+ onPress: closeOnOutsidePress ? onOutsideClose : void 0
1232
2005
  }
1233
2006
  ),
1234
2007
  children
@@ -1237,50 +2010,111 @@ var ModalOverlay = ({
1237
2010
  );
1238
2011
  };
1239
2012
 
1240
- // src/components/Modal/Modal.tsx
1241
- import { jsx as jsx13 } from "react/jsx-runtime";
2013
+ // src/components/Modal/Root/ModalRoot.tsx
2014
+ import { jsx as jsx14 } from "react/jsx-runtime";
1242
2015
  var ModalRoot = ({
1243
- isOpen,
1244
- onClose,
1245
- closeOnBackdrop = true,
1246
- children,
1247
- overlayStyle,
1248
- contentStyle
2016
+ open,
2017
+ defaultOpen = false,
2018
+ onOpenChange,
2019
+ closeOnOutsidePress = true,
2020
+ children
1249
2021
  }) => {
1250
2022
  const modal = useModal({
1251
- isOpen,
1252
- onClose,
1253
- closeOnBackdrop
2023
+ open,
2024
+ defaultOpen,
2025
+ onOpenChange,
2026
+ closeOnOutsidePress
1254
2027
  });
1255
- return /* @__PURE__ */ jsx13(ModalContext_default.Provider, { value: { onClose: modal.onClose }, children: /* @__PURE__ */ jsx13(
1256
- ModalOverlay,
2028
+ const dismiss = useNativeDismiss({
2029
+ id: modal.contentId,
2030
+ visible: modal.open,
2031
+ closeOnOutsidePress: modal.closeOnOutsidePress,
2032
+ onClose: modal.requestClose
2033
+ });
2034
+ return /* @__PURE__ */ jsx14(
2035
+ ModalContext_default.Provider,
1257
2036
  {
1258
- isOpen: modal.isOpen,
1259
- onClose: modal.onClose,
1260
- closeOnBackdrop: modal.closeOnBackdrop,
1261
- overlayStyle,
1262
- children: /* @__PURE__ */ jsx13(ModalContent, { style: contentStyle, children })
2037
+ value: {
2038
+ closeOnOutsidePress: modal.closeOnOutsidePress,
2039
+ onClose: dismiss.requestClose,
2040
+ onOutsideClose: dismiss.requestOutsideClose,
2041
+ open: modal.open,
2042
+ setOpen: modal.setOpen
2043
+ },
2044
+ children
1263
2045
  }
1264
- ) });
2046
+ );
2047
+ };
2048
+ ModalRoot.displayName = "ModalRoot";
2049
+
2050
+ // src/components/Modal/Trigger/ModalTrigger.tsx
2051
+ import { cloneElement as cloneElement5, isValidElement as isValidElement6 } from "react";
2052
+ import { Pressable as Pressable6, Text as Text7 } from "react-native";
2053
+ import { jsx as jsx15 } from "react/jsx-runtime";
2054
+ var ModalTrigger = ({
2055
+ children,
2056
+ asChild = false,
2057
+ disabled = false,
2058
+ accessibilityLabel,
2059
+ style,
2060
+ testID
2061
+ }) => {
2062
+ const root = useModalContext();
2063
+ const child = asChild && isValidElement6(children) ? children : void 0;
2064
+ const handlePress = (event) => {
2065
+ if (disabled || child?.props.disabled) return;
2066
+ child?.props.onPress?.(event);
2067
+ root.setOpen(true);
2068
+ };
2069
+ if (child) {
2070
+ return cloneElement5(child, {
2071
+ onPress: handlePress,
2072
+ accessibilityRole: child.props.accessibilityRole ?? "button",
2073
+ accessibilityState: {
2074
+ ...child.props.accessibilityState,
2075
+ expanded: root.open,
2076
+ disabled: disabled || child.props.disabled
2077
+ },
2078
+ accessibilityLabel: accessibilityLabel ?? child.props.accessibilityLabel,
2079
+ disabled: disabled || child.props.disabled,
2080
+ style: child.props.style
2081
+ });
2082
+ }
2083
+ return /* @__PURE__ */ jsx15(
2084
+ Pressable6,
2085
+ {
2086
+ accessibilityRole: "button",
2087
+ accessibilityState: { expanded: root.open, disabled },
2088
+ accessibilityLabel,
2089
+ disabled,
2090
+ onPress: handlePress,
2091
+ style,
2092
+ testID,
2093
+ children: typeof children === "string" ? /* @__PURE__ */ jsx15(Text7, { children }) : children
2094
+ }
2095
+ );
1265
2096
  };
1266
- ModalRoot.displayName = "Modal";
2097
+ ModalTrigger.displayName = "Modal.Trigger";
1267
2098
 
1268
- // src/components/Modal/index.ts
2099
+ // src/components/Modal/Modal.tsx
1269
2100
  var Modal2 = Object.assign(ModalRoot, {
2101
+ Trigger: ModalTrigger,
2102
+ Overlay: ModalOverlay,
2103
+ Content: ModalContent,
1270
2104
  Header: ModalHeader,
1271
2105
  Body: ModalBody,
1272
2106
  Footer: ModalFooter,
1273
- Content: ModalContent
2107
+ Close: ModalClose
1274
2108
  });
2109
+ Modal2.displayName = "Modal";
1275
2110
 
1276
2111
  // src/components/RadioGroup/RadioGroup.tsx
1277
2112
  import { forwardRef } from "react";
1278
- import { useControllableState as useControllableState2 } from "@vellira-ui/core";
1279
2113
  import { View as View11 } from "react-native";
1280
2114
 
1281
2115
  // src/patterns/FormField/FormField.tsx
1282
- import { useId } from "react";
1283
- import { Text as Text7, View as View10 } from "react-native";
2116
+ import { useId as useId3 } from "react";
2117
+ import { Text as Text8, View as View10 } from "react-native";
1284
2118
 
1285
2119
  // src/patterns/FormField/FormField.styles.ts
1286
2120
  import { StyleSheet as StyleSheet13 } from "react-native";
@@ -1356,7 +2190,7 @@ var FormFieldContext = createContext3(null);
1356
2190
  var useFormFieldContext = () => useContext3(FormFieldContext);
1357
2191
 
1358
2192
  // src/patterns/FormField/FormField.tsx
1359
- import { jsx as jsx14, jsxs as jsxs7 } from "react/jsx-runtime";
2193
+ import { jsx as jsx16, jsxs as jsxs7 } from "react/jsx-runtime";
1360
2194
  function FormField({
1361
2195
  id,
1362
2196
  label,
@@ -1379,7 +2213,7 @@ function FormField({
1379
2213
  const { theme } = useTheme();
1380
2214
  const styles = useThemeStyles(createStyles12);
1381
2215
  const sizeTokens = theme.components.formField.size[size];
1382
- const generatedId = useId();
2216
+ const generatedId = useId3();
1383
2217
  const controlId = id ?? generatedId;
1384
2218
  const labelId = label ? `${controlId}-label` : void 0;
1385
2219
  const descriptionId = description ? `${controlId}-description` : void 0;
@@ -1407,7 +2241,7 @@ function FormField({
1407
2241
  style: [styles.root, { gap: sizeTokens.gap }, style],
1408
2242
  children: [
1409
2243
  label && (typeof label === "string" || typeof label === "number" ? /* @__PURE__ */ jsxs7(
1410
- Text7,
2244
+ Text8,
1411
2245
  {
1412
2246
  style: [
1413
2247
  styles.label,
@@ -1420,8 +2254,8 @@ function FormField({
1420
2254
  ],
1421
2255
  children: [
1422
2256
  label,
1423
- required && /* @__PURE__ */ jsx14(
1424
- Text7,
2257
+ required && /* @__PURE__ */ jsx16(
2258
+ Text8,
1425
2259
  {
1426
2260
  style: styles.required,
1427
2261
  accessible: false,
@@ -1429,8 +2263,8 @@ function FormField({
1429
2263
  children: " *"
1430
2264
  }
1431
2265
  ),
1432
- !required && optionalText && /* @__PURE__ */ jsx14(
1433
- Text7,
2266
+ !required && optionalText && /* @__PURE__ */ jsx16(
2267
+ Text8,
1434
2268
  {
1435
2269
  style: [
1436
2270
  styles.optional,
@@ -1442,8 +2276,8 @@ function FormField({
1442
2276
  children: optionalText
1443
2277
  }
1444
2278
  ),
1445
- labelInfo && /* @__PURE__ */ jsx14(
1446
- Text7,
2279
+ labelInfo && /* @__PURE__ */ jsx16(
2280
+ Text8,
1447
2281
  {
1448
2282
  style: [
1449
2283
  styles.labelInfo,
@@ -1459,8 +2293,8 @@ function FormField({
1459
2293
  }
1460
2294
  ) : /* @__PURE__ */ jsxs7(View10, { style: styles.customLabel, children: [
1461
2295
  label,
1462
- required && /* @__PURE__ */ jsx14(
1463
- Text7,
2296
+ required && /* @__PURE__ */ jsx16(
2297
+ Text8,
1464
2298
  {
1465
2299
  style: styles.required,
1466
2300
  accessible: false,
@@ -1471,8 +2305,8 @@ function FormField({
1471
2305
  !required && optionalText,
1472
2306
  labelInfo
1473
2307
  ] })),
1474
- description && (typeof description === "string" || typeof description === "number" ? /* @__PURE__ */ jsx14(
1475
- Text7,
2308
+ description && (typeof description === "string" || typeof description === "number" ? /* @__PURE__ */ jsx16(
2309
+ Text8,
1476
2310
  {
1477
2311
  style: [
1478
2312
  styles.description,
@@ -1486,9 +2320,9 @@ function FormField({
1486
2320
  children: description
1487
2321
  }
1488
2322
  ) : description),
1489
- /* @__PURE__ */ jsx14(FormFieldContext.Provider, { value: contextValue, children: /* @__PURE__ */ jsx14(View10, { style: [styles.control, { gap: sizeTokens.gap }, controlStyle], children }) }),
1490
- error && (typeof error === "string" || typeof error === "number" ? /* @__PURE__ */ jsx14(
1491
- Text7,
2323
+ /* @__PURE__ */ jsx16(FormFieldContext.Provider, { value: contextValue, children: /* @__PURE__ */ jsx16(View10, { style: [styles.control, { gap: sizeTokens.gap }, controlStyle], children }) }),
2324
+ error && (typeof error === "string" || typeof error === "number" ? /* @__PURE__ */ jsx16(
2325
+ Text8,
1492
2326
  {
1493
2327
  accessibilityLiveRegion: "polite",
1494
2328
  style: [
@@ -1502,7 +2336,7 @@ function FormField({
1502
2336
  ],
1503
2337
  children: error
1504
2338
  }
1505
- ) : /* @__PURE__ */ jsx14(View10, { accessibilityLiveRegion: "polite", children: error }))
2339
+ ) : /* @__PURE__ */ jsx16(View10, { accessibilityLiveRegion: "polite", children: error }))
1506
2340
  ]
1507
2341
  }
1508
2342
  );
@@ -1535,7 +2369,7 @@ function useRadioGroupContext() {
1535
2369
  }
1536
2370
 
1537
2371
  // src/components/RadioGroup/RadioGroup.tsx
1538
- import { jsx as jsx15 } from "react/jsx-runtime";
2372
+ import { jsx as jsx17 } from "react/jsx-runtime";
1539
2373
  var RadioGroup = forwardRef(
1540
2374
  ({
1541
2375
  value,
@@ -1560,7 +2394,7 @@ var RadioGroup = forwardRef(
1560
2394
  ...rest
1561
2395
  }, ref) => {
1562
2396
  const styles = useThemeStyles(createStyles13);
1563
- const [selectedValue, setSelectedValue] = useControllableState2({
2397
+ const [selectedValue, setSelectedValue] = useControllableState({
1564
2398
  value,
1565
2399
  defaultValue,
1566
2400
  onChange: onValueChange
@@ -1572,7 +2406,7 @@ var RadioGroup = forwardRef(
1572
2406
  required ? "Required." : void 0,
1573
2407
  typeof error === "string" ? error : void 0
1574
2408
  ].filter(Boolean).join(" ")) || void 0;
1575
- return /* @__PURE__ */ jsx15(
2409
+ return /* @__PURE__ */ jsx17(
1576
2410
  FormField,
1577
2411
  {
1578
2412
  label,
@@ -1584,7 +2418,7 @@ var RadioGroup = forwardRef(
1584
2418
  descriptionStyle,
1585
2419
  errorStyle,
1586
2420
  style,
1587
- children: /* @__PURE__ */ jsx15(
2421
+ children: /* @__PURE__ */ jsx17(
1588
2422
  RadioGroupProvider,
1589
2423
  {
1590
2424
  value: {
@@ -1596,7 +2430,7 @@ var RadioGroup = forwardRef(
1596
2430
  color,
1597
2431
  onValueChange: setSelectedValue
1598
2432
  },
1599
- children: /* @__PURE__ */ jsx15(
2433
+ children: /* @__PURE__ */ jsx17(
1600
2434
  View11,
1601
2435
  {
1602
2436
  ...rest,
@@ -1624,14 +2458,14 @@ var RadioGroup = forwardRef(
1624
2458
  RadioGroup.displayName = "RadioGroup";
1625
2459
 
1626
2460
  // src/components/Select/Content/SelectContent.tsx
1627
- import { useEffect as useEffect5, useRef as useRef4, useState as useState3 } from "react";
1628
- import { FlatList as FlatList2, Pressable as Pressable10, Text as Text12, View as View21 } from "react-native";
2461
+ import { useEffect as useEffect9, useRef as useRef6, useState as useState8 } from "react";
2462
+ import { FlatList as FlatList2, Pressable as Pressable11, Text as Text13, View as View21 } from "react-native";
1629
2463
 
1630
2464
  // src/components/Select/Group/SelectGroup.tsx
1631
- import { Pressable as Pressable6, Text as Text8 } from "react-native";
2465
+ import { Pressable as Pressable7, Text as Text9 } from "react-native";
1632
2466
 
1633
2467
  // src/components/Select/internal/SelectCollection.ts
1634
- import { Children as Children3, isValidElement as isValidElement5 } from "react";
2468
+ import { Children as Children3, isValidElement as isValidElement7 } from "react";
1635
2469
 
1636
2470
  // src/components/Select/internal/types.ts
1637
2471
  var selectSlotName = /* @__PURE__ */ Symbol("VelliraNativeSelectSlot");
@@ -1655,7 +2489,7 @@ var getGroupLabel = (props) => {
1655
2489
  if (props.label) return props.label;
1656
2490
  let label;
1657
2491
  Children3.forEach(props.children, (child) => {
1658
- if (label || !isValidElement5(child)) return;
2492
+ if (label || !isValidElement7(child)) return;
1659
2493
  if (getSelectSlot(child.type) === "label") {
1660
2494
  label = getTextFromNode(child.props.children);
1661
2495
  }
@@ -1666,7 +2500,7 @@ var getGroupItemValues = (children) => {
1666
2500
  const values = [];
1667
2501
  const visit = (node) => {
1668
2502
  Children3.forEach(node, (child) => {
1669
- if (!isValidElement5(child)) return;
2503
+ if (!isValidElement7(child)) return;
1670
2504
  const slot = getSelectSlot(child.type);
1671
2505
  if (slot === "content") {
1672
2506
  visit(child.props.children);
@@ -1693,7 +2527,7 @@ var parseSelectChildren = (children) => {
1693
2527
  let loading;
1694
2528
  const visit = (node, group) => {
1695
2529
  Children3.forEach(node, (child) => {
1696
- if (!isValidElement5(child)) return;
2530
+ if (!isValidElement7(child)) return;
1697
2531
  const slot = getSelectSlot(child.type);
1698
2532
  if (slot === "content") {
1699
2533
  visit(child.props.children, group);
@@ -1805,14 +2639,14 @@ var createGroupStyles = (theme) => StyleSheet15.create({
1805
2639
  });
1806
2640
 
1807
2641
  // src/components/Select/Group/SelectGroup.tsx
1808
- import { jsx as jsx16, jsxs as jsxs8 } from "react/jsx-runtime";
2642
+ import { jsx as jsx18, jsxs as jsxs8 } from "react/jsx-runtime";
1809
2643
  var SelectGroup = createSelectSlot(
1810
2644
  "group",
1811
2645
  "Select.Group"
1812
2646
  );
1813
2647
  var SelectGroupLabelRow = ({ label }) => {
1814
2648
  const styles = useThemeStyles(createGroupStyles);
1815
- return /* @__PURE__ */ jsx16(Text8, { style: styles.groupLabel, children: label });
2649
+ return /* @__PURE__ */ jsx18(Text9, { style: styles.groupLabel, children: label });
1816
2650
  };
1817
2651
  var SelectGroupActionRow = ({
1818
2652
  label,
@@ -1826,7 +2660,7 @@ var SelectGroupActionRow = ({
1826
2660
  const isMixed = selectedCount > 0 && selectedCount < itemCount;
1827
2661
  const resolvedLabel = selectLabel ?? label;
1828
2662
  return /* @__PURE__ */ jsxs8(
1829
- Pressable6,
2663
+ Pressable7,
1830
2664
  {
1831
2665
  accessibilityRole: "button",
1832
2666
  accessibilityLabel: resolvedLabel,
@@ -1840,8 +2674,8 @@ var SelectGroupActionRow = ({
1840
2674
  onPress,
1841
2675
  style: styles.groupAction,
1842
2676
  children: [
1843
- /* @__PURE__ */ jsx16(Text8, { style: styles.groupActionText, children: resolvedLabel }),
1844
- /* @__PURE__ */ jsxs8(Text8, { style: styles.groupActionMeta, children: [
2677
+ /* @__PURE__ */ jsx18(Text9, { style: styles.groupActionText, children: resolvedLabel }),
2678
+ /* @__PURE__ */ jsxs8(Text9, { style: styles.groupActionMeta, children: [
1845
2679
  selectedCount,
1846
2680
  "/",
1847
2681
  itemCount
@@ -1861,14 +2695,14 @@ var SelectLabel = createSelectSlot(
1861
2695
 
1862
2696
  // src/components/Select/Group/SelectSeparator.tsx
1863
2697
  import { View as View12 } from "react-native";
1864
- import { jsx as jsx17 } from "react/jsx-runtime";
2698
+ import { jsx as jsx19 } from "react/jsx-runtime";
1865
2699
  var SelectSeparator = createSelectSlot(
1866
2700
  "separator",
1867
2701
  "Select.Separator"
1868
2702
  );
1869
2703
  var SelectSeparatorRow = () => {
1870
2704
  const styles = useThemeStyles(createGroupStyles);
1871
- return /* @__PURE__ */ jsx17(View12, { style: styles.separator });
2705
+ return /* @__PURE__ */ jsx19(View12, { style: styles.separator });
1872
2706
  };
1873
2707
  SelectSeparatorRow.displayName = "Select.SeparatorRow";
1874
2708
 
@@ -1884,9 +2718,9 @@ var useSelectContext = () => {
1884
2718
  };
1885
2719
 
1886
2720
  // src/components/Select/Item/SelectItem.tsx
1887
- import { cloneElement as cloneElement4, isValidElement as isValidElement6 } from "react";
2721
+ import { cloneElement as cloneElement6, isValidElement as isValidElement8 } from "react";
1888
2722
  import { Check } from "@vellira-ui/icons";
1889
- import { Pressable as Pressable7, Text as Text9, View as View13 } from "react-native";
2723
+ import { Pressable as Pressable8, Text as Text10, View as View13 } from "react-native";
1890
2724
 
1891
2725
  // src/components/Select/Item/SelectItem.styles.ts
1892
2726
  import { StyleSheet as StyleSheet16 } from "react-native";
@@ -1948,17 +2782,17 @@ var createItemStyles = (theme) => StyleSheet16.create({
1948
2782
  });
1949
2783
 
1950
2784
  // src/components/Select/Item/SelectItem.tsx
1951
- import { Fragment as Fragment2, jsx as jsx18, jsxs as jsxs9 } from "react/jsx-runtime";
2785
+ import { Fragment as Fragment2, jsx as jsx20, jsxs as jsxs9 } from "react/jsx-runtime";
1952
2786
  var renderNodeOrText = (node, textStyle, fallback) => {
1953
2787
  if (typeof node === "string" || typeof node === "number") {
1954
- return /* @__PURE__ */ jsx18(Text9, { style: textStyle, children: node });
2788
+ return /* @__PURE__ */ jsx20(Text10, { style: textStyle, children: node });
1955
2789
  }
1956
- if (isValidElement6(node) && node.type === Text9) {
1957
- return cloneElement4(node, {
2790
+ if (isValidElement8(node) && node.type === Text10) {
2791
+ return cloneElement6(node, {
1958
2792
  style: [textStyle, node.props.style]
1959
2793
  });
1960
2794
  }
1961
- return node ?? (fallback ? /* @__PURE__ */ jsx18(Text9, { style: textStyle, children: fallback }) : null);
2795
+ return node ?? (fallback ? /* @__PURE__ */ jsx20(Text10, { style: textStyle, children: fallback }) : null);
1962
2796
  };
1963
2797
  var SelectItem = createSelectSlot(
1964
2798
  "item",
@@ -1982,8 +2816,8 @@ var SelectItemRow = ({
1982
2816
  }
1983
2817
  return pressed ? optionPalette.pressed : theme.components.select.option.default;
1984
2818
  };
1985
- return /* @__PURE__ */ jsx18(
1986
- Pressable7,
2819
+ return /* @__PURE__ */ jsx20(
2820
+ Pressable8,
1987
2821
  {
1988
2822
  disabled: isDisabled,
1989
2823
  accessibilityRole: "button",
@@ -2017,7 +2851,7 @@ var SelectItemRow = ({
2017
2851
  }),
2018
2852
  [styles.optionLabel, { color: optionFg }]
2019
2853
  ) : /* @__PURE__ */ jsxs9(Fragment2, { children: [
2020
- option.icon && /* @__PURE__ */ jsx18(View13, { style: styles.optionIcon, children: isValidElement6(option.icon) ? cloneElement4(
2854
+ option.icon && /* @__PURE__ */ jsx20(View13, { style: styles.optionIcon, children: isValidElement8(option.icon) ? cloneElement6(
2021
2855
  option.icon,
2022
2856
  {
2023
2857
  color: optionFg,
@@ -2025,16 +2859,16 @@ var SelectItemRow = ({
2025
2859
  }
2026
2860
  ) : option.icon }),
2027
2861
  /* @__PURE__ */ jsxs9(View13, { style: styles.optionTextWrap, children: [
2028
- /* @__PURE__ */ jsx18(
2029
- Text9,
2862
+ /* @__PURE__ */ jsx20(
2863
+ Text10,
2030
2864
  {
2031
2865
  numberOfLines: 1,
2032
2866
  style: [styles.optionLabel, { color: optionFg }],
2033
2867
  children: option.label
2034
2868
  }
2035
2869
  ),
2036
- option.description && /* @__PURE__ */ jsx18(
2037
- Text9,
2870
+ option.description && /* @__PURE__ */ jsx20(
2871
+ Text10,
2038
2872
  {
2039
2873
  numberOfLines: 2,
2040
2874
  style: [styles.optionDescription, { color: descriptionFg }],
@@ -2042,7 +2876,7 @@ var SelectItemRow = ({
2042
2876
  }
2043
2877
  )
2044
2878
  ] }),
2045
- option.badge && /* @__PURE__ */ jsx18(
2879
+ option.badge && /* @__PURE__ */ jsx20(
2046
2880
  View13,
2047
2881
  {
2048
2882
  style: [
@@ -2058,7 +2892,7 @@ var SelectItemRow = ({
2058
2892
  ])
2059
2893
  }
2060
2894
  ),
2061
- isSelected && /* @__PURE__ */ jsx18(View13, { style: styles.check, children: /* @__PURE__ */ jsx18(Check, { width: 16, height: 16, color: optionFg }) })
2895
+ isSelected && /* @__PURE__ */ jsx20(View13, { style: styles.check, children: /* @__PURE__ */ jsx20(Check, { width: 16, height: 16, color: optionFg }) })
2062
2896
  ] });
2063
2897
  }
2064
2898
  }
@@ -2085,7 +2919,7 @@ var SelectItemIcon = createSelectSlot(
2085
2919
  );
2086
2920
 
2087
2921
  // src/components/Select/Presentation/SelectBackdrop.tsx
2088
- import { Pressable as Pressable8 } from "react-native";
2922
+ import { Pressable as Pressable9 } from "react-native";
2089
2923
 
2090
2924
  // src/components/Select/Presentation/SelectPresentation.styles.ts
2091
2925
  import { StyleSheet as StyleSheet17 } from "react-native";
@@ -2160,14 +2994,14 @@ var createPresentationStyles = (theme) => StyleSheet17.create({
2160
2994
  });
2161
2995
 
2162
2996
  // src/components/Select/Presentation/SelectBackdrop.tsx
2163
- import { jsx as jsx19 } from "react/jsx-runtime";
2997
+ import { jsx as jsx21 } from "react/jsx-runtime";
2164
2998
  var SelectBackdrop = ({
2165
2999
  onClose,
2166
3000
  dismissOnBackdropPress
2167
3001
  }) => {
2168
3002
  const styles = useThemeStyles(createPresentationStyles);
2169
- return /* @__PURE__ */ jsx19(
2170
- Pressable8,
3003
+ return /* @__PURE__ */ jsx21(
3004
+ Pressable9,
2171
3005
  {
2172
3006
  style: styles.backdrop,
2173
3007
  onPress: dismissOnBackdropPress ? onClose : void 0,
@@ -2180,16 +3014,16 @@ SelectBackdrop.displayName = "Select.Backdrop";
2180
3014
 
2181
3015
  // src/components/Select/Presentation/SelectHandle.tsx
2182
3016
  import { View as View14 } from "react-native";
2183
- import { jsx as jsx20 } from "react/jsx-runtime";
3017
+ import { jsx as jsx22 } from "react/jsx-runtime";
2184
3018
  var SelectHandle = () => {
2185
3019
  const styles = useThemeStyles(createPresentationStyles);
2186
- return /* @__PURE__ */ jsx20(View14, { style: styles.handleWrap, accessible: false, children: /* @__PURE__ */ jsx20(View14, { style: styles.handle }) });
3020
+ return /* @__PURE__ */ jsx22(View14, { style: styles.handleWrap, accessible: false, children: /* @__PURE__ */ jsx22(View14, { style: styles.handle }) });
2187
3021
  };
2188
3022
  SelectHandle.displayName = "Select.Handle";
2189
3023
 
2190
3024
  // src/components/Select/Presentation/SelectModal.tsx
2191
3025
  import { Modal as Modal3, View as View15 } from "react-native";
2192
- import { jsx as jsx21, jsxs as jsxs10 } from "react/jsx-runtime";
3026
+ import { jsx as jsx23, jsxs as jsxs10 } from "react/jsx-runtime";
2193
3027
  var SelectModal = ({
2194
3028
  visible,
2195
3029
  onClose,
@@ -2198,7 +3032,7 @@ var SelectModal = ({
2198
3032
  children
2199
3033
  }) => {
2200
3034
  const styles = useThemeStyles(createPresentationStyles);
2201
- return /* @__PURE__ */ jsx21(
3035
+ return /* @__PURE__ */ jsx23(
2202
3036
  Modal3,
2203
3037
  {
2204
3038
  transparent: true,
@@ -2211,14 +3045,14 @@ var SelectModal = ({
2211
3045
  style: [styles.modalRoot, styles.modalPresentationRoot],
2212
3046
  testID: "select-content-root",
2213
3047
  children: [
2214
- /* @__PURE__ */ jsx21(
3048
+ /* @__PURE__ */ jsx23(
2215
3049
  SelectBackdrop,
2216
3050
  {
2217
3051
  onClose,
2218
3052
  dismissOnBackdropPress
2219
3053
  }
2220
3054
  ),
2221
- /* @__PURE__ */ jsx21(
3055
+ /* @__PURE__ */ jsx23(
2222
3056
  View15,
2223
3057
  {
2224
3058
  style: [styles.content, styles.modalPresentation, contentStyle],
@@ -2236,7 +3070,7 @@ SelectModal.displayName = "Select.Modal";
2236
3070
 
2237
3071
  // src/components/Select/Presentation/SelectPopover.tsx
2238
3072
  import { Modal as Modal4, View as View16 } from "react-native";
2239
- import { jsx as jsx22, jsxs as jsxs11 } from "react/jsx-runtime";
3073
+ import { jsx as jsx24, jsxs as jsxs11 } from "react/jsx-runtime";
2240
3074
  var SelectPopover = ({
2241
3075
  visible,
2242
3076
  onClose,
@@ -2248,7 +3082,7 @@ var SelectPopover = ({
2248
3082
  children
2249
3083
  }) => {
2250
3084
  const styles = useThemeStyles(createPresentationStyles);
2251
- return /* @__PURE__ */ jsx22(
3085
+ return /* @__PURE__ */ jsx24(
2252
3086
  Modal4,
2253
3087
  {
2254
3088
  transparent: true,
@@ -2265,14 +3099,14 @@ var SelectPopover = ({
2265
3099
  ],
2266
3100
  testID: "select-content-root",
2267
3101
  children: [
2268
- /* @__PURE__ */ jsx22(
3102
+ /* @__PURE__ */ jsx24(
2269
3103
  SelectBackdrop,
2270
3104
  {
2271
3105
  onClose,
2272
3106
  dismissOnBackdropPress
2273
3107
  }
2274
3108
  ),
2275
- /* @__PURE__ */ jsx22(
3109
+ /* @__PURE__ */ jsx24(
2276
3110
  View16,
2277
3111
  {
2278
3112
  style: [
@@ -2296,7 +3130,7 @@ SelectPopover.displayName = "Select.Popover";
2296
3130
 
2297
3131
  // src/components/Select/Presentation/SelectSheet.tsx
2298
3132
  import { Modal as Modal5, View as View17 } from "react-native";
2299
- import { jsx as jsx23, jsxs as jsxs12 } from "react/jsx-runtime";
3133
+ import { jsx as jsx25, jsxs as jsxs12 } from "react/jsx-runtime";
2300
3134
  var SelectSheet = ({
2301
3135
  visible,
2302
3136
  onClose,
@@ -2305,7 +3139,7 @@ var SelectSheet = ({
2305
3139
  children
2306
3140
  }) => {
2307
3141
  const styles = useThemeStyles(createPresentationStyles);
2308
- return /* @__PURE__ */ jsx23(
3142
+ return /* @__PURE__ */ jsx25(
2309
3143
  Modal5,
2310
3144
  {
2311
3145
  transparent: true,
@@ -2318,7 +3152,7 @@ var SelectSheet = ({
2318
3152
  style: [styles.modalRoot, styles.sheetRoot],
2319
3153
  testID: "select-content-root",
2320
3154
  children: [
2321
- /* @__PURE__ */ jsx23(
3155
+ /* @__PURE__ */ jsx25(
2322
3156
  SelectBackdrop,
2323
3157
  {
2324
3158
  onClose,
@@ -2331,7 +3165,7 @@ var SelectSheet = ({
2331
3165
  style: [styles.content, styles.sheet, contentStyle],
2332
3166
  testID: "select-sheet",
2333
3167
  children: [
2334
- /* @__PURE__ */ jsx23(SelectHandle, {}),
3168
+ /* @__PURE__ */ jsx25(SelectHandle, {}),
2335
3169
  children
2336
3170
  ]
2337
3171
  }
@@ -2420,11 +3254,11 @@ var createContentStyles = (theme) => StyleSheet18.create({
2420
3254
  });
2421
3255
 
2422
3256
  // src/components/Select/Content/SelectEmpty.tsx
2423
- import { Text as Text10, View as View18 } from "react-native";
2424
- import { jsx as jsx24 } from "react/jsx-runtime";
3257
+ import { Text as Text11, View as View18 } from "react-native";
3258
+ import { jsx as jsx26 } from "react/jsx-runtime";
2425
3259
  var renderText = (node, style) => {
2426
3260
  if (typeof node === "string" || typeof node === "number") {
2427
- return /* @__PURE__ */ jsx24(Text10, { style, children: node });
3261
+ return /* @__PURE__ */ jsx26(Text11, { style, children: node });
2428
3262
  }
2429
3263
  return node;
2430
3264
  };
@@ -2435,16 +3269,16 @@ var SelectEmpty = createSelectSlot(
2435
3269
  var SelectEmptyState = () => {
2436
3270
  const styles = useThemeStyles(createContentStyles);
2437
3271
  const { empty } = useSelectContext();
2438
- return /* @__PURE__ */ jsx24(View18, { style: styles.empty, children: renderText(empty, styles.emptyText) });
3272
+ return /* @__PURE__ */ jsx26(View18, { style: styles.empty, children: renderText(empty, styles.emptyText) });
2439
3273
  };
2440
3274
  SelectEmptyState.displayName = "Select.EmptyState";
2441
3275
 
2442
3276
  // src/components/Select/Content/SelectLoading.tsx
2443
- import { ActivityIndicator, Text as Text11, View as View19 } from "react-native";
2444
- import { jsx as jsx25, jsxs as jsxs13 } from "react/jsx-runtime";
3277
+ import { ActivityIndicator, Text as Text12, View as View19 } from "react-native";
3278
+ import { jsx as jsx27, jsxs as jsxs13 } from "react/jsx-runtime";
2445
3279
  var renderText2 = (node, style) => {
2446
3280
  if (typeof node === "string" || typeof node === "number") {
2447
- return /* @__PURE__ */ jsx25(Text11, { style, children: node });
3281
+ return /* @__PURE__ */ jsx27(Text12, { style, children: node });
2448
3282
  }
2449
3283
  return node;
2450
3284
  };
@@ -2457,7 +3291,7 @@ var SelectLoadingState = () => {
2457
3291
  const styles = useThemeStyles(createContentStyles);
2458
3292
  const { loadingContent } = useSelectContext();
2459
3293
  return /* @__PURE__ */ jsxs13(View19, { style: styles.loading, children: [
2460
- /* @__PURE__ */ jsx25(
3294
+ /* @__PURE__ */ jsx27(
2461
3295
  ActivityIndicator,
2462
3296
  {
2463
3297
  testID: "select-content-loading-indicator",
@@ -2471,9 +3305,9 @@ var SelectLoadingState = () => {
2471
3305
  SelectLoadingState.displayName = "Select.LoadingState";
2472
3306
 
2473
3307
  // src/components/Select/Content/SelectSearch.tsx
2474
- import { useEffect as useEffect4 } from "react";
2475
- import { Close as Close2, Search } from "@vellira-ui/icons";
2476
- import { Pressable as Pressable9, TextInput, View as View20 } from "react-native";
3308
+ import { useEffect as useEffect8 } from "react";
3309
+ import { Close as Close2, Search as Search2 } from "@vellira-ui/icons";
3310
+ import { Pressable as Pressable10, TextInput as TextInput2, View as View20 } from "react-native";
2477
3311
 
2478
3312
  // src/components/Select/Content/SelectSearch.styles.ts
2479
3313
  import { StyleSheet as StyleSheet19 } from "react-native";
@@ -2519,7 +3353,7 @@ var createSearchStyles = (theme) => StyleSheet19.create({
2519
3353
  });
2520
3354
 
2521
3355
  // src/components/Select/Content/SelectSearch.tsx
2522
- import { jsx as jsx26, jsxs as jsxs14 } from "react/jsx-runtime";
3356
+ import { jsx as jsx28, jsxs as jsxs14 } from "react/jsx-runtime";
2523
3357
  var SelectSearch = createSelectSlot(
2524
3358
  "search",
2525
3359
  "Select.Search"
@@ -2537,7 +3371,7 @@ var SelectSearchField = () => {
2537
3371
  virtual
2538
3372
  } = useSelectContext();
2539
3373
  const shouldAutoFocus = !virtual || selectedRowIndex === 0;
2540
- useEffect4(() => {
3374
+ useEffect8(() => {
2541
3375
  if (!shouldAutoFocus) return;
2542
3376
  const focusTimer = setTimeout(() => {
2543
3377
  searchInputRef.current?.focus();
@@ -2545,14 +3379,14 @@ var SelectSearchField = () => {
2545
3379
  return () => clearTimeout(focusTimer);
2546
3380
  }, [searchInputRef, shouldAutoFocus]);
2547
3381
  return /* @__PURE__ */ jsxs14(View20, { style: styles.searchWrap, children: [
2548
- /* @__PURE__ */ jsx26(
3382
+ /* @__PURE__ */ jsx28(
2549
3383
  View20,
2550
3384
  {
2551
3385
  style: styles.searchIcon,
2552
3386
  accessibilityElementsHidden: true,
2553
3387
  importantForAccessibility: "no",
2554
- children: /* @__PURE__ */ jsx26(
2555
- Search,
3388
+ children: /* @__PURE__ */ jsx28(
3389
+ Search2,
2556
3390
  {
2557
3391
  width: 16,
2558
3392
  height: 16,
@@ -2561,8 +3395,8 @@ var SelectSearchField = () => {
2561
3395
  )
2562
3396
  }
2563
3397
  ),
2564
- /* @__PURE__ */ jsx26(
2565
- TextInput,
3398
+ /* @__PURE__ */ jsx28(
3399
+ TextInput2,
2566
3400
  {
2567
3401
  ref: searchInputRef,
2568
3402
  value: query,
@@ -2575,15 +3409,15 @@ var SelectSearchField = () => {
2575
3409
  style: [styles.searchInput, searchStyle]
2576
3410
  }
2577
3411
  ),
2578
- query && /* @__PURE__ */ jsx26(
2579
- Pressable9,
3412
+ query && /* @__PURE__ */ jsx28(
3413
+ Pressable10,
2580
3414
  {
2581
3415
  accessibilityRole: "button",
2582
3416
  accessibilityLabel: "Clear search",
2583
3417
  hitSlop: 8,
2584
3418
  onPress: () => setQuery(""),
2585
3419
  style: styles.searchClearButton,
2586
- children: /* @__PURE__ */ jsx26(
3420
+ children: /* @__PURE__ */ jsx28(
2587
3421
  Close2,
2588
3422
  {
2589
3423
  width: 14,
@@ -2598,15 +3432,15 @@ var SelectSearchField = () => {
2598
3432
  SelectSearchField.displayName = "Select.SearchField";
2599
3433
 
2600
3434
  // src/components/Select/Content/SelectContent.tsx
2601
- import { Fragment as Fragment3, jsx as jsx27, jsxs as jsxs15 } from "react/jsx-runtime";
3435
+ import { Fragment as Fragment3, jsx as jsx29, jsxs as jsxs15 } from "react/jsx-runtime";
2602
3436
  var SelectContent = createSelectSlot(
2603
3437
  "content",
2604
3438
  "Select.Content"
2605
3439
  );
2606
3440
  var SelectContentSurface = () => {
2607
3441
  const styles = useThemeStyles(createContentStyles);
2608
- const wasOpenRef = useRef4(false);
2609
- const [openCycle, setOpenCycle] = useState3(0);
3442
+ const wasOpenRef = useRef6(false);
3443
+ const [openCycle, setOpenCycle] = useState8(0);
2610
3444
  const context = useSelectContext();
2611
3445
  const {
2612
3446
  isOpen,
@@ -2633,7 +3467,7 @@ var SelectContentSurface = () => {
2633
3467
  } = context;
2634
3468
  const shouldSeedSelectedPosition = Boolean(context.virtual) && selectedRowIndex > 0 && query === "";
2635
3469
  const initialScrollIndex = shouldSeedSelectedPosition ? selectedRowIndex : void 0;
2636
- useEffect5(() => {
3470
+ useEffect9(() => {
2637
3471
  if (isOpen && !wasOpenRef.current) {
2638
3472
  setOpenCycle((cycle) => cycle + 1);
2639
3473
  }
@@ -2648,7 +3482,7 @@ var SelectContentSurface = () => {
2648
3482
  const selectedGroupCount = selectedOptions.filter(
2649
3483
  (option) => enabledGroupValues.includes(option.value)
2650
3484
  ).length;
2651
- return /* @__PURE__ */ jsx27(
3485
+ return /* @__PURE__ */ jsx29(
2652
3486
  SelectGroupActionRow,
2653
3487
  {
2654
3488
  label: item.label,
@@ -2659,14 +3493,14 @@ var SelectContentSurface = () => {
2659
3493
  }
2660
3494
  );
2661
3495
  }
2662
- return /* @__PURE__ */ jsx27(SelectGroupLabelRow, { label: item.label });
3496
+ return /* @__PURE__ */ jsx29(SelectGroupLabelRow, { label: item.label });
2663
3497
  }
2664
3498
  if (item.type === "separator") {
2665
- return /* @__PURE__ */ jsx27(SelectSeparatorRow, {});
3499
+ return /* @__PURE__ */ jsx29(SelectSeparatorRow, {});
2666
3500
  }
2667
3501
  const isSelected = selectedValues.includes(item.option.value);
2668
3502
  const maxReached = !isSelected && typeof maxSelected === "number" && selectedValues.length >= maxSelected;
2669
- return /* @__PURE__ */ jsx27(
3503
+ return /* @__PURE__ */ jsx29(
2670
3504
  SelectItemRow,
2671
3505
  {
2672
3506
  option: item.option,
@@ -2686,34 +3520,34 @@ var SelectContentSurface = () => {
2686
3520
  accessibilityRole: "toolbar",
2687
3521
  accessibilityLabel: `${resolvedLabel} selection actions`,
2688
3522
  children: [
2689
- /* @__PURE__ */ jsx27(
2690
- Pressable10,
3523
+ /* @__PURE__ */ jsx29(
3524
+ Pressable11,
2691
3525
  {
2692
3526
  onPress: closeContent,
2693
3527
  hitSlop: 8,
2694
3528
  style: styles.toolbarAction,
2695
3529
  accessibilityRole: "button",
2696
3530
  accessibilityLabel: "Close selection",
2697
- children: /* @__PURE__ */ jsx27(Text12, { style: styles.cancelText, children: "Cancel" })
3531
+ children: /* @__PURE__ */ jsx29(Text13, { style: styles.cancelText, children: "Cancel" })
2698
3532
  }
2699
3533
  ),
2700
- /* @__PURE__ */ jsx27(Text12, { style: styles.title, numberOfLines: 1, accessibilityRole: "header", children: resolvedLabel }),
2701
- /* @__PURE__ */ jsx27(
2702
- Pressable10,
3534
+ /* @__PURE__ */ jsx29(Text13, { style: styles.title, numberOfLines: 1, accessibilityRole: "header", children: resolvedLabel }),
3535
+ /* @__PURE__ */ jsx29(
3536
+ Pressable11,
2703
3537
  {
2704
3538
  onPress: closeContent,
2705
3539
  hitSlop: 8,
2706
3540
  style: styles.toolbarAction,
2707
3541
  accessibilityRole: "button",
2708
3542
  accessibilityLabel: "Done",
2709
- children: /* @__PURE__ */ jsx27(Text12, { style: styles.doneText, children: "Done" })
3543
+ children: /* @__PURE__ */ jsx29(Text13, { style: styles.doneText, children: "Done" })
2710
3544
  }
2711
3545
  )
2712
3546
  ]
2713
3547
  }
2714
3548
  ),
2715
- searchable && /* @__PURE__ */ jsx27(SelectSearchField, {}),
2716
- loading && filteredRows.length === 0 ? /* @__PURE__ */ jsx27(SelectLoadingState, {}) : filteredRows.length === 0 ? /* @__PURE__ */ jsx27(SelectEmptyState, {}) : /* @__PURE__ */ jsx27(
3549
+ searchable && /* @__PURE__ */ jsx29(SelectSearchField, {}),
3550
+ loading && filteredRows.length === 0 ? /* @__PURE__ */ jsx29(SelectLoadingState, {}) : filteredRows.length === 0 ? /* @__PURE__ */ jsx29(SelectEmptyState, {}) : /* @__PURE__ */ jsx29(
2717
3551
  FlatList2,
2718
3552
  {
2719
3553
  data: filteredRows,
@@ -2735,7 +3569,7 @@ var SelectContentSurface = () => {
2735
3569
  )
2736
3570
  ] });
2737
3571
  if (resolvedPresentation === "sheet") {
2738
- return /* @__PURE__ */ jsx27(
3572
+ return /* @__PURE__ */ jsx29(
2739
3573
  SelectSheet,
2740
3574
  {
2741
3575
  visible: isOpen,
@@ -2747,7 +3581,7 @@ var SelectContentSurface = () => {
2747
3581
  );
2748
3582
  }
2749
3583
  if (resolvedPresentation === "popover") {
2750
- return /* @__PURE__ */ jsx27(
3584
+ return /* @__PURE__ */ jsx29(
2751
3585
  SelectPopover,
2752
3586
  {
2753
3587
  visible: isOpen,
@@ -2761,7 +3595,7 @@ var SelectContentSurface = () => {
2761
3595
  }
2762
3596
  );
2763
3597
  }
2764
- return /* @__PURE__ */ jsx27(
3598
+ return /* @__PURE__ */ jsx29(
2765
3599
  SelectModal,
2766
3600
  {
2767
3601
  visible: isOpen,
@@ -2775,8 +3609,7 @@ var SelectContentSurface = () => {
2775
3609
  SelectContentSurface.displayName = "Select.ContentSurface";
2776
3610
 
2777
3611
  // src/components/Select/Root/SelectRoot.tsx
2778
- import { useMemo as useMemo7, useRef as useRef5, useState as useState5 } from "react";
2779
- import { useSelect } from "@vellira-ui/core";
3612
+ import { useId as useId4, useMemo as useMemo8, useRef as useRef7, useState as useState10 } from "react";
2780
3613
  import { View as View23 } from "react-native";
2781
3614
 
2782
3615
  // src/components/Select/internal/useSelectAccessibility.ts
@@ -2807,17 +3640,17 @@ var useSelectAccessibility = ({
2807
3640
  };
2808
3641
 
2809
3642
  // src/components/Select/internal/useSelectCollection.ts
2810
- import { useMemo as useMemo5 } from "react";
3643
+ import { useMemo as useMemo6 } from "react";
2811
3644
  var useSelectCollection = (children, optionsProp) => {
2812
- const parsedChildren = useMemo5(
3645
+ const parsedChildren = useMemo6(
2813
3646
  () => parseSelectChildren(children),
2814
3647
  [children]
2815
3648
  );
2816
- const options = useMemo5(
3649
+ const options = useMemo6(
2817
3650
  () => [...optionsProp ?? [], ...parsedChildren.options],
2818
3651
  [optionsProp, parsedChildren.options]
2819
3652
  );
2820
- const rows = useMemo5(() => {
3653
+ const rows = useMemo6(() => {
2821
3654
  if (parsedChildren.rows.length > 0) {
2822
3655
  return parsedChildren.rows;
2823
3656
  }
@@ -2848,7 +3681,7 @@ var useSelectPresentation = (presentation = "auto") => {
2848
3681
  };
2849
3682
 
2850
3683
  // src/components/Select/internal/useSelectSearch.ts
2851
- import { useEffect as useEffect6, useMemo as useMemo6, useState as useState4 } from "react";
3684
+ import { useEffect as useEffect10, useMemo as useMemo7, useState as useState9 } from "react";
2852
3685
  var useSelectSearch = ({
2853
3686
  rows,
2854
3687
  isOpen,
@@ -2858,10 +3691,10 @@ var useSelectSearch = ({
2858
3691
  filterOptions,
2859
3692
  filter = defaultSelectFilter
2860
3693
  }) => {
2861
- const [query, setQuery] = useState4("");
3694
+ const [query, setQuery] = useState9("");
2862
3695
  const shouldSearch = searchable ?? searchableFromChildren ?? Boolean(onSearch);
2863
3696
  const shouldFilter = filterOptions ?? !onSearch;
2864
- const filteredRows = useMemo6(() => {
3697
+ const filteredRows = useMemo7(() => {
2865
3698
  if (!query || !shouldFilter) return rows;
2866
3699
  const visibleRows = [];
2867
3700
  let pendingGroup;
@@ -2888,7 +3721,7 @@ var useSelectSearch = ({
2888
3721
  return index > 0 && index < collection.length - 1 && collection[index - 1]?.type !== "separator";
2889
3722
  });
2890
3723
  }, [filter, query, rows, shouldFilter]);
2891
- useEffect6(() => {
3724
+ useEffect10(() => {
2892
3725
  if (!isOpen) {
2893
3726
  setQuery("");
2894
3727
  return;
@@ -2912,9 +3745,9 @@ var SelectIcon = createSelectSlot(
2912
3745
  );
2913
3746
 
2914
3747
  // src/components/Select/Trigger/SelectTrigger.tsx
2915
- import { cloneElement as cloneElement5, isValidElement as isValidElement7 } from "react";
3748
+ import { cloneElement as cloneElement7, isValidElement as isValidElement9 } from "react";
2916
3749
  import { ChevronDown as ChevronDown2, Close as Close3 } from "@vellira-ui/icons";
2917
- import { ActivityIndicator as ActivityIndicator2, Pressable as Pressable11, Text as Text13, View as View22 } from "react-native";
3750
+ import { ActivityIndicator as ActivityIndicator2, Pressable as Pressable12, Text as Text14, View as View22 } from "react-native";
2918
3751
 
2919
3752
  // src/components/Select/Trigger/SelectTrigger.styles.ts
2920
3753
  import { StyleSheet as StyleSheet20 } from "react-native";
@@ -2998,7 +3831,7 @@ var createTriggerStyles = (theme) => StyleSheet20.create({
2998
3831
  });
2999
3832
 
3000
3833
  // src/components/Select/Trigger/SelectTrigger.tsx
3001
- import { jsx as jsx28, jsxs as jsxs16 } from "react/jsx-runtime";
3834
+ import { jsx as jsx30, jsxs as jsxs16 } from "react/jsx-runtime";
3002
3835
  var SelectTriggerSlot = createSelectSlot(
3003
3836
  "trigger",
3004
3837
  "Select.Trigger"
@@ -3042,7 +3875,7 @@ function SelectTrigger({
3042
3875
  };
3043
3876
  const resolvedAccessibilityHint = accessibilityHint ?? (hasError ? "Invalid selection. Opens a list of options" : required ? "Required. Opens a list of options" : "Opens a list of options");
3044
3877
  const iconColor = disabled ? theme.components.select.trigger.disabled.icon : triggerState.icon;
3045
- const renderIcon = (icon) => isValidElement7(icon) ? cloneElement5(icon, { color: iconColor, size: resolvedIconSize }) : null;
3878
+ const renderIcon = (icon) => isValidElement9(icon) ? cloneElement7(icon, { color: iconColor, size: resolvedIconSize }) : null;
3046
3879
  const renderValue = () => {
3047
3880
  const valueStyle = [
3048
3881
  styles.text,
@@ -3055,10 +3888,10 @@ function SelectTrigger({
3055
3888
  textStyle
3056
3889
  ];
3057
3890
  if (typeof displayText === "string" || typeof displayText === "number") {
3058
- return /* @__PURE__ */ jsx28(Text13, { numberOfLines: 1, style: valueStyle, children: displayText });
3891
+ return /* @__PURE__ */ jsx30(Text14, { numberOfLines: 1, style: valueStyle, children: displayText });
3059
3892
  }
3060
- if (isValidElement7(displayText) && displayText.type === Text13) {
3061
- return cloneElement5(displayText, {
3893
+ if (isValidElement9(displayText) && displayText.type === Text14) {
3894
+ return cloneElement7(displayText, {
3062
3895
  numberOfLines: displayText.props.numberOfLines ?? 1,
3063
3896
  style: [valueStyle, displayText.props.style]
3064
3897
  });
@@ -3066,7 +3899,7 @@ function SelectTrigger({
3066
3899
  return displayText;
3067
3900
  };
3068
3901
  return /* @__PURE__ */ jsxs16(
3069
- Pressable11,
3902
+ Pressable12,
3070
3903
  {
3071
3904
  nativeID,
3072
3905
  disabled,
@@ -3106,7 +3939,7 @@ function SelectTrigger({
3106
3939
  triggerStyle
3107
3940
  ],
3108
3941
  children: [
3109
- startIcon && /* @__PURE__ */ jsx28(
3942
+ startIcon && /* @__PURE__ */ jsx30(
3110
3943
  View22,
3111
3944
  {
3112
3945
  pointerEvents: "none",
@@ -3116,25 +3949,25 @@ function SelectTrigger({
3116
3949
  children: renderIcon(startIcon)
3117
3950
  }
3118
3951
  ),
3119
- prefix && /* @__PURE__ */ jsx28(Text13, { style: styles.affix, children: prefix }),
3120
- /* @__PURE__ */ jsx28(View22, { style: styles.value, children: renderValue() }),
3121
- suffix && /* @__PURE__ */ jsx28(Text13, { style: styles.affix, children: suffix }),
3122
- loading ? /* @__PURE__ */ jsx28(
3952
+ prefix && /* @__PURE__ */ jsx30(Text14, { style: styles.affix, children: prefix }),
3953
+ /* @__PURE__ */ jsx30(View22, { style: styles.value, children: renderValue() }),
3954
+ suffix && /* @__PURE__ */ jsx30(Text14, { style: styles.affix, children: suffix }),
3955
+ loading ? /* @__PURE__ */ jsx30(
3123
3956
  ActivityIndicator2,
3124
3957
  {
3125
3958
  testID: "select-loading-indicator",
3126
3959
  size: "small",
3127
3960
  color: iconColor
3128
3961
  }
3129
- ) : clearable && hasValue && !disabled ? /* @__PURE__ */ jsx28(
3130
- Pressable11,
3962
+ ) : clearable && hasValue && !disabled ? /* @__PURE__ */ jsx30(
3963
+ Pressable12,
3131
3964
  {
3132
3965
  accessibilityRole: "button",
3133
3966
  accessibilityLabel: "Clear selection",
3134
3967
  hitSlop: 8,
3135
3968
  onPress: onClear,
3136
3969
  style: styles.clearButton,
3137
- children: /* @__PURE__ */ jsx28(
3970
+ children: /* @__PURE__ */ jsx30(
3138
3971
  Close3,
3139
3972
  {
3140
3973
  width: 14,
@@ -3143,7 +3976,7 @@ function SelectTrigger({
3143
3976
  }
3144
3977
  )
3145
3978
  }
3146
- ) : endIcon ? /* @__PURE__ */ jsx28(
3979
+ ) : endIcon ? /* @__PURE__ */ jsx30(
3147
3980
  View22,
3148
3981
  {
3149
3982
  pointerEvents: "none",
@@ -3152,13 +3985,13 @@ function SelectTrigger({
3152
3985
  importantForAccessibility: "no",
3153
3986
  children: renderIcon(endIcon)
3154
3987
  }
3155
- ) : /* @__PURE__ */ jsx28(
3988
+ ) : /* @__PURE__ */ jsx30(
3156
3989
  View22,
3157
3990
  {
3158
3991
  style: [styles.endIcon, isOpen && styles.iconOpen],
3159
3992
  accessibilityElementsHidden: true,
3160
3993
  importantForAccessibility: "no",
3161
- children: /* @__PURE__ */ jsx28(ChevronDown2, { width: 16, height: 16, color: iconColor })
3994
+ children: /* @__PURE__ */ jsx30(ChevronDown2, { width: 16, height: 16, color: iconColor })
3162
3995
  }
3163
3996
  )
3164
3997
  ]
@@ -3174,7 +4007,7 @@ var SelectValue = createSelectSlot(
3174
4007
  );
3175
4008
 
3176
4009
  // src/components/Select/Root/SelectRoot.tsx
3177
- import { jsx as jsx29, jsxs as jsxs17 } from "react/jsx-runtime";
4010
+ import { jsx as jsx31, jsxs as jsxs17 } from "react/jsx-runtime";
3178
4011
  function SelectRoot(props) {
3179
4012
  const {
3180
4013
  label,
@@ -3225,10 +4058,11 @@ function SelectRoot(props) {
3225
4058
  testID
3226
4059
  } = props;
3227
4060
  const field = useFormFieldContext();
4061
+ const overlayId = useId4();
3228
4062
  const hasOwnField = Boolean(label || description || error);
3229
- const [triggerWidth, setTriggerWidth] = useState5();
3230
- const searchInputRef = useRef5(null);
3231
- const selectedFocusValueRef = useRef5(void 0);
4063
+ const [triggerWidth, setTriggerWidth] = useState10();
4064
+ const searchInputRef = useRef7(null);
4065
+ const selectedFocusValueRef = useRef7(void 0);
3232
4066
  const resolvedPresentation = useSelectPresentation(presentation);
3233
4067
  const {
3234
4068
  options,
@@ -3281,7 +4115,7 @@ function SelectRoot(props) {
3281
4115
  const selectedOptions = options.filter(
3282
4116
  (option) => selectedValues.includes(option.value)
3283
4117
  );
3284
- const optionsByValue = useMemo7(
4118
+ const optionsByValue = useMemo8(
3285
4119
  () => new Map(
3286
4120
  options.filter((option) => !option.disabled).map((option) => [option.value, option])
3287
4121
  ),
@@ -3306,7 +4140,7 @@ function SelectRoot(props) {
3306
4140
  )
3307
4141
  );
3308
4142
  const itemHeight = typeof virtual === "object" ? virtual.estimatedItemSize ?? 46 : 46;
3309
- const displayValue = useMemo7(() => {
4143
+ const displayValue = useMemo8(() => {
3310
4144
  if (renderValue) {
3311
4145
  return renderValue(
3312
4146
  props.multiple ? selectedOptions : selectedOption ?? null,
@@ -3338,6 +4172,12 @@ function SelectRoot(props) {
3338
4172
  fieldDescribedBy: field?.ariaDescribedBy
3339
4173
  });
3340
4174
  const hasValue = selectedValues.length > 0;
4175
+ const dismiss = useNativeDismiss({
4176
+ id: overlayId,
4177
+ visible: isOpen,
4178
+ closeOnOutsidePress: dismissOnBackdropPress,
4179
+ onClose: closeDropdown
4180
+ });
3341
4181
  const clearValue = () => {
3342
4182
  selectedFocusValueRef.current = void 0;
3343
4183
  selectValue("");
@@ -3424,7 +4264,7 @@ function SelectRoot(props) {
3424
4264
  searchInputRef,
3425
4265
  empty: empty ?? emptyFromChildren ?? "Nothing found",
3426
4266
  loadingContent: loadingFromChildren ?? loadingText,
3427
- closeContent: closeDropdown,
4267
+ closeContent: dismiss.requestClose,
3428
4268
  openContent: openDropdown,
3429
4269
  clearValue,
3430
4270
  selectOption,
@@ -3445,13 +4285,13 @@ function SelectRoot(props) {
3445
4285
  fieldLabelId: !hasOwnField ? field?.labelId : void 0,
3446
4286
  fieldDescribedBy: !hasOwnField ? field?.ariaDescribedBy : void 0
3447
4287
  };
3448
- const control = /* @__PURE__ */ jsx29(SelectContext.Provider, { value: contextValue, children: /* @__PURE__ */ jsxs17(
4288
+ const control = /* @__PURE__ */ jsx31(SelectContext.Provider, { value: contextValue, children: /* @__PURE__ */ jsxs17(
3449
4289
  View23,
3450
4290
  {
3451
4291
  testID,
3452
4292
  onLayout: (event) => setTriggerWidth(event.nativeEvent.layout.width),
3453
4293
  children: [
3454
- /* @__PURE__ */ jsx29(
4294
+ /* @__PURE__ */ jsx31(
3455
4295
  SelectTrigger,
3456
4296
  {
3457
4297
  displayText: displayValue,
@@ -3481,14 +4321,14 @@ function SelectRoot(props) {
3481
4321
  onClear: clearValue
3482
4322
  }
3483
4323
  ),
3484
- /* @__PURE__ */ jsx29(SelectContentSurface, {})
4324
+ /* @__PURE__ */ jsx31(SelectContentSurface, {})
3485
4325
  ]
3486
4326
  }
3487
4327
  ) });
3488
4328
  if (!hasOwnField && field) {
3489
4329
  return control;
3490
4330
  }
3491
- return /* @__PURE__ */ jsx29(
4331
+ return /* @__PURE__ */ jsx31(
3492
4332
  FormField,
3493
4333
  {
3494
4334
  label,
@@ -3530,7 +4370,7 @@ import { View as View24 } from "react-native";
3530
4370
  import { createContext as createContext6, useContext as useContext6 } from "react";
3531
4371
  var TabsContext = createContext6(null);
3532
4372
  var TabsProvider = TabsContext.Provider;
3533
- var useTabs = () => {
4373
+ var useTabs2 = () => {
3534
4374
  const context = useContext6(TabsContext);
3535
4375
  if (!context) {
3536
4376
  throw new Error("Tabs components must be used inside <Tabs>.");
@@ -3567,11 +4407,11 @@ var createStyles14 = (theme) => StyleSheet21.create({
3567
4407
  });
3568
4408
 
3569
4409
  // src/components/Tabs/List/TabsList.tsx
3570
- import { jsx as jsx30 } from "react/jsx-runtime";
4410
+ import { jsx as jsx32 } from "react/jsx-runtime";
3571
4411
  var TabsList = ({ children, style }) => {
3572
4412
  const styles = useThemeStyles(createStyles14);
3573
- const { orientation, appearance } = useTabs();
3574
- return /* @__PURE__ */ jsx30(
4413
+ const { orientation, appearance } = useTabs2();
4414
+ return /* @__PURE__ */ jsx32(
3575
4415
  View24,
3576
4416
  {
3577
4417
  accessibilityRole: "tablist",
@@ -3619,12 +4459,12 @@ var createStyles15 = (theme) => StyleSheet22.create({
3619
4459
  });
3620
4460
 
3621
4461
  // src/components/Tabs/Panel/TabsPanel.tsx
3622
- import { jsx as jsx31 } from "react/jsx-runtime";
4462
+ import { jsx as jsx33 } from "react/jsx-runtime";
3623
4463
  var TabsPanel = ({ index, children, style }) => {
3624
4464
  const styles = useThemeStyles(createStyles15);
3625
- const { activeIndex, orientation } = useTabs();
4465
+ const { activeIndex, orientation } = useTabs2();
3626
4466
  if (activeIndex !== index) return null;
3627
- return /* @__PURE__ */ jsx31(
4467
+ return /* @__PURE__ */ jsx33(
3628
4468
  View25,
3629
4469
  {
3630
4470
  style: [
@@ -3639,8 +4479,8 @@ var TabsPanel = ({ index, children, style }) => {
3639
4479
  TabsPanel.displayName = "TabsPanel";
3640
4480
 
3641
4481
  // src/components/Tabs/Tab/Tab.tsx
3642
- import { cloneElement as cloneElement6, isValidElement as isValidElement8 } from "react";
3643
- import { Pressable as Pressable12, Text as Text14, View as View26 } from "react-native";
4482
+ import { cloneElement as cloneElement8, isValidElement as isValidElement10 } from "react";
4483
+ import { Pressable as Pressable13, Text as Text15, View as View26 } from "react-native";
3644
4484
 
3645
4485
  // src/components/Tabs/Tab/Tab.styles.ts
3646
4486
  import { StyleSheet as StyleSheet23 } from "react-native";
@@ -3763,7 +4603,7 @@ var createStyles16 = (theme) => StyleSheet23.create({
3763
4603
  });
3764
4604
 
3765
4605
  // src/components/Tabs/Tab/Tab.tsx
3766
- import { Fragment as Fragment4, jsx as jsx32, jsxs as jsxs18 } from "react/jsx-runtime";
4606
+ import { Fragment as Fragment4, jsx as jsx34, jsxs as jsxs18 } from "react/jsx-runtime";
3767
4607
  var Tab = ({
3768
4608
  index,
3769
4609
  children,
@@ -3774,18 +4614,18 @@ var Tab = ({
3774
4614
  }) => {
3775
4615
  const { theme } = useTheme();
3776
4616
  const styles = useThemeStyles(createStyles16);
3777
- const { activeIndex, appearance, orientation, setActiveIndex } = useTabs();
4617
+ const { activeIndex, appearance, orientation, setActiveIndex } = useTabs2();
3778
4618
  const isActive = activeIndex === index;
3779
4619
  const isPills = appearance === "pills";
3780
4620
  const isUnderline = appearance === "underline";
3781
4621
  const isDefault = appearance === "default";
3782
4622
  const isVertical = orientation === "vertical";
3783
4623
  const iconColor = isPills && isActive ? theme.components.tabs.pills.active.fg : isActive ? theme.components.tabs.trigger.active.fg : theme.components.tabs.trigger.default.fg;
3784
- const renderedIcon = isValidElement8(icon) ? cloneElement6(icon, {
4624
+ const renderedIcon = isValidElement10(icon) ? cloneElement8(icon, {
3785
4625
  color: iconColor
3786
4626
  }) : icon;
3787
- return /* @__PURE__ */ jsx32(
3788
- Pressable12,
4627
+ return /* @__PURE__ */ jsx34(
4628
+ Pressable13,
3789
4629
  {
3790
4630
  disabled,
3791
4631
  accessibilityRole: "tab",
@@ -3806,7 +4646,7 @@ var Tab = ({
3806
4646
  style
3807
4647
  ],
3808
4648
  children: ({ pressed }) => /* @__PURE__ */ jsxs18(Fragment4, { children: [
3809
- isUnderline && !isVertical && /* @__PURE__ */ jsx32(
4649
+ isUnderline && !isVertical && /* @__PURE__ */ jsx34(
3810
4650
  View26,
3811
4651
  {
3812
4652
  pointerEvents: "none",
@@ -3816,7 +4656,7 @@ var Tab = ({
3816
4656
  ]
3817
4657
  }
3818
4658
  ),
3819
- isUnderline && isVertical && /* @__PURE__ */ jsx32(
4659
+ isUnderline && isVertical && /* @__PURE__ */ jsx34(
3820
4660
  View26,
3821
4661
  {
3822
4662
  pointerEvents: "none",
@@ -3827,9 +4667,9 @@ var Tab = ({
3827
4667
  ]
3828
4668
  }
3829
4669
  ),
3830
- icon != null && /* @__PURE__ */ jsx32(View26, { style: styles.tabIcon, children: renderedIcon }),
3831
- children != null && /* @__PURE__ */ jsx32(
3832
- Text14,
4670
+ icon != null && /* @__PURE__ */ jsx34(View26, { style: styles.tabIcon, children: renderedIcon }),
4671
+ children != null && /* @__PURE__ */ jsx34(
4672
+ Text15,
3833
4673
  {
3834
4674
  numberOfLines: 2,
3835
4675
  ellipsizeMode: "tail",
@@ -3850,8 +4690,7 @@ var Tab = ({
3850
4690
  Tab.displayName = "Tab";
3851
4691
 
3852
4692
  // src/components/Tabs/Tabs.tsx
3853
- import { useMemo as useMemo8 } from "react";
3854
- import { useTabs as useTabs2 } from "@vellira-ui/core";
4693
+ import { useMemo as useMemo9 } from "react";
3855
4694
  import { View as View27 } from "react-native";
3856
4695
 
3857
4696
  // src/components/Tabs/Tabs.styles.ts
@@ -3871,7 +4710,7 @@ var createStyles17 = (theme) => StyleSheet24.create({
3871
4710
  });
3872
4711
 
3873
4712
  // src/components/Tabs/Tabs.tsx
3874
- import { jsx as jsx33 } from "react/jsx-runtime";
4713
+ import { jsx as jsx35 } from "react/jsx-runtime";
3875
4714
  var TabsRoot = ({
3876
4715
  children,
3877
4716
  activeIndex: controlledActiveIndex,
@@ -3882,17 +4721,17 @@ var TabsRoot = ({
3882
4721
  style
3883
4722
  }) => {
3884
4723
  const styles = useThemeStyles(createStyles17);
3885
- const { activeIndex, setActiveIndex } = useTabs2({
4724
+ const { activeIndex, setActiveIndex } = useTabs({
3886
4725
  activeIndex: controlledActiveIndex,
3887
4726
  defaultActiveIndex,
3888
4727
  onChange,
3889
4728
  orientation
3890
4729
  });
3891
- const value = useMemo8(
4730
+ const value = useMemo9(
3892
4731
  () => ({ activeIndex, appearance, orientation, setActiveIndex }),
3893
4732
  [activeIndex, appearance, orientation, setActiveIndex]
3894
4733
  );
3895
- return /* @__PURE__ */ jsx33(TabsProvider, { value, children: /* @__PURE__ */ jsx33(
4734
+ return /* @__PURE__ */ jsx35(TabsProvider, { value, children: /* @__PURE__ */ jsx35(
3896
4735
  View27,
3897
4736
  {
3898
4737
  style: [
@@ -3914,74 +4753,8 @@ var Tabs = Object.assign(TabsRoot, {
3914
4753
  });
3915
4754
 
3916
4755
  // src/components/Tooltip/Tooltip.tsx
3917
- import { useEffect as useEffect7, useRef as useRef7, useState as useState7 } from "react";
3918
- import { Modal as Modal6, Pressable as Pressable13, Text as Text15, View as View28 } from "react-native";
3919
-
3920
- // src/hooks/useNativeFloatingPosition.ts
3921
- import { useCallback as useCallback2, useRef as useRef6, useState as useState6 } from "react";
3922
- import { Dimensions } from "react-native";
3923
- var safePadding = 12;
3924
- function useNativeFloatingPosition(placement = "top", offset = 8) {
3925
- const [position, setPosition] = useState6({ top: 0, left: 0 });
3926
- const floatingSizeRef = useRef6({
3927
- width: 0,
3928
- height: 0
3929
- });
3930
- const lastTriggerRef = useRef6(null);
3931
- const clamp = useCallback2((value, min, max) => {
3932
- return Math.min(Math.max(value, min), Math.max(min, max));
3933
- }, []);
3934
- const calculatePosition = useCallback2(
3935
- (triggerRect, size) => {
3936
- const { width: screenWidth, height: screenHeight } = Dimensions.get("window");
3937
- const [side, align = "center"] = placement.split("-");
3938
- const horizontalTop = side === "bottom" ? triggerRect.y + triggerRect.height + offset : triggerRect.y - size.height - offset;
3939
- const verticalTop = align === "start" ? triggerRect.y : align === "end" ? triggerRect.y + triggerRect.height - size.height : triggerRect.y + triggerRect.height / 2 - size.height / 2;
3940
- const horizontalLeft = align === "start" ? triggerRect.x : align === "end" ? triggerRect.x + triggerRect.width - size.width : triggerRect.x + triggerRect.width / 2 - size.width / 2;
3941
- const verticalLeft = side === "right" ? triggerRect.x + triggerRect.width + offset : triggerRect.x - size.width - offset;
3942
- const rawPosition = side === "left" || side === "right" ? { top: verticalTop, left: verticalLeft } : { top: horizontalTop, left: horizontalLeft };
3943
- return {
3944
- top: clamp(
3945
- rawPosition.top,
3946
- safePadding,
3947
- screenHeight - size.height - safePadding
3948
- ),
3949
- left: clamp(
3950
- rawPosition.left,
3951
- safePadding,
3952
- screenWidth - size.width - safePadding
3953
- )
3954
- };
3955
- },
3956
- [placement, offset, clamp]
3957
- );
3958
- const updatePosition = useCallback2(
3959
- (triggerRef, measuredSize = floatingSizeRef.current) => {
3960
- lastTriggerRef.current = triggerRef;
3961
- const node = triggerRef.current;
3962
- if (!node || typeof node.measureInWindow !== "function") {
3963
- setPosition({ top: 0, left: 0 });
3964
- return;
3965
- }
3966
- node.measureInWindow((x, y, width, height) => {
3967
- setPosition(calculatePosition({ x, y, width, height }, measuredSize));
3968
- });
3969
- },
3970
- [calculatePosition]
3971
- );
3972
- const onFloatingLayout = useCallback2(
3973
- (event) => {
3974
- const { width, height } = event.nativeEvent.layout;
3975
- const nextSize = { width, height };
3976
- floatingSizeRef.current = nextSize;
3977
- if (lastTriggerRef.current) {
3978
- updatePosition(lastTriggerRef.current, nextSize);
3979
- }
3980
- },
3981
- [updatePosition]
3982
- );
3983
- return { position, updatePosition, onFloatingLayout };
3984
- }
4756
+ import { useEffect as useEffect11, useId as useId5, useRef as useRef8, useState as useState11 } from "react";
4757
+ import { Modal as Modal6, Pressable as Pressable14, Text as Text16, View as View28 } from "react-native";
3985
4758
 
3986
4759
  // src/components/Tooltip/Tooltip.styles.ts
3987
4760
  import { StyleSheet as StyleSheet25 } from "react-native";
@@ -4022,7 +4795,7 @@ var createStyles18 = (theme) => StyleSheet25.create({
4022
4795
  });
4023
4796
 
4024
4797
  // src/components/Tooltip/Tooltip.tsx
4025
- import { jsx as jsx34, jsxs as jsxs19 } from "react/jsx-runtime";
4798
+ import { jsx as jsx36, jsxs as jsxs19 } from "react/jsx-runtime";
4026
4799
  function Tooltip({
4027
4800
  children,
4028
4801
  content,
@@ -4035,9 +4808,10 @@ function Tooltip({
4035
4808
  textStyle
4036
4809
  }) {
4037
4810
  const styles = useThemeStyles(createStyles18);
4038
- const [visible, setVisible] = useState7(false);
4039
- const triggerRef = useRef7(null);
4040
- const closeTimerRef = useRef7(null);
4811
+ const overlayId = useId5();
4812
+ const [visible, setVisible] = useState11(false);
4813
+ const triggerRef = useRef8(null);
4814
+ const closeTimerRef = useRef8(null);
4041
4815
  const { position, updatePosition, onFloatingLayout } = useNativeFloatingPosition(placement, 8);
4042
4816
  const hideDelay = delay?.close ?? 2500;
4043
4817
  const clearCloseTimer = () => {
@@ -4046,6 +4820,14 @@ function Tooltip({
4046
4820
  closeTimerRef.current = null;
4047
4821
  }
4048
4822
  };
4823
+ const dismiss = useNativeDismiss({
4824
+ id: overlayId,
4825
+ visible: visible && !disabled,
4826
+ onClose: () => {
4827
+ clearCloseTimer();
4828
+ setVisible(false);
4829
+ }
4830
+ });
4049
4831
  const showTooltip = () => {
4050
4832
  if (disabled) return;
4051
4833
  clearCloseTimer();
@@ -4056,20 +4838,19 @@ function Tooltip({
4056
4838
  closeTimerRef.current = null;
4057
4839
  }, hideDelay);
4058
4840
  };
4059
- useEffect7(() => {
4841
+ useEffect11(() => {
4060
4842
  return clearCloseTimer;
4061
4843
  }, []);
4062
4844
  return /* @__PURE__ */ jsxs19(View28, { style: [styles.root, style], children: [
4063
- /* @__PURE__ */ jsx34(Pressable13, { ref: triggerRef, onLongPress: showTooltip, children }),
4064
- /* @__PURE__ */ jsx34(Modal6, { visible: visible && !disabled, transparent: true, animationType: "fade", children: /* @__PURE__ */ jsx34(
4065
- Pressable13,
4845
+ /* @__PURE__ */ jsx36(Pressable14, { ref: triggerRef, onLongPress: showTooltip, children }),
4846
+ /* @__PURE__ */ jsx36(
4847
+ Modal6,
4066
4848
  {
4067
- style: styles.overlay,
4068
- onPress: () => {
4069
- clearCloseTimer();
4070
- setVisible(false);
4071
- },
4072
- children: /* @__PURE__ */ jsx34(
4849
+ visible: visible && !disabled,
4850
+ transparent: true,
4851
+ animationType: "fade",
4852
+ onRequestClose: dismiss.requestClose,
4853
+ children: /* @__PURE__ */ jsx36(Pressable14, { style: styles.overlay, onPress: dismiss.requestOutsideClose, children: /* @__PURE__ */ jsx36(
4073
4854
  View28,
4074
4855
  {
4075
4856
  pointerEvents: "none",
@@ -4083,18 +4864,18 @@ function Tooltip({
4083
4864
  contentStyle
4084
4865
  ],
4085
4866
  onLayout: onFloatingLayout,
4086
- children: typeof content === "string" ? /* @__PURE__ */ jsx34(Text15, { style: [styles.text, textStyle], children: content }) : content
4867
+ children: typeof content === "string" ? /* @__PURE__ */ jsx36(Text16, { style: [styles.text, textStyle], children: content }) : content
4087
4868
  }
4088
- )
4869
+ ) })
4089
4870
  }
4090
- ) })
4871
+ )
4091
4872
  ] });
4092
4873
  }
4093
4874
  Tooltip.displayName = "Tooltip";
4094
4875
 
4095
4876
  // src/primitives/Button/Button.tsx
4096
- import { cloneElement as cloneElement7, useState as useState8 } from "react";
4097
- import { ActivityIndicator as ActivityIndicator3, Pressable as Pressable14, Text as Text16, View as View29 } from "react-native";
4877
+ import { cloneElement as cloneElement9, useState as useState12 } from "react";
4878
+ import { ActivityIndicator as ActivityIndicator3, Pressable as Pressable15, Text as Text17, View as View29 } from "react-native";
4098
4879
 
4099
4880
  // src/utils/devWarning.ts
4100
4881
  var devWarning = (condition, message) => {
@@ -4171,7 +4952,7 @@ var createStyles19 = (theme) => StyleSheet26.create({
4171
4952
  });
4172
4953
 
4173
4954
  // src/primitives/Button/Button.tsx
4174
- import { Fragment as Fragment5, jsx as jsx35, jsxs as jsxs20 } from "react/jsx-runtime";
4955
+ import { Fragment as Fragment5, jsx as jsx37, jsxs as jsxs20 } from "react/jsx-runtime";
4175
4956
  var sizeMap = {
4176
4957
  sm: {
4177
4958
  px: 12,
@@ -4227,9 +5008,9 @@ function Button({
4227
5008
  const config = sizeMap[size];
4228
5009
  const radius = shape === "square" ? theme.tokens.radius.sm : shape === "rounded" ? theme.tokens.radius.md : theme.tokens.radius.full;
4229
5010
  const appearanceTheme = theme.components.button[color][appearance];
4230
- const [isHovered, setIsHovered] = useState8(false);
4231
- const [isFocused, setIsFocused] = useState8(false);
4232
- const [labelWidth, setLabelWidth] = useState8(0);
5011
+ const [isHovered, setIsHovered] = useState12(false);
5012
+ const [isFocused, setIsFocused] = useState12(false);
5013
+ const [labelWidth, setLabelWidth] = useState12(0);
4233
5014
  const isDisabled = disabled || loading;
4234
5015
  const iconOnly = iconOnlyProp || !children && Boolean(iconStart || iconEnd);
4235
5016
  const content = loading && loadingText ? loadingText : children;
@@ -4255,7 +5036,7 @@ function Button({
4255
5036
  setIsHovered(false);
4256
5037
  onHoverOut?.(event);
4257
5038
  };
4258
- const renderIcon = (icon, iconColor) => cloneElement7(icon, {
5039
+ const renderIcon = (icon, iconColor) => cloneElement9(icon, {
4259
5040
  color: iconColor,
4260
5041
  size: resolvedIconSize
4261
5042
  });
@@ -4266,8 +5047,8 @@ function Button({
4266
5047
  );
4267
5048
  };
4268
5049
  const getInteractionTheme = (pressed) => isDisabled ? theme.components.button.disabled : pressed ? appearanceTheme.pressed : isHovered ? appearanceTheme.hover : appearanceTheme.default;
4269
- return /* @__PURE__ */ jsx35(
4270
- Pressable14,
5050
+ return /* @__PURE__ */ jsx37(
5051
+ Pressable15,
4271
5052
  {
4272
5053
  ...props,
4273
5054
  testID,
@@ -4304,11 +5085,11 @@ function Button({
4304
5085
  const interactionTheme = getInteractionTheme(pressed);
4305
5086
  const contentColor = interactionTheme.fg;
4306
5087
  return /* @__PURE__ */ jsxs20(Fragment5, { children: [
4307
- loading && /* @__PURE__ */ jsx35(ActivityIndicator3, { size: "small", color: contentColor }),
5088
+ loading && /* @__PURE__ */ jsx37(ActivityIndicator3, { size: "small", color: contentColor }),
4308
5089
  !loading && iconStart && renderIcon(iconStart, contentColor),
4309
5090
  content && !iconOnly && /* @__PURE__ */ jsxs20(View29, { style: styles.labelSlot, children: [
4310
- /* @__PURE__ */ jsx35(
4311
- Text16,
5091
+ /* @__PURE__ */ jsx37(
5092
+ Text17,
4312
5093
  {
4313
5094
  onLayout: handleLabelLayout,
4314
5095
  style: [
@@ -4323,8 +5104,8 @@ function Button({
4323
5104
  children: content
4324
5105
  }
4325
5106
  ),
4326
- measureLabel && /* @__PURE__ */ jsx35(
4327
- Text16,
5107
+ measureLabel && /* @__PURE__ */ jsx37(
5108
+ Text17,
4328
5109
  {
4329
5110
  accessibilityElementsHidden: true,
4330
5111
  importantForAccessibility: "no-hide-descendants",
@@ -4341,8 +5122,8 @@ function Button({
4341
5122
  }
4342
5123
  )
4343
5124
  ] }),
4344
- badge && !iconOnly && /* @__PURE__ */ jsx35(
4345
- Text16,
5125
+ badge && !iconOnly && /* @__PURE__ */ jsx37(
5126
+ Text17,
4346
5127
  {
4347
5128
  style: [
4348
5129
  styles.badge,
@@ -4354,8 +5135,8 @@ function Button({
4354
5135
  children: badge
4355
5136
  }
4356
5137
  ),
4357
- shortcut && !iconOnly && /* @__PURE__ */ jsx35(
4358
- Text16,
5138
+ shortcut && !iconOnly && /* @__PURE__ */ jsx37(
5139
+ Text17,
4359
5140
  {
4360
5141
  style: [
4361
5142
  styles.shortcut,
@@ -4374,10 +5155,9 @@ function Button({
4374
5155
  }
4375
5156
 
4376
5157
  // src/primitives/Checkbox/Checkbox.tsx
4377
- import { forwardRef as forwardRef2, useEffect as useEffect8 } from "react";
4378
- import { useControllableState as useControllableState3 } from "@vellira-ui/core";
5158
+ import { forwardRef as forwardRef2, useEffect as useEffect12 } from "react";
4379
5159
  import { Check as Check2 } from "@vellira-ui/icons";
4380
- import { Pressable as Pressable15, Text as Text17, View as View30 } from "react-native";
5160
+ import { Pressable as Pressable16, Text as Text18, View as View30 } from "react-native";
4381
5161
 
4382
5162
  // src/primitives/Checkbox/Checkbox.styles.ts
4383
5163
  import { StyleSheet as StyleSheet27 } from "react-native";
@@ -4524,7 +5304,7 @@ var createStyles20 = (theme) => StyleSheet27.create({
4524
5304
  });
4525
5305
 
4526
5306
  // src/primitives/Checkbox/Checkbox.tsx
4527
- import { Fragment as Fragment6, jsx as jsx36, jsxs as jsxs21 } from "react/jsx-runtime";
5307
+ import { Fragment as Fragment6, jsx as jsx38, jsxs as jsxs21 } from "react/jsx-runtime";
4528
5308
  var iconSizeBySize = {
4529
5309
  sm: 10,
4530
5310
  md: 12,
@@ -4570,7 +5350,7 @@ var Checkbox = forwardRef2(
4570
5350
  lg: styles.errorTextLg
4571
5351
  };
4572
5352
  const hasError = Boolean(error);
4573
- const [isChecked, setIsChecked] = useControllableState3({
5353
+ const [isChecked, setIsChecked] = useControllableState({
4574
5354
  value: checked,
4575
5355
  defaultValue: defaultChecked,
4576
5356
  onChange: onCheckedChange
@@ -4582,15 +5362,15 @@ var Checkbox = forwardRef2(
4582
5362
  const resolvedAccessibilityLabel = accessibilityLabel ?? label;
4583
5363
  const resolvedAccessibilityHint = [accessibilityHint, description, error].filter(Boolean).join(" ");
4584
5364
  const accessibilityChecked = indeterminate ? "mixed" : isChecked;
4585
- useEffect8(() => {
5365
+ useEffect12(() => {
4586
5366
  devWarning(
4587
5367
  Boolean(resolvedAccessibilityLabel),
4588
5368
  "Checkbox: an accessible label must be provided through label or accessibilityLabel."
4589
5369
  );
4590
5370
  }, [resolvedAccessibilityLabel]);
4591
5371
  return /* @__PURE__ */ jsxs21(View30, { style: styles.container, children: [
4592
- /* @__PURE__ */ jsx36(
4593
- Pressable15,
5372
+ /* @__PURE__ */ jsx38(
5373
+ Pressable16,
4594
5374
  {
4595
5375
  ...PressableProps,
4596
5376
  ref,
@@ -4614,7 +5394,7 @@ var Checkbox = forwardRef2(
4614
5394
  const isSelected = isChecked || indeterminate;
4615
5395
  const checkColor = disabled ? theme.components.checkbox.disabled.fg : pressed && isSelected ? checkboxColor.pressed.fg : checkboxColor.default.fg;
4616
5396
  return /* @__PURE__ */ jsxs21(Fragment6, { children: [
4617
- /* @__PURE__ */ jsx36(
5397
+ /* @__PURE__ */ jsx38(
4618
5398
  View30,
4619
5399
  {
4620
5400
  style: [
@@ -4632,7 +5412,7 @@ var Checkbox = forwardRef2(
4632
5412
  hasError && styles.boxError,
4633
5413
  disabled && styles.boxDisabled
4634
5414
  ],
4635
- children: indeterminate ? indeterminateIcon ?? /* @__PURE__ */ jsx36(
5415
+ children: indeterminate ? indeterminateIcon ?? /* @__PURE__ */ jsx38(
4636
5416
  View30,
4637
5417
  {
4638
5418
  style: [
@@ -4642,11 +5422,11 @@ var Checkbox = forwardRef2(
4642
5422
  }
4643
5423
  ]
4644
5424
  }
4645
- ) : isChecked && (icon ?? /* @__PURE__ */ jsx36(Check2, { size: iconSizeBySize[size], color: checkColor }))
5425
+ ) : isChecked && (icon ?? /* @__PURE__ */ jsx38(Check2, { size: iconSizeBySize[size], color: checkColor }))
4646
5426
  }
4647
5427
  ),
4648
5428
  label && /* @__PURE__ */ jsxs21(
4649
- Text17,
5429
+ Text18,
4650
5430
  {
4651
5431
  style: [
4652
5432
  styles.label,
@@ -4659,7 +5439,7 @@ var Checkbox = forwardRef2(
4659
5439
  ],
4660
5440
  children: [
4661
5441
  label,
4662
- required && /* @__PURE__ */ jsx36(Text17, { style: styles.requiredMark, children: " *" })
5442
+ required && /* @__PURE__ */ jsx38(Text18, { style: styles.requiredMark, children: " *" })
4663
5443
  ]
4664
5444
  }
4665
5445
  )
@@ -4667,8 +5447,8 @@ var Checkbox = forwardRef2(
4667
5447
  }
4668
5448
  }
4669
5449
  ),
4670
- description && /* @__PURE__ */ jsx36(
4671
- Text17,
5450
+ description && /* @__PURE__ */ jsx38(
5451
+ Text18,
4672
5452
  {
4673
5453
  style: [
4674
5454
  styles.descriptionText,
@@ -4678,15 +5458,15 @@ var Checkbox = forwardRef2(
4678
5458
  children: description
4679
5459
  }
4680
5460
  ),
4681
- hasError && /* @__PURE__ */ jsx36(Text17, { style: [styles.errorText, helperTextSizeStyle[size]], children: error })
5461
+ hasError && /* @__PURE__ */ jsx38(Text18, { style: [styles.errorText, helperTextSizeStyle[size]], children: error })
4682
5462
  ] });
4683
5463
  }
4684
5464
  );
4685
5465
  Checkbox.displayName = "Checkbox";
4686
5466
 
4687
5467
  // src/primitives/Input/Input.tsx
4688
- import { cloneElement as cloneElement8, forwardRef as forwardRef3, useState as useState9 } from "react";
4689
- import { Pressable as Pressable16, Text as Text18, TextInput as TextInput2, View as View31 } from "react-native";
5468
+ import { cloneElement as cloneElement10, forwardRef as forwardRef3, useState as useState13 } from "react";
5469
+ import { Pressable as Pressable17, Text as Text19, TextInput as TextInput3, View as View31 } from "react-native";
4690
5470
 
4691
5471
  // src/primitives/Input/Input.styles.ts
4692
5472
  import { StyleSheet as StyleSheet28 } from "react-native";
@@ -4836,7 +5616,7 @@ var createStyles21 = (theme) => StyleSheet28.create({
4836
5616
  });
4837
5617
 
4838
5618
  // src/primitives/Input/Input.tsx
4839
- import { jsx as jsx37, jsxs as jsxs22 } from "react/jsx-runtime";
5619
+ import { jsx as jsx39, jsxs as jsxs22 } from "react/jsx-runtime";
4840
5620
  var keyboardTypeByInputType = {
4841
5621
  text: "default",
4842
5622
  email: "email-address",
@@ -4937,8 +5717,8 @@ var Input = forwardRef3(
4937
5717
  const styles = useThemeStyles(createStyles21);
4938
5718
  const field = useFormFieldContext();
4939
5719
  const hasOwnField = Boolean(label || description || error);
4940
- const [isFocused, setIsFocused] = useState9(false);
4941
- const [uncontrolledValue, setUncontrolledValue] = useState9(
5720
+ const [isFocused, setIsFocused] = useState13(false);
5721
+ const [uncontrolledValue, setUncontrolledValue] = useState13(
4942
5722
  defaultValue ?? ""
4943
5723
  );
4944
5724
  const isControlled = value !== void 0;
@@ -4955,7 +5735,7 @@ var Input = forwardRef3(
4955
5735
  const isReadOnly = readOnly || loading;
4956
5736
  const placeholderTextColor = isDisabled ? getDisabledPlaceholderTextColor(theme) : readOnly ? theme.components.input.readOnly.placeholder : inputState.placeholder;
4957
5737
  const isPassword = type === "password";
4958
- const [isPasswordRevealed, setIsPasswordRevealed] = useState9(false);
5738
+ const [isPasswordRevealed, setIsPasswordRevealed] = useState13(false);
4959
5739
  const resolvedIconSize = iconSize ?? 16;
4960
5740
  const handleFocus = (event) => {
4961
5741
  setIsFocused(true);
@@ -4987,21 +5767,21 @@ var Input = forwardRef3(
4987
5767
  const endIconColor = isDisabled ? theme.components.input.disabled.icon : theme.components.input.icon[endIconTone];
4988
5768
  const clearIconColor = isDisabled ? theme.components.input.disabled.icon : theme.components.input.icon[clearIconTone];
4989
5769
  const control = /* @__PURE__ */ jsxs22(View31, { style: styles.inputWrapper, children: [
4990
- startIcon && /* @__PURE__ */ jsx37(
5770
+ startIcon && /* @__PURE__ */ jsx39(
4991
5771
  View31,
4992
5772
  {
4993
5773
  pointerEvents: "none",
4994
5774
  style: styles.leftIcon,
4995
5775
  accessibilityElementsHidden: true,
4996
5776
  importantForAccessibility: "no",
4997
- children: cloneElement8(startIcon, {
5777
+ children: cloneElement10(startIcon, {
4998
5778
  color: startIconColor,
4999
5779
  size: resolvedIconSize
5000
5780
  })
5001
5781
  }
5002
5782
  ),
5003
- /* @__PURE__ */ jsx37(
5004
- TextInput2,
5783
+ /* @__PURE__ */ jsx39(
5784
+ TextInput3,
5005
5785
  {
5006
5786
  ...props,
5007
5787
  ref,
@@ -5056,37 +5836,37 @@ var Input = forwardRef3(
5056
5836
  ]
5057
5837
  }
5058
5838
  ),
5059
- showClearButton ? /* @__PURE__ */ jsx37(
5060
- Pressable16,
5839
+ showClearButton ? /* @__PURE__ */ jsx39(
5840
+ Pressable17,
5061
5841
  {
5062
5842
  accessibilityRole: "button",
5063
5843
  accessibilityLabel: "Clear input",
5064
5844
  hitSlop: 8,
5065
5845
  onPress: handleClear,
5066
5846
  style: styles.clearButton,
5067
- children: clearIcon ? cloneElement8(clearIcon, {
5847
+ children: clearIcon ? cloneElement10(clearIcon, {
5068
5848
  color: clearIconColor,
5069
5849
  size: resolvedIconSize
5070
- }) : /* @__PURE__ */ jsx37(Text18, { style: [styles.clearButtonText, { color: clearIconColor }], children: "\xD7" })
5850
+ }) : /* @__PURE__ */ jsx39(Text19, { style: [styles.clearButtonText, { color: clearIconColor }], children: "\xD7" })
5071
5851
  }
5072
- ) : showRevealButton ? /* @__PURE__ */ jsx37(
5073
- Pressable16,
5852
+ ) : showRevealButton ? /* @__PURE__ */ jsx39(
5853
+ Pressable17,
5074
5854
  {
5075
5855
  accessibilityRole: "button",
5076
5856
  accessibilityLabel: isPasswordRevealed ? "Hide password" : "Show password",
5077
5857
  hitSlop: 8,
5078
5858
  onPress: () => setIsPasswordRevealed((revealed) => !revealed),
5079
5859
  style: styles.revealButton,
5080
- children: /* @__PURE__ */ jsx37(Text18, { style: styles.revealButtonText, children: isPasswordRevealed ? "Hide" : "Show" })
5860
+ children: /* @__PURE__ */ jsx39(Text19, { style: styles.revealButtonText, children: isPasswordRevealed ? "Hide" : "Show" })
5081
5861
  }
5082
- ) : showRightIcon && endIcon && /* @__PURE__ */ jsx37(
5862
+ ) : showRightIcon && endIcon && /* @__PURE__ */ jsx39(
5083
5863
  View31,
5084
5864
  {
5085
5865
  pointerEvents: "none",
5086
5866
  style: styles.rightIcon,
5087
5867
  accessibilityElementsHidden: true,
5088
5868
  importantForAccessibility: "no",
5089
- children: cloneElement8(endIcon, {
5869
+ children: cloneElement10(endIcon, {
5090
5870
  color: endIconColor,
5091
5871
  size: resolvedIconSize
5092
5872
  })
@@ -5096,7 +5876,7 @@ var Input = forwardRef3(
5096
5876
  if (!hasOwnField && field) {
5097
5877
  return control;
5098
5878
  }
5099
- return /* @__PURE__ */ jsx37(
5879
+ return /* @__PURE__ */ jsx39(
5100
5880
  FormField,
5101
5881
  {
5102
5882
  label,
@@ -5114,12 +5894,27 @@ var Input = forwardRef3(
5114
5894
  );
5115
5895
  Input.displayName = "Input";
5116
5896
 
5897
+ // src/primitives/Portal/Portal.tsx
5898
+ import { createContext as createContext7, useContext as useContext7 } from "react";
5899
+ import { Fragment as Fragment7, jsx as jsx40 } from "react/jsx-runtime";
5900
+ var PortalContext = createContext7(null);
5901
+ var PortalProvider = ({
5902
+ children,
5903
+ container = null
5904
+ }) => /* @__PURE__ */ jsx40(PortalContext.Provider, { value: container, children });
5905
+ var Portal = ({ children }) => {
5906
+ useContext7(PortalContext);
5907
+ return /* @__PURE__ */ jsx40(Fragment7, { children });
5908
+ };
5909
+ Portal.__velliraPortal = true;
5910
+ Portal.displayName = "Portal";
5911
+ PortalProvider.displayName = "PortalProvider";
5912
+
5117
5913
  // src/primitives/Radio/Radio.tsx
5118
- import { forwardRef as forwardRef4, useEffect as useEffect9 } from "react";
5119
- import { useControllableState as useControllableState4 } from "@vellira-ui/core";
5914
+ import { forwardRef as forwardRef4, useEffect as useEffect13 } from "react";
5120
5915
  import {
5121
- Pressable as Pressable17,
5122
- Text as Text19,
5916
+ Pressable as Pressable18,
5917
+ Text as Text20,
5123
5918
  View as View32
5124
5919
  } from "react-native";
5125
5920
 
@@ -5210,7 +6005,7 @@ var createStyles22 = (theme) => StyleSheet29.create({
5210
6005
  });
5211
6006
 
5212
6007
  // src/primitives/Radio/Radio.tsx
5213
- import { Fragment as Fragment7, jsx as jsx38, jsxs as jsxs23 } from "react/jsx-runtime";
6008
+ import { Fragment as Fragment8, jsx as jsx41, jsxs as jsxs23 } from "react/jsx-runtime";
5214
6009
  var controlSizeBySize = {
5215
6010
  sm: 14,
5216
6011
  md: 16,
@@ -5248,7 +6043,7 @@ var Radio = forwardRef4(
5248
6043
  const styles = createStyles22(theme);
5249
6044
  const group = useRadioGroupContext();
5250
6045
  const isInsideGroup = group !== null;
5251
- const [standaloneChecked, setStandaloneChecked] = useControllableState4({
6046
+ const [standaloneChecked, setStandaloneChecked] = useControllableState({
5252
6047
  value: checked,
5253
6048
  defaultValue: defaultChecked,
5254
6049
  onChange: onCheckedChange
@@ -5284,7 +6079,7 @@ var Radio = forwardRef4(
5284
6079
  };
5285
6080
  const typographySize = typographySizeByRadioSize[resolvedSize];
5286
6081
  const controlMarginTop = (typographySize.labelLineHeight - controlSize) / 2;
5287
- useEffect9(() => {
6082
+ useEffect13(() => {
5288
6083
  if (typeof __DEV__ !== "undefined" && __DEV__ && !label && !accessibilityLabel) {
5289
6084
  console.warn(
5290
6085
  "Radio requires either a visible label or accessibilityLabel."
@@ -5314,8 +6109,8 @@ var Radio = forwardRef4(
5314
6109
  typeof style === "function" ? style(state) : style
5315
6110
  ];
5316
6111
  return /* @__PURE__ */ jsxs23(View32, { style: [styles.root, containerStyle], children: [
5317
- /* @__PURE__ */ jsx38(
5318
- Pressable17,
6112
+ /* @__PURE__ */ jsx41(
6113
+ Pressable18,
5319
6114
  {
5320
6115
  ...rest,
5321
6116
  ref,
@@ -5329,8 +6124,8 @@ var Radio = forwardRef4(
5329
6124
  disabled: resolvedDisabled,
5330
6125
  onPress: handlePress,
5331
6126
  style: resolvePressableStyle,
5332
- children: (state) => /* @__PURE__ */ jsxs23(Fragment7, { children: [
5333
- /* @__PURE__ */ jsx38(
6127
+ children: (state) => /* @__PURE__ */ jsxs23(Fragment8, { children: [
6128
+ /* @__PURE__ */ jsx41(
5334
6129
  View32,
5335
6130
  {
5336
6131
  pointerEvents: "none",
@@ -5354,7 +6149,7 @@ var Radio = forwardRef4(
5354
6149
  resolvedDisabled && styles.controlDisabled,
5355
6150
  resolvedChecked && resolvedDisabled && styles.controlCheckedDisabled
5356
6151
  ],
5357
- children: resolvedChecked && (icon ?? /* @__PURE__ */ jsx38(
6152
+ children: resolvedChecked && (icon ?? /* @__PURE__ */ jsx41(
5358
6153
  View32,
5359
6154
  {
5360
6155
  style: [
@@ -5371,8 +6166,8 @@ var Radio = forwardRef4(
5371
6166
  }
5372
6167
  ),
5373
6168
  (label || description) && /* @__PURE__ */ jsxs23(View32, { pointerEvents: "none", style: styles.content, children: [
5374
- label && (typeof label === "string" ? /* @__PURE__ */ jsx38(
5375
- Text19,
6169
+ label && (typeof label === "string" ? /* @__PURE__ */ jsx41(
6170
+ Text20,
5376
6171
  {
5377
6172
  style: [
5378
6173
  styles.label,
@@ -5393,8 +6188,8 @@ var Radio = forwardRef4(
5393
6188
  children: label
5394
6189
  }
5395
6190
  ) : label),
5396
- description && (typeof description === "string" ? /* @__PURE__ */ jsx38(
5397
- Text19,
6191
+ description && (typeof description === "string" ? /* @__PURE__ */ jsx41(
6192
+ Text20,
5398
6193
  {
5399
6194
  style: [
5400
6195
  styles.description,
@@ -5412,8 +6207,8 @@ var Radio = forwardRef4(
5412
6207
  ] })
5413
6208
  }
5414
6209
  ),
5415
- error && /* @__PURE__ */ jsx38(
5416
- Text19,
6210
+ error && /* @__PURE__ */ jsx41(
6211
+ Text20,
5417
6212
  {
5418
6213
  accessibilityLiveRegion: "polite",
5419
6214
  style: [
@@ -5439,6 +6234,8 @@ export {
5439
6234
  FormField,
5440
6235
  Input,
5441
6236
  Modal2 as Modal,
6237
+ Portal,
6238
+ PortalProvider,
5442
6239
  Radio,
5443
6240
  RadioGroup,
5444
6241
  Select,