@vellira-ui/react-native 2.41.0 → 2.42.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +17 -13
- package/dist/index.js +444 -202
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -114,23 +114,27 @@ export function RoleSelect() {
|
|
|
114
114
|
|
|
115
115
|
### Dropdown Notes
|
|
116
116
|
|
|
117
|
-
Use `Dropdown` for contextual actions, not saved form values.
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
117
|
+
Use `Dropdown` for contextual actions, not saved form values. Compose native
|
|
118
|
+
menus with `Dropdown.Trigger`, `Dropdown.Content`, `Dropdown.Item`, groups,
|
|
119
|
+
labels, and separators. Use `open`, `defaultOpen`, and `onOpenChange` for menu
|
|
120
|
+
state. Use root `color` for the semantic trigger and menu palette, and
|
|
121
|
+
`Dropdown.Item danger` for destructive commands.
|
|
121
122
|
|
|
122
123
|
```tsx
|
|
123
|
-
import type { DropdownItem } from '@vellira-ui/react-native';
|
|
124
124
|
import { Dropdown } from '@vellira-ui/react-native';
|
|
125
125
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
<Dropdown
|
|
126
|
+
<Dropdown color='primary' label='Actions'>
|
|
127
|
+
<Dropdown.Content>
|
|
128
|
+
<Dropdown.Label>File</Dropdown.Label>
|
|
129
|
+
<Dropdown.Item value='duplicate' onSelect={duplicate}>
|
|
130
|
+
Duplicate
|
|
131
|
+
</Dropdown.Item>
|
|
132
|
+
<Dropdown.Separator />
|
|
133
|
+
<Dropdown.Item value='delete' danger onSelect={deleteFile}>
|
|
134
|
+
Delete
|
|
135
|
+
</Dropdown.Item>
|
|
136
|
+
</Dropdown.Content>
|
|
137
|
+
</Dropdown>;
|
|
134
138
|
```
|
|
135
139
|
|
|
136
140
|
### FormField Notes
|
package/dist/index.js
CHANGED
|
@@ -1,8 +1,133 @@
|
|
|
1
1
|
import { Children, cloneElement, createContext, forwardRef, isValidElement, useCallback, useContext, useEffect, useId, useMemo, useRef, useState } from "react";
|
|
2
2
|
import { Check, ChevronDown, Close, Search } from "@vellira-ui/icons";
|
|
3
|
-
import { AccessibilityInfo, ActivityIndicator, Animated, Dimensions, FlatList, Modal as Modal$1, Pressable, ScrollView, StyleSheet, Text, TextInput, View, findNodeHandle, useWindowDimensions } from "react-native";
|
|
3
|
+
import { AccessibilityInfo, ActivityIndicator, Animated, Dimensions, Easing, FlatList, Modal as Modal$1, Pressable, ScrollView, StyleSheet, Text, TextInput, View, findNodeHandle, useWindowDimensions } from "react-native";
|
|
4
4
|
import { darkTheme, highContrastTheme, lightTheme } from "@vellira-ui/tokens";
|
|
5
5
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
6
|
+
//#region src/managers/FloatingManager/useNativeFloatingPosition.ts
|
|
7
|
+
const safePadding = 12;
|
|
8
|
+
function useNativeFloatingPosition(placement = "top", offset = 8) {
|
|
9
|
+
const [position, setPosition] = useState({
|
|
10
|
+
top: 0,
|
|
11
|
+
left: 0
|
|
12
|
+
});
|
|
13
|
+
const floatingSizeRef = useRef({
|
|
14
|
+
width: 0,
|
|
15
|
+
height: 0
|
|
16
|
+
});
|
|
17
|
+
const lastTriggerRef = useRef(null);
|
|
18
|
+
const clamp = useCallback((value, min, max) => {
|
|
19
|
+
return Math.min(Math.max(value, min), Math.max(min, max));
|
|
20
|
+
}, []);
|
|
21
|
+
const calculatePosition = useCallback((triggerRect, size) => {
|
|
22
|
+
const { width: screenWidth, height: screenHeight } = Dimensions.get("window");
|
|
23
|
+
const [side, align = "center"] = placement.split("-");
|
|
24
|
+
const horizontalTop = side === "bottom" ? triggerRect.y + triggerRect.height + offset : triggerRect.y - size.height - offset;
|
|
25
|
+
const verticalTop = align === "start" ? triggerRect.y : align === "end" ? triggerRect.y + triggerRect.height - size.height : triggerRect.y + triggerRect.height / 2 - size.height / 2;
|
|
26
|
+
const horizontalLeft = align === "start" ? triggerRect.x : align === "end" ? triggerRect.x + triggerRect.width - size.width : triggerRect.x + triggerRect.width / 2 - size.width / 2;
|
|
27
|
+
const verticalLeft = side === "right" ? triggerRect.x + triggerRect.width + offset : triggerRect.x - size.width - offset;
|
|
28
|
+
const rawPosition = side === "left" || side === "right" ? {
|
|
29
|
+
top: verticalTop,
|
|
30
|
+
left: verticalLeft
|
|
31
|
+
} : {
|
|
32
|
+
top: horizontalTop,
|
|
33
|
+
left: horizontalLeft
|
|
34
|
+
};
|
|
35
|
+
return {
|
|
36
|
+
top: clamp(rawPosition.top, safePadding, screenHeight - size.height - safePadding),
|
|
37
|
+
left: clamp(rawPosition.left, safePadding, screenWidth - size.width - safePadding)
|
|
38
|
+
};
|
|
39
|
+
}, [
|
|
40
|
+
placement,
|
|
41
|
+
offset,
|
|
42
|
+
clamp
|
|
43
|
+
]);
|
|
44
|
+
const updatePosition = useCallback((triggerRef, measuredSize = floatingSizeRef.current) => {
|
|
45
|
+
lastTriggerRef.current = triggerRef;
|
|
46
|
+
const node = triggerRef.current;
|
|
47
|
+
if (!node || typeof node.measureInWindow !== "function") {
|
|
48
|
+
setPosition({
|
|
49
|
+
top: 0,
|
|
50
|
+
left: 0
|
|
51
|
+
});
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
node.measureInWindow((x, y, width, height) => {
|
|
55
|
+
setPosition(calculatePosition({
|
|
56
|
+
x,
|
|
57
|
+
y,
|
|
58
|
+
width,
|
|
59
|
+
height
|
|
60
|
+
}, measuredSize));
|
|
61
|
+
});
|
|
62
|
+
}, [calculatePosition]);
|
|
63
|
+
return {
|
|
64
|
+
position,
|
|
65
|
+
updatePosition,
|
|
66
|
+
onFloatingLayout: useCallback((event) => {
|
|
67
|
+
const { width, height } = event.nativeEvent.layout;
|
|
68
|
+
const nextSize = {
|
|
69
|
+
width,
|
|
70
|
+
height
|
|
71
|
+
};
|
|
72
|
+
floatingSizeRef.current = nextSize;
|
|
73
|
+
if (lastTriggerRef.current) updatePosition(lastTriggerRef.current, nextSize);
|
|
74
|
+
}, [updatePosition])
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
//#endregion
|
|
78
|
+
//#region src/managers/OverlayStack/NativeOverlayStack.ts
|
|
79
|
+
let stack = [];
|
|
80
|
+
const nativeOverlayStackStore = {
|
|
81
|
+
add(id) {
|
|
82
|
+
stack = stack.filter((item) => item !== id);
|
|
83
|
+
stack.push(id);
|
|
84
|
+
},
|
|
85
|
+
remove(id) {
|
|
86
|
+
stack = stack.filter((item) => item !== id);
|
|
87
|
+
},
|
|
88
|
+
isTop(id) {
|
|
89
|
+
return stack[stack.length - 1] === id;
|
|
90
|
+
}
|
|
91
|
+
};
|
|
92
|
+
//#endregion
|
|
93
|
+
//#region src/managers/OverlayStack/useNativeOverlayStack.ts
|
|
94
|
+
const useNativeOverlayStack = ({ id, visible }) => {
|
|
95
|
+
useEffect(() => {
|
|
96
|
+
if (!visible) return;
|
|
97
|
+
nativeOverlayStackStore.add(id);
|
|
98
|
+
return () => {
|
|
99
|
+
nativeOverlayStackStore.remove(id);
|
|
100
|
+
};
|
|
101
|
+
}, [id, visible]);
|
|
102
|
+
return { isTopOverlay: useCallback(() => nativeOverlayStackStore.isTop(id), [id]) };
|
|
103
|
+
};
|
|
104
|
+
//#endregion
|
|
105
|
+
//#region src/hooks/behavior/overlay/useOverlayStack.ts
|
|
106
|
+
const useOverlayStack = ({ active, id }) => useNativeOverlayStack({
|
|
107
|
+
id,
|
|
108
|
+
visible: active
|
|
109
|
+
});
|
|
110
|
+
//#endregion
|
|
111
|
+
//#region src/hooks/behavior/overlay/useOverlayDismiss.ts
|
|
112
|
+
const useOverlayDismiss = ({ active, closeOnOutsidePress = true, id, requestClose }) => {
|
|
113
|
+
const { isTopOverlay } = useOverlayStack({
|
|
114
|
+
active,
|
|
115
|
+
id
|
|
116
|
+
});
|
|
117
|
+
const requestTopClose = useCallback(() => {
|
|
118
|
+
if (!isTopOverlay()) return;
|
|
119
|
+
requestClose();
|
|
120
|
+
}, [isTopOverlay, requestClose]);
|
|
121
|
+
return {
|
|
122
|
+
isTopOverlay,
|
|
123
|
+
requestClose: requestTopClose,
|
|
124
|
+
requestOutsideClose: useCallback(() => {
|
|
125
|
+
if (!closeOnOutsidePress) return;
|
|
126
|
+
requestTopClose();
|
|
127
|
+
}, [closeOnOutsidePress, requestTopClose])
|
|
128
|
+
};
|
|
129
|
+
};
|
|
130
|
+
//#endregion
|
|
6
131
|
//#region src/hooks/useControllableState.ts
|
|
7
132
|
const useControllableState = ({ value, defaultValue, onChange }) => {
|
|
8
133
|
const [internalValue, setInternalValue] = useState(defaultValue);
|
|
@@ -515,9 +640,10 @@ const createStyles$21 = (theme) => StyleSheet.create({
|
|
|
515
640
|
});
|
|
516
641
|
//#endregion
|
|
517
642
|
//#region src/components/Dropdown/Content/DropdownContent.tsx
|
|
518
|
-
function DropdownContent({ isOpen, children, onClose, contentStyle, accessibilityLabel, presentation, searchable = false, searchValue = "", searchPlaceholder = "Search actions...", searchAccessibilityLabel, onSearchChange }) {
|
|
643
|
+
function DropdownContent({ isOpen, children, onClose, color = "primary", contentStyle, accessibilityLabel, presentation, searchable = false, searchValue = "", searchPlaceholder = "Search actions...", searchAccessibilityLabel, onSearchChange }) {
|
|
519
644
|
const { theme } = useTheme();
|
|
520
645
|
const styles = useThemeStyles(createStyles$21);
|
|
646
|
+
const colorPalette = theme.components.dropdown[color];
|
|
521
647
|
const isSheet = presentation === "sheet";
|
|
522
648
|
const animation = useRef(new Animated.Value(isOpen ? 1 : 0)).current;
|
|
523
649
|
const [reduceMotion, setReduceMotion] = useState(false);
|
|
@@ -589,6 +715,7 @@ function DropdownContent({ isOpen, children, onClose, contentStyle, accessibilit
|
|
|
589
715
|
style: [
|
|
590
716
|
styles.menu,
|
|
591
717
|
styles[`${presentation}Menu`],
|
|
718
|
+
{ borderColor: colorPalette.content.border },
|
|
592
719
|
contentStyle,
|
|
593
720
|
menuAnimatedStyle
|
|
594
721
|
],
|
|
@@ -619,125 +746,6 @@ function DropdownContent({ isOpen, children, onClose, contentStyle, accessibilit
|
|
|
619
746
|
}
|
|
620
747
|
DropdownContent.displayName = "DropdownContent";
|
|
621
748
|
//#endregion
|
|
622
|
-
//#region src/managers/FloatingManager/useNativeFloatingPosition.ts
|
|
623
|
-
const safePadding = 12;
|
|
624
|
-
function useNativeFloatingPosition(placement = "top", offset = 8) {
|
|
625
|
-
const [position, setPosition] = useState({
|
|
626
|
-
top: 0,
|
|
627
|
-
left: 0
|
|
628
|
-
});
|
|
629
|
-
const floatingSizeRef = useRef({
|
|
630
|
-
width: 0,
|
|
631
|
-
height: 0
|
|
632
|
-
});
|
|
633
|
-
const lastTriggerRef = useRef(null);
|
|
634
|
-
const clamp = useCallback((value, min, max) => {
|
|
635
|
-
return Math.min(Math.max(value, min), Math.max(min, max));
|
|
636
|
-
}, []);
|
|
637
|
-
const calculatePosition = useCallback((triggerRect, size) => {
|
|
638
|
-
const { width: screenWidth, height: screenHeight } = Dimensions.get("window");
|
|
639
|
-
const [side, align = "center"] = placement.split("-");
|
|
640
|
-
const horizontalTop = side === "bottom" ? triggerRect.y + triggerRect.height + offset : triggerRect.y - size.height - offset;
|
|
641
|
-
const verticalTop = align === "start" ? triggerRect.y : align === "end" ? triggerRect.y + triggerRect.height - size.height : triggerRect.y + triggerRect.height / 2 - size.height / 2;
|
|
642
|
-
const horizontalLeft = align === "start" ? triggerRect.x : align === "end" ? triggerRect.x + triggerRect.width - size.width : triggerRect.x + triggerRect.width / 2 - size.width / 2;
|
|
643
|
-
const verticalLeft = side === "right" ? triggerRect.x + triggerRect.width + offset : triggerRect.x - size.width - offset;
|
|
644
|
-
const rawPosition = side === "left" || side === "right" ? {
|
|
645
|
-
top: verticalTop,
|
|
646
|
-
left: verticalLeft
|
|
647
|
-
} : {
|
|
648
|
-
top: horizontalTop,
|
|
649
|
-
left: horizontalLeft
|
|
650
|
-
};
|
|
651
|
-
return {
|
|
652
|
-
top: clamp(rawPosition.top, safePadding, screenHeight - size.height - safePadding),
|
|
653
|
-
left: clamp(rawPosition.left, safePadding, screenWidth - size.width - safePadding)
|
|
654
|
-
};
|
|
655
|
-
}, [
|
|
656
|
-
placement,
|
|
657
|
-
offset,
|
|
658
|
-
clamp
|
|
659
|
-
]);
|
|
660
|
-
const updatePosition = useCallback((triggerRef, measuredSize = floatingSizeRef.current) => {
|
|
661
|
-
lastTriggerRef.current = triggerRef;
|
|
662
|
-
const node = triggerRef.current;
|
|
663
|
-
if (!node || typeof node.measureInWindow !== "function") {
|
|
664
|
-
setPosition({
|
|
665
|
-
top: 0,
|
|
666
|
-
left: 0
|
|
667
|
-
});
|
|
668
|
-
return;
|
|
669
|
-
}
|
|
670
|
-
node.measureInWindow((x, y, width, height) => {
|
|
671
|
-
setPosition(calculatePosition({
|
|
672
|
-
x,
|
|
673
|
-
y,
|
|
674
|
-
width,
|
|
675
|
-
height
|
|
676
|
-
}, measuredSize));
|
|
677
|
-
});
|
|
678
|
-
}, [calculatePosition]);
|
|
679
|
-
return {
|
|
680
|
-
position,
|
|
681
|
-
updatePosition,
|
|
682
|
-
onFloatingLayout: useCallback((event) => {
|
|
683
|
-
const { width, height } = event.nativeEvent.layout;
|
|
684
|
-
const nextSize = {
|
|
685
|
-
width,
|
|
686
|
-
height
|
|
687
|
-
};
|
|
688
|
-
floatingSizeRef.current = nextSize;
|
|
689
|
-
if (lastTriggerRef.current) updatePosition(lastTriggerRef.current, nextSize);
|
|
690
|
-
}, [updatePosition])
|
|
691
|
-
};
|
|
692
|
-
}
|
|
693
|
-
//#endregion
|
|
694
|
-
//#region src/managers/OverlayStack/NativeOverlayStack.ts
|
|
695
|
-
let stack = [];
|
|
696
|
-
const nativeOverlayStackStore = {
|
|
697
|
-
add(id) {
|
|
698
|
-
stack = stack.filter((item) => item !== id);
|
|
699
|
-
stack.push(id);
|
|
700
|
-
},
|
|
701
|
-
remove(id) {
|
|
702
|
-
stack = stack.filter((item) => item !== id);
|
|
703
|
-
},
|
|
704
|
-
isTop(id) {
|
|
705
|
-
return stack[stack.length - 1] === id;
|
|
706
|
-
}
|
|
707
|
-
};
|
|
708
|
-
//#endregion
|
|
709
|
-
//#region src/managers/OverlayStack/useNativeOverlayStack.ts
|
|
710
|
-
const useNativeOverlayStack = ({ id, visible }) => {
|
|
711
|
-
useEffect(() => {
|
|
712
|
-
if (!visible) return;
|
|
713
|
-
nativeOverlayStackStore.add(id);
|
|
714
|
-
return () => {
|
|
715
|
-
nativeOverlayStackStore.remove(id);
|
|
716
|
-
};
|
|
717
|
-
}, [id, visible]);
|
|
718
|
-
return { isTopOverlay: useCallback(() => nativeOverlayStackStore.isTop(id), [id]) };
|
|
719
|
-
};
|
|
720
|
-
//#endregion
|
|
721
|
-
//#region src/managers/OverlayStack/useNativeDismiss.ts
|
|
722
|
-
const useNativeDismiss = ({ id, visible, closeOnOutsidePress = true, onClose }) => {
|
|
723
|
-
const { isTopOverlay } = useNativeOverlayStack({
|
|
724
|
-
id,
|
|
725
|
-
visible
|
|
726
|
-
});
|
|
727
|
-
const requestClose = useCallback(() => {
|
|
728
|
-
if (!isTopOverlay()) return;
|
|
729
|
-
onClose();
|
|
730
|
-
}, [isTopOverlay, onClose]);
|
|
731
|
-
return {
|
|
732
|
-
isTopOverlay,
|
|
733
|
-
requestClose,
|
|
734
|
-
requestOutsideClose: useCallback(() => {
|
|
735
|
-
if (!closeOnOutsidePress) return;
|
|
736
|
-
requestClose();
|
|
737
|
-
}, [closeOnOutsidePress, requestClose])
|
|
738
|
-
};
|
|
739
|
-
};
|
|
740
|
-
//#endregion
|
|
741
749
|
//#region src/components/Dropdown/Group/DropdownGroup.styles.ts
|
|
742
750
|
const createStyles$20 = (theme) => StyleSheet.create({ groupLabel: {
|
|
743
751
|
paddingHorizontal: theme.tokens.spacing[4],
|
|
@@ -875,10 +883,6 @@ const createStyles$19 = (theme) => StyleSheet.create({
|
|
|
875
883
|
backgroundColor: theme.components.dropdown.item.default.bg,
|
|
876
884
|
borderRadius: theme.tokens.radius.sm
|
|
877
885
|
},
|
|
878
|
-
itemPressed: { backgroundColor: theme.components.dropdown.item.pressed.bg },
|
|
879
|
-
itemDisabled: { backgroundColor: theme.components.dropdown.item.disabled.bg },
|
|
880
|
-
itemDanger: { backgroundColor: theme.components.dropdown.item.danger.default.bg },
|
|
881
|
-
itemDangerPressed: { backgroundColor: theme.components.dropdown.item.danger.active.bg },
|
|
882
886
|
itemText: {
|
|
883
887
|
flex: 1,
|
|
884
888
|
minWidth: 0,
|
|
@@ -886,17 +890,14 @@ const createStyles$19 = (theme) => StyleSheet.create({
|
|
|
886
890
|
fontFamily: theme.tokens.typography.family.regular,
|
|
887
891
|
fontSize: theme.tokens.typography.size.md,
|
|
888
892
|
lineHeight: theme.tokens.typography.lineHeight.md
|
|
889
|
-
}
|
|
890
|
-
itemTextPressed: { color: theme.components.dropdown.item.pressed.fg },
|
|
891
|
-
itemTextDisabled: { color: theme.components.dropdown.item.disabled.fg },
|
|
892
|
-
itemTextDanger: { color: theme.components.dropdown.item.danger.default.fg },
|
|
893
|
-
itemTextDangerPressed: { color: theme.components.dropdown.item.danger.active.fg }
|
|
893
|
+
}
|
|
894
894
|
});
|
|
895
895
|
//#endregion
|
|
896
896
|
//#region src/components/Dropdown/Item/DropdownItem.tsx
|
|
897
|
-
function DropdownItem({ label, value, icon, danger = false, disabled = false, textWrap = "truncate", itemStyle, textStyle, onSelect }) {
|
|
897
|
+
function DropdownItem({ label, value, color = "primary", icon, danger = false, disabled = false, textWrap = "truncate", itemStyle, textStyle, onSelect }) {
|
|
898
898
|
const { theme } = useTheme();
|
|
899
899
|
const styles = useThemeStyles(createStyles$19);
|
|
900
|
+
const colorPalette = theme.components.dropdown[color];
|
|
900
901
|
const renderColoredNode = (node, color) => {
|
|
901
902
|
if (!isValidElement(node)) return node;
|
|
902
903
|
return cloneElement(node, { color });
|
|
@@ -904,12 +905,12 @@ function DropdownItem({ label, value, icon, danger = false, disabled = false, te
|
|
|
904
905
|
const getContentColor = (pressed) => {
|
|
905
906
|
if (disabled) return theme.components.dropdown.item.disabled.fg;
|
|
906
907
|
if (danger) return pressed ? theme.components.dropdown.item.danger.active.fg : theme.components.dropdown.item.danger.default.fg;
|
|
907
|
-
return pressed ?
|
|
908
|
+
return pressed ? colorPalette.item.pressed.fg : theme.components.dropdown.item.default.fg;
|
|
908
909
|
};
|
|
909
910
|
const getBackgroundColor = (pressed) => {
|
|
910
911
|
if (disabled) return theme.components.dropdown.item.disabled.bg;
|
|
911
912
|
if (danger) return pressed ? theme.components.dropdown.item.danger.active.bg : theme.components.dropdown.item.danger.default.bg;
|
|
912
|
-
return pressed ?
|
|
913
|
+
return pressed ? colorPalette.item.pressed.bg : theme.components.dropdown.item.default.bg;
|
|
913
914
|
};
|
|
914
915
|
const accessibilityLabel = typeof label === "string" ? label : value;
|
|
915
916
|
const numberOfLines = textWrap === "wrap" ? void 0 : 1;
|
|
@@ -1009,10 +1010,6 @@ const createStyles$17 = (theme) => StyleSheet.create({
|
|
|
1009
1010
|
minHeight: 52,
|
|
1010
1011
|
padding: 0
|
|
1011
1012
|
},
|
|
1012
|
-
triggerPressed: {
|
|
1013
|
-
backgroundColor: theme.components.dropdown.trigger.hover.bg,
|
|
1014
|
-
borderColor: theme.components.dropdown.trigger.hover.border
|
|
1015
|
-
},
|
|
1016
1013
|
triggerDisabled: {
|
|
1017
1014
|
backgroundColor: theme.components.dropdown.trigger.disabled.bg,
|
|
1018
1015
|
borderColor: theme.components.dropdown.trigger.disabled.border,
|
|
@@ -1022,7 +1019,6 @@ const createStyles$17 = (theme) => StyleSheet.create({
|
|
|
1022
1019
|
color: theme.components.dropdown.trigger.default.fg,
|
|
1023
1020
|
fontFamily: theme.tokens.typography.family.regular
|
|
1024
1021
|
},
|
|
1025
|
-
triggerTextPressed: { color: theme.components.dropdown.trigger.hover.fg },
|
|
1026
1022
|
triggerTextDisabled: { color: theme.components.dropdown.trigger.disabled.fg },
|
|
1027
1023
|
textSm: {
|
|
1028
1024
|
fontSize: theme.tokens.typography.size.sm,
|
|
@@ -1049,9 +1045,10 @@ const createStyles$17 = (theme) => StyleSheet.create({
|
|
|
1049
1045
|
});
|
|
1050
1046
|
//#endregion
|
|
1051
1047
|
//#region src/components/Dropdown/Trigger/DropdownTrigger.tsx
|
|
1052
|
-
function DropdownTrigger({ label, trigger, children, icon, arrowIcon, showArrow = true, size = "md", disabled = false, isOpen, triggerStyle, triggerRef, accessibilityLabel, accessibilityHint, onPress }) {
|
|
1048
|
+
function DropdownTrigger({ asChild = false, label, trigger, children, icon, arrowIcon, showArrow = true, color = "primary", size = "md", disabled = false, isOpen, triggerStyle, triggerRef, accessibilityLabel, accessibilityHint, onPress }) {
|
|
1053
1049
|
const { theme } = useTheme();
|
|
1054
1050
|
const styles = useThemeStyles(createStyles$17);
|
|
1051
|
+
const colorPalette = theme.components.dropdown[color];
|
|
1055
1052
|
const textSizeStyle = {
|
|
1056
1053
|
sm: styles.textSm,
|
|
1057
1054
|
md: styles.textMd,
|
|
@@ -1091,7 +1088,7 @@ function DropdownTrigger({ label, trigger, children, icon, arrowIcon, showArrow
|
|
|
1091
1088
|
if (!isValidElement(node)) return node;
|
|
1092
1089
|
return cloneElement(node, { color });
|
|
1093
1090
|
};
|
|
1094
|
-
const contentColor = disabled ? theme.components.dropdown.trigger.disabled.fg : isPressed ?
|
|
1091
|
+
const contentColor = disabled ? theme.components.dropdown.trigger.disabled.fg : isPressed ? colorPalette.trigger.hover.fg : colorPalette.trigger.default.fg;
|
|
1095
1092
|
const arrow = arrowIcon ? renderColoredNode(arrowIcon, contentColor) : /* @__PURE__ */ jsx(ChevronDown, {
|
|
1096
1093
|
width: 16,
|
|
1097
1094
|
height: 16,
|
|
@@ -1099,7 +1096,7 @@ function DropdownTrigger({ label, trigger, children, icon, arrowIcon, showArrow
|
|
|
1099
1096
|
});
|
|
1100
1097
|
const renderedIcon = icon ? renderColoredNode(icon, contentColor) : null;
|
|
1101
1098
|
const triggerContent = trigger ?? children;
|
|
1102
|
-
if (isValidElement(triggerContent)) {
|
|
1099
|
+
if (asChild && isValidElement(triggerContent)) {
|
|
1103
1100
|
const child = triggerContent;
|
|
1104
1101
|
const isChildDisabled = disabled || child.props.disabled;
|
|
1105
1102
|
return cloneElement(child, {
|
|
@@ -1133,9 +1130,16 @@ function DropdownTrigger({ label, trigger, children, icon, arrowIcon, showArrow
|
|
|
1133
1130
|
style: [
|
|
1134
1131
|
styles.trigger,
|
|
1135
1132
|
styles[size],
|
|
1133
|
+
{
|
|
1134
|
+
backgroundColor: colorPalette.trigger.default.bg,
|
|
1135
|
+
borderColor: colorPalette.trigger.default.border
|
|
1136
|
+
},
|
|
1136
1137
|
isIconOnly && styles.iconOnly,
|
|
1137
1138
|
isIconOnly && iconOnlySizeStyle,
|
|
1138
|
-
isPressed && !disabled &&
|
|
1139
|
+
isPressed && !disabled && {
|
|
1140
|
+
backgroundColor: colorPalette.trigger.hover.bg,
|
|
1141
|
+
borderColor: colorPalette.trigger.hover.border
|
|
1142
|
+
},
|
|
1139
1143
|
disabled && styles.triggerDisabled,
|
|
1140
1144
|
triggerStyle
|
|
1141
1145
|
],
|
|
@@ -1178,7 +1182,7 @@ const createStyles$16 = (theme) => StyleSheet.create({
|
|
|
1178
1182
|
});
|
|
1179
1183
|
//#endregion
|
|
1180
1184
|
//#region src/components/Dropdown/Dropdown.tsx
|
|
1181
|
-
function DropdownRoot({ children, label = "Menu", trigger, icon, arrowIcon, showArrow = true, open, defaultOpen = false, onOpenChange, presentation = "auto", closeOnSelect = true, disabled = false, loading = false, loadingText = "Loading actions...", searchable = false, command = false, searchValue, defaultSearchValue = "", searchPlaceholder, onSearch, empty, noOptionsText, size = "md", style, triggerStyle, contentStyle, itemStyle, textStyle, accessibilityLabel, accessibilityHint }) {
|
|
1185
|
+
function DropdownRoot({ children, label = "Menu", trigger, icon, arrowIcon, showArrow = true, open, defaultOpen = false, onOpenChange, presentation = "auto", closeOnSelect = true, color = "primary", disabled = false, loading = false, loadingText = "Loading actions...", searchable = false, command = false, searchValue, defaultSearchValue = "", searchPlaceholder, onSearch, empty, noOptionsText, size = "md", style, triggerStyle, contentStyle, itemStyle, textStyle, accessibilityLabel, accessibilityHint }) {
|
|
1182
1186
|
const styles = useThemeStyles(createStyles$16);
|
|
1183
1187
|
const overlayId = useId();
|
|
1184
1188
|
const [uncontrolledSearchValue, setUncontrolledSearchValue] = useState(defaultSearchValue);
|
|
@@ -1228,10 +1232,10 @@ function DropdownRoot({ children, label = "Menu", trigger, icon, arrowIcon, show
|
|
|
1228
1232
|
closeDropdown();
|
|
1229
1233
|
requestAnimationFrame(focusTrigger);
|
|
1230
1234
|
}, [closeDropdown, focusTrigger]);
|
|
1231
|
-
const dismiss =
|
|
1235
|
+
const dismiss = useOverlayDismiss({
|
|
1232
1236
|
id: overlayId,
|
|
1233
|
-
|
|
1234
|
-
|
|
1237
|
+
active: isOpen,
|
|
1238
|
+
requestClose: closeAndFocusTrigger
|
|
1235
1239
|
});
|
|
1236
1240
|
const handleSelect = useCallback((entry) => {
|
|
1237
1241
|
if (entry.disabled || loading) return;
|
|
@@ -1265,6 +1269,7 @@ function DropdownRoot({ children, label = "Menu", trigger, icon, arrowIcon, show
|
|
|
1265
1269
|
return /* @__PURE__ */ jsx(DropdownItem, {
|
|
1266
1270
|
label: item.props.children,
|
|
1267
1271
|
value: item.props.value ?? item.id,
|
|
1272
|
+
color,
|
|
1268
1273
|
icon: item.props.icon,
|
|
1269
1274
|
danger: item.props.danger,
|
|
1270
1275
|
disabled: item.props.disabled,
|
|
@@ -1274,6 +1279,7 @@ function DropdownRoot({ children, label = "Menu", trigger, icon, arrowIcon, show
|
|
|
1274
1279
|
onSelect: () => handleSelect(item)
|
|
1275
1280
|
});
|
|
1276
1281
|
}, [
|
|
1282
|
+
color,
|
|
1277
1283
|
handleSelect,
|
|
1278
1284
|
itemStyle,
|
|
1279
1285
|
styles.emptyText,
|
|
@@ -1293,11 +1299,13 @@ function DropdownRoot({ children, label = "Menu", trigger, icon, arrowIcon, show
|
|
|
1293
1299
|
return /* @__PURE__ */ jsxs(View, {
|
|
1294
1300
|
style: [styles.root, style],
|
|
1295
1301
|
children: [/* @__PURE__ */ jsx(DropdownTrigger, {
|
|
1302
|
+
asChild: Boolean(parsed.trigger),
|
|
1296
1303
|
label,
|
|
1297
1304
|
trigger: trigger ?? parsed.trigger,
|
|
1298
1305
|
icon,
|
|
1299
1306
|
arrowIcon,
|
|
1300
1307
|
showArrow,
|
|
1308
|
+
color,
|
|
1301
1309
|
disabled: disabled || parsed.triggerProps?.disabled,
|
|
1302
1310
|
isOpen,
|
|
1303
1311
|
size,
|
|
@@ -1311,6 +1319,7 @@ function DropdownRoot({ children, label = "Menu", trigger, icon, arrowIcon, show
|
|
|
1311
1319
|
}), /* @__PURE__ */ jsx(DropdownContent, {
|
|
1312
1320
|
isOpen,
|
|
1313
1321
|
onClose: dismiss.requestClose,
|
|
1322
|
+
color,
|
|
1314
1323
|
contentStyle: [contentStyle, contentStyleFromSlot],
|
|
1315
1324
|
accessibilityLabel: menuAccessibilityLabel,
|
|
1316
1325
|
presentation: presentationFromSlot ?? resolvedPresentation,
|
|
@@ -1576,11 +1585,11 @@ const ModalRoot = ({ open, defaultOpen = false, onOpenChange, closeOnOutsidePres
|
|
|
1576
1585
|
onOpenChange,
|
|
1577
1586
|
closeOnOutsidePress
|
|
1578
1587
|
});
|
|
1579
|
-
const dismiss =
|
|
1588
|
+
const dismiss = useOverlayDismiss({
|
|
1580
1589
|
id: modal.contentId,
|
|
1581
|
-
|
|
1590
|
+
active: modal.open,
|
|
1582
1591
|
closeOnOutsidePress: modal.closeOnOutsidePress,
|
|
1583
|
-
|
|
1592
|
+
requestClose: modal.requestClose
|
|
1584
1593
|
});
|
|
1585
1594
|
return /* @__PURE__ */ jsx(ModalContext.Provider, {
|
|
1586
1595
|
value: {
|
|
@@ -3475,11 +3484,11 @@ function SelectRoot(props) {
|
|
|
3475
3484
|
fieldDescribedBy: field?.ariaDescribedBy
|
|
3476
3485
|
});
|
|
3477
3486
|
const hasValue = selectedValues.length > 0;
|
|
3478
|
-
const dismiss =
|
|
3487
|
+
const dismiss = useOverlayDismiss({
|
|
3479
3488
|
id: overlayId,
|
|
3480
|
-
|
|
3489
|
+
active: isOpen,
|
|
3481
3490
|
closeOnOutsidePress: dismissOnBackdropPress,
|
|
3482
|
-
|
|
3491
|
+
requestClose: closeDropdown
|
|
3483
3492
|
});
|
|
3484
3493
|
const clearValue = () => {
|
|
3485
3494
|
selectedFocusValueRef.current = void 0;
|
|
@@ -3699,18 +3708,216 @@ const TabsContent = ({ value, children, forceMount = false, style }) => {
|
|
|
3699
3708
|
TabsContent.displayName = "Tabs.Content";
|
|
3700
3709
|
//#endregion
|
|
3701
3710
|
//#region src/components/Tabs/List/TabsIndicator.tsx
|
|
3702
|
-
const
|
|
3703
|
-
|
|
3704
|
-
|
|
3705
|
-
|
|
3706
|
-
|
|
3707
|
-
|
|
3711
|
+
const COLLAPSED_SIZE = 8;
|
|
3712
|
+
const LINE_ANIMATION_DURATION = 360;
|
|
3713
|
+
const SURFACE_ANIMATION_DURATION = 220;
|
|
3714
|
+
const easing = Easing?.bezier?.(.22, 1, .36, 1) ?? ((value) => value);
|
|
3715
|
+
const animateValue = (value, toValue, duration) => Animated.timing(value, {
|
|
3716
|
+
toValue,
|
|
3717
|
+
duration,
|
|
3718
|
+
easing,
|
|
3719
|
+
useNativeDriver: false
|
|
3708
3720
|
});
|
|
3721
|
+
const TabsIndicator = ({ children, style }) => {
|
|
3722
|
+
const { theme } = useTheme();
|
|
3723
|
+
const { value, orientation, variant, color, size, indicatorVersion, getTriggerLayout } = useTabs();
|
|
3724
|
+
const translateX = useRef(new Animated.Value(0)).current;
|
|
3725
|
+
const translateY = useRef(new Animated.Value(0)).current;
|
|
3726
|
+
const width = useRef(new Animated.Value(0)).current;
|
|
3727
|
+
const height = useRef(new Animated.Value(0)).current;
|
|
3728
|
+
const previousLayoutRef = useRef(null);
|
|
3729
|
+
const previousValueRef = useRef(void 0);
|
|
3730
|
+
const previousOrientationRef = useRef(orientation);
|
|
3731
|
+
const animationRef = useRef(null);
|
|
3732
|
+
const [reduceMotion, setReduceMotion] = useState(false);
|
|
3733
|
+
const [visible, setVisible] = useState(false);
|
|
3734
|
+
const isVertical = orientation === "vertical";
|
|
3735
|
+
const palette = theme.components.tabs[color];
|
|
3736
|
+
useEffect(() => {
|
|
3737
|
+
AccessibilityInfo.isReduceMotionEnabled?.().then(setReduceMotion);
|
|
3738
|
+
const subscription = AccessibilityInfo.addEventListener?.("reduceMotionChanged", setReduceMotion);
|
|
3739
|
+
return () => {
|
|
3740
|
+
subscription?.remove();
|
|
3741
|
+
animationRef.current?.stop();
|
|
3742
|
+
};
|
|
3743
|
+
}, []);
|
|
3744
|
+
useEffect(() => {
|
|
3745
|
+
if (!value) {
|
|
3746
|
+
setVisible(false);
|
|
3747
|
+
return;
|
|
3748
|
+
}
|
|
3749
|
+
const nextLayout = getTriggerLayout(value);
|
|
3750
|
+
if (!nextLayout || nextLayout.width <= 0 || nextLayout.height <= 0) {
|
|
3751
|
+
setVisible(false);
|
|
3752
|
+
return;
|
|
3753
|
+
}
|
|
3754
|
+
setVisible(true);
|
|
3755
|
+
animationRef.current?.stop();
|
|
3756
|
+
const previousLayout = previousLayoutRef.current;
|
|
3757
|
+
if (!(!reduceMotion && previousLayout && previousValueRef.current !== value && previousOrientationRef.current === orientation)) {
|
|
3758
|
+
translateX.setValue(nextLayout.x);
|
|
3759
|
+
translateY.setValue(nextLayout.y);
|
|
3760
|
+
width.setValue(nextLayout.width);
|
|
3761
|
+
height.setValue(nextLayout.height);
|
|
3762
|
+
previousLayoutRef.current = nextLayout;
|
|
3763
|
+
previousValueRef.current = value;
|
|
3764
|
+
previousOrientationRef.current = orientation;
|
|
3765
|
+
return;
|
|
3766
|
+
}
|
|
3767
|
+
if (variant === "line" && isVertical) {
|
|
3768
|
+
const previousCenter = previousLayout.y + previousLayout.height / 2;
|
|
3769
|
+
const nextCenter = nextLayout.y + nextLayout.height / 2;
|
|
3770
|
+
const collapsedPreviousY = previousCenter - COLLAPSED_SIZE / 2;
|
|
3771
|
+
const collapsedNextY = nextCenter - COLLAPSED_SIZE / 2;
|
|
3772
|
+
translateY.setValue(previousLayout.y);
|
|
3773
|
+
height.setValue(previousLayout.height);
|
|
3774
|
+
animationRef.current = Animated.sequence([
|
|
3775
|
+
Animated.parallel([animateValue(height, COLLAPSED_SIZE, LINE_ANIMATION_DURATION * .28), animateValue(translateY, collapsedPreviousY, LINE_ANIMATION_DURATION * .28)]),
|
|
3776
|
+
animateValue(translateY, collapsedNextY, LINE_ANIMATION_DURATION * .36),
|
|
3777
|
+
Animated.parallel([animateValue(height, nextLayout.height, LINE_ANIMATION_DURATION * .36), animateValue(translateY, nextLayout.y, LINE_ANIMATION_DURATION * .36)])
|
|
3778
|
+
]);
|
|
3779
|
+
} else if (variant === "line") {
|
|
3780
|
+
const previousCenter = previousLayout.x + previousLayout.width / 2;
|
|
3781
|
+
const nextCenter = nextLayout.x + nextLayout.width / 2;
|
|
3782
|
+
const collapsedPreviousX = previousCenter - COLLAPSED_SIZE / 2;
|
|
3783
|
+
const collapsedNextX = nextCenter - COLLAPSED_SIZE / 2;
|
|
3784
|
+
translateX.setValue(previousLayout.x);
|
|
3785
|
+
width.setValue(previousLayout.width);
|
|
3786
|
+
animationRef.current = Animated.sequence([
|
|
3787
|
+
Animated.parallel([animateValue(width, COLLAPSED_SIZE, LINE_ANIMATION_DURATION * .28), animateValue(translateX, collapsedPreviousX, LINE_ANIMATION_DURATION * .28)]),
|
|
3788
|
+
animateValue(translateX, collapsedNextX, LINE_ANIMATION_DURATION * .36),
|
|
3789
|
+
Animated.parallel([animateValue(width, nextLayout.width, LINE_ANIMATION_DURATION * .36), animateValue(translateX, nextLayout.x, LINE_ANIMATION_DURATION * .36)])
|
|
3790
|
+
]);
|
|
3791
|
+
} else {
|
|
3792
|
+
translateX.setValue(previousLayout.x);
|
|
3793
|
+
translateY.setValue(previousLayout.y);
|
|
3794
|
+
width.setValue(previousLayout.width);
|
|
3795
|
+
height.setValue(previousLayout.height);
|
|
3796
|
+
animationRef.current = Animated.parallel([
|
|
3797
|
+
animateValue(translateX, nextLayout.x, SURFACE_ANIMATION_DURATION),
|
|
3798
|
+
animateValue(translateY, nextLayout.y, SURFACE_ANIMATION_DURATION),
|
|
3799
|
+
animateValue(width, nextLayout.width, SURFACE_ANIMATION_DURATION),
|
|
3800
|
+
animateValue(height, nextLayout.height, SURFACE_ANIMATION_DURATION)
|
|
3801
|
+
]);
|
|
3802
|
+
}
|
|
3803
|
+
animationRef.current.start(() => {
|
|
3804
|
+
translateX.setValue(nextLayout.x);
|
|
3805
|
+
translateY.setValue(nextLayout.y);
|
|
3806
|
+
width.setValue(nextLayout.width);
|
|
3807
|
+
height.setValue(nextLayout.height);
|
|
3808
|
+
});
|
|
3809
|
+
previousLayoutRef.current = nextLayout;
|
|
3810
|
+
previousValueRef.current = value;
|
|
3811
|
+
previousOrientationRef.current = orientation;
|
|
3812
|
+
}, [
|
|
3813
|
+
getTriggerLayout,
|
|
3814
|
+
height,
|
|
3815
|
+
indicatorVersion,
|
|
3816
|
+
isVertical,
|
|
3817
|
+
orientation,
|
|
3818
|
+
reduceMotion,
|
|
3819
|
+
translateX,
|
|
3820
|
+
translateY,
|
|
3821
|
+
value,
|
|
3822
|
+
variant,
|
|
3823
|
+
width
|
|
3824
|
+
]);
|
|
3825
|
+
const indicatorStyle = useMemo(() => {
|
|
3826
|
+
const baseStyle = {
|
|
3827
|
+
position: "absolute",
|
|
3828
|
+
opacity: visible ? 1 : 0,
|
|
3829
|
+
zIndex: 0
|
|
3830
|
+
};
|
|
3831
|
+
if (variant === "line") return [
|
|
3832
|
+
baseStyle,
|
|
3833
|
+
{
|
|
3834
|
+
backgroundColor: palette.indicator.bg,
|
|
3835
|
+
borderRadius: theme.tokens.radius.full
|
|
3836
|
+
},
|
|
3837
|
+
isVertical ? {
|
|
3838
|
+
top: 0,
|
|
3839
|
+
left: 0,
|
|
3840
|
+
width: 3,
|
|
3841
|
+
height,
|
|
3842
|
+
transform: [{ translateY }]
|
|
3843
|
+
} : {
|
|
3844
|
+
right: void 0,
|
|
3845
|
+
bottom: 0,
|
|
3846
|
+
left: 0,
|
|
3847
|
+
width,
|
|
3848
|
+
height: 3,
|
|
3849
|
+
transform: [{ translateX }]
|
|
3850
|
+
},
|
|
3851
|
+
style
|
|
3852
|
+
];
|
|
3853
|
+
if (variant === "pills") return [
|
|
3854
|
+
baseStyle,
|
|
3855
|
+
{
|
|
3856
|
+
top: 0,
|
|
3857
|
+
left: 0,
|
|
3858
|
+
width,
|
|
3859
|
+
height,
|
|
3860
|
+
backgroundColor: palette.pills.active.bg,
|
|
3861
|
+
borderColor: palette.pills.active.border,
|
|
3862
|
+
borderRadius: theme.tokens.radius[size === "lg" ? "lg" : size === "sm" ? "sm" : "md"],
|
|
3863
|
+
borderWidth: 1,
|
|
3864
|
+
transform: [{ translateX }, { translateY }]
|
|
3865
|
+
},
|
|
3866
|
+
style
|
|
3867
|
+
];
|
|
3868
|
+
return [
|
|
3869
|
+
baseStyle,
|
|
3870
|
+
{
|
|
3871
|
+
top: 0,
|
|
3872
|
+
left: 0,
|
|
3873
|
+
width,
|
|
3874
|
+
height,
|
|
3875
|
+
backgroundColor: palette.segmented.active.bg,
|
|
3876
|
+
borderColor: palette.segmented.active.border,
|
|
3877
|
+
borderRadius: theme.tokens.radius.lg,
|
|
3878
|
+
borderWidth: 1,
|
|
3879
|
+
shadowColor: "#181521",
|
|
3880
|
+
shadowOffset: {
|
|
3881
|
+
width: 0,
|
|
3882
|
+
height: 1
|
|
3883
|
+
},
|
|
3884
|
+
shadowOpacity: .06,
|
|
3885
|
+
shadowRadius: 2,
|
|
3886
|
+
transform: [{ translateX }, { translateY }]
|
|
3887
|
+
},
|
|
3888
|
+
style
|
|
3889
|
+
];
|
|
3890
|
+
}, [
|
|
3891
|
+
height,
|
|
3892
|
+
isVertical,
|
|
3893
|
+
palette.indicator.bg,
|
|
3894
|
+
palette.pills.active.bg,
|
|
3895
|
+
palette.pills.active.border,
|
|
3896
|
+
palette.segmented.active.bg,
|
|
3897
|
+
palette.segmented.active.border,
|
|
3898
|
+
size,
|
|
3899
|
+
style,
|
|
3900
|
+
theme.tokens.radius,
|
|
3901
|
+
translateX,
|
|
3902
|
+
translateY,
|
|
3903
|
+
variant,
|
|
3904
|
+
visible,
|
|
3905
|
+
width
|
|
3906
|
+
]);
|
|
3907
|
+
return /* @__PURE__ */ jsx(Animated.View, {
|
|
3908
|
+
accessibilityElementsHidden: true,
|
|
3909
|
+
importantForAccessibility: "no-hide-descendants",
|
|
3910
|
+
pointerEvents: "none",
|
|
3911
|
+
style: indicatorStyle,
|
|
3912
|
+
children
|
|
3913
|
+
});
|
|
3914
|
+
};
|
|
3709
3915
|
TabsIndicator.displayName = "Tabs.Indicator";
|
|
3710
3916
|
//#endregion
|
|
3711
3917
|
//#region src/components/Tabs/List/TabsList.styles.ts
|
|
3712
3918
|
const createStyles$6 = (theme) => StyleSheet.create({
|
|
3713
3919
|
list: {
|
|
3920
|
+
position: "relative",
|
|
3714
3921
|
flexDirection: "row",
|
|
3715
3922
|
alignSelf: "stretch",
|
|
3716
3923
|
width: "100%",
|
|
@@ -3775,31 +3982,62 @@ const createStyles$5 = (theme) => StyleSheet.create({
|
|
|
3775
3982
|
justifyContent: "center",
|
|
3776
3983
|
paddingHorizontal: theme.tokens.spacing[4],
|
|
3777
3984
|
paddingVertical: theme.tokens.spacing[2],
|
|
3778
|
-
borderWidth: 1
|
|
3985
|
+
borderWidth: 1,
|
|
3986
|
+
zIndex: 1
|
|
3987
|
+
},
|
|
3988
|
+
tabIconOnly: {
|
|
3989
|
+
width: 44,
|
|
3990
|
+
minWidth: 44,
|
|
3991
|
+
paddingHorizontal: 0
|
|
3779
3992
|
},
|
|
3780
3993
|
tabSm: {
|
|
3781
3994
|
minHeight: 36,
|
|
3782
3995
|
paddingHorizontal: theme.tokens.spacing[3],
|
|
3783
3996
|
paddingVertical: 6
|
|
3784
3997
|
},
|
|
3998
|
+
tabIconOnlySm: {
|
|
3999
|
+
width: 36,
|
|
4000
|
+
minWidth: 36,
|
|
4001
|
+
paddingHorizontal: 0
|
|
4002
|
+
},
|
|
3785
4003
|
tabLg: {
|
|
3786
4004
|
minHeight: 52,
|
|
3787
4005
|
paddingHorizontal: theme.tokens.spacing[5],
|
|
3788
4006
|
paddingVertical: theme.tokens.spacing[3]
|
|
3789
4007
|
},
|
|
4008
|
+
tabIconOnlyLg: {
|
|
4009
|
+
width: 52,
|
|
4010
|
+
minWidth: 52,
|
|
4011
|
+
paddingHorizontal: 0
|
|
4012
|
+
},
|
|
3790
4013
|
tabSegmented: {
|
|
3791
4014
|
minHeight: 32,
|
|
3792
4015
|
paddingVertical: 5,
|
|
3793
4016
|
borderRadius: theme.tokens.radius.lg
|
|
3794
4017
|
},
|
|
4018
|
+
tabSegmentedIconOnly: {
|
|
4019
|
+
width: 32,
|
|
4020
|
+
minWidth: 32,
|
|
4021
|
+
paddingHorizontal: 0
|
|
4022
|
+
},
|
|
3795
4023
|
tabSegmentedSm: {
|
|
3796
4024
|
minHeight: 30,
|
|
3797
4025
|
paddingVertical: 4
|
|
3798
4026
|
},
|
|
4027
|
+
tabSegmentedIconOnlySm: {
|
|
4028
|
+
width: 30,
|
|
4029
|
+
minWidth: 30,
|
|
4030
|
+
paddingHorizontal: 0
|
|
4031
|
+
},
|
|
3799
4032
|
tabSegmentedLg: {
|
|
3800
4033
|
minHeight: 40,
|
|
3801
4034
|
paddingVertical: 8
|
|
3802
4035
|
},
|
|
4036
|
+
tabSegmentedIconOnlyLg: {
|
|
4037
|
+
width: 40,
|
|
4038
|
+
minWidth: 40,
|
|
4039
|
+
paddingHorizontal: 0
|
|
4040
|
+
},
|
|
3803
4041
|
tabVertical: {
|
|
3804
4042
|
position: "relative",
|
|
3805
4043
|
width: "100%",
|
|
@@ -3808,25 +4046,6 @@ const createStyles$5 = (theme) => StyleSheet.create({
|
|
|
3808
4046
|
flexShrink: 0,
|
|
3809
4047
|
justifyContent: "flex-start"
|
|
3810
4048
|
},
|
|
3811
|
-
horizontalIndicator: {
|
|
3812
|
-
position: "absolute",
|
|
3813
|
-
right: 0,
|
|
3814
|
-
bottom: 0,
|
|
3815
|
-
left: 0,
|
|
3816
|
-
height: 3,
|
|
3817
|
-
backgroundColor: "transparent"
|
|
3818
|
-
},
|
|
3819
|
-
horizontalIndicatorActive: { backgroundColor: "transparent" },
|
|
3820
|
-
verticalIndicator: {
|
|
3821
|
-
position: "absolute",
|
|
3822
|
-
top: 0,
|
|
3823
|
-
bottom: 0,
|
|
3824
|
-
left: 0,
|
|
3825
|
-
width: 3,
|
|
3826
|
-
backgroundColor: "transparent"
|
|
3827
|
-
},
|
|
3828
|
-
verticalIndicatorActive: { backgroundColor: "transparent" },
|
|
3829
|
-
verticalIndicatorPressed: { backgroundColor: "transparent" },
|
|
3830
4049
|
tabHovered: { backgroundColor: "transparent" },
|
|
3831
4050
|
tabPressed: { backgroundColor: "transparent" },
|
|
3832
4051
|
tabFocused: { borderColor: theme.semantic.focus.ring.color },
|
|
@@ -3860,6 +4079,11 @@ const createStyles$5 = (theme) => StyleSheet.create({
|
|
|
3860
4079
|
paddingVertical: theme.tokens.spacing[1],
|
|
3861
4080
|
borderRadius: theme.tokens.radius.md
|
|
3862
4081
|
},
|
|
4082
|
+
tabPillsIconOnly: {
|
|
4083
|
+
width: 36,
|
|
4084
|
+
minWidth: 36,
|
|
4085
|
+
paddingHorizontal: 0
|
|
4086
|
+
},
|
|
3863
4087
|
tabPillsActive: {
|
|
3864
4088
|
backgroundColor: "transparent",
|
|
3865
4089
|
borderRadius: theme.tokens.radius.md
|
|
@@ -3931,7 +4155,7 @@ TabsIcon.displayName = "Tabs.Icon";
|
|
|
3931
4155
|
const TabsTrigger = ({ value, children, icon, badge, description, disabled, style, textStyle }) => {
|
|
3932
4156
|
const { theme } = useTheme();
|
|
3933
4157
|
const styles = useThemeStyles(createStyles$5);
|
|
3934
|
-
const { value: selectedValue, variant, color, size, orientation, disabled: rootDisabled, setValue, registerTrigger } = useTabs();
|
|
4158
|
+
const { value: selectedValue, variant, color, size, orientation, disabled: rootDisabled, setValue, registerTrigger, registerTriggerLayout } = useTabs();
|
|
3935
4159
|
const isDisabled = rootDisabled || disabled;
|
|
3936
4160
|
const isActive = selectedValue === value;
|
|
3937
4161
|
const isPills = variant === "pills";
|
|
@@ -3940,6 +4164,7 @@ const TabsTrigger = ({ value, children, icon, badge, description, disabled, styl
|
|
|
3940
4164
|
const isVertical = orientation === "vertical";
|
|
3941
4165
|
const isSm = size === "sm";
|
|
3942
4166
|
const isLg = size === "lg";
|
|
4167
|
+
const isOnlyIcon = icon != null && children == null && badge == null;
|
|
3943
4168
|
const palette = theme.components.tabs[color];
|
|
3944
4169
|
const state = isDisabled ? theme.components.tabs.disabled : isPills ? isActive ? palette.pills.active : palette.pills.default : isActive ? palette.trigger.active : palette.trigger.default;
|
|
3945
4170
|
const pressedState = isDisabled ? state : isPills ? isActive ? palette.pills.active : palette.pills.hover : isActive ? palette.trigger.active : palette.trigger.hover;
|
|
@@ -3947,12 +4172,17 @@ const TabsTrigger = ({ value, children, icon, badge, description, disabled, styl
|
|
|
3947
4172
|
registerTrigger(value, Boolean(isDisabled), true);
|
|
3948
4173
|
return () => {
|
|
3949
4174
|
registerTrigger(value, Boolean(isDisabled), false);
|
|
4175
|
+
registerTriggerLayout(value, void 0);
|
|
3950
4176
|
};
|
|
3951
4177
|
}, [
|
|
3952
4178
|
isDisabled,
|
|
3953
4179
|
registerTrigger,
|
|
4180
|
+
registerTriggerLayout,
|
|
3954
4181
|
value
|
|
3955
4182
|
]);
|
|
4183
|
+
const handleLayout = (event) => {
|
|
4184
|
+
registerTriggerLayout(value, event.nativeEvent.layout);
|
|
4185
|
+
};
|
|
3956
4186
|
const iconColor = isPills && isActive ? palette.pills.active.fg : isActive ? palette.trigger.active.fg : state.fg;
|
|
3957
4187
|
const renderedIcon = isValidElement(icon) ? cloneElement(icon, { color: iconColor }) : icon;
|
|
3958
4188
|
return /* @__PURE__ */ jsx(Pressable, {
|
|
@@ -3965,43 +4195,39 @@ const TabsTrigger = ({ value, children, icon, badge, description, disabled, styl
|
|
|
3965
4195
|
onPress: () => {
|
|
3966
4196
|
if (!isDisabled && !isActive) setValue(value);
|
|
3967
4197
|
},
|
|
4198
|
+
onLayout: handleLayout,
|
|
3968
4199
|
style: ({ pressed }) => [
|
|
3969
4200
|
styles.tab,
|
|
3970
4201
|
isSm && styles.tabSm,
|
|
3971
4202
|
isLg && styles.tabLg,
|
|
4203
|
+
isOnlyIcon && styles.tabIconOnly,
|
|
4204
|
+
isOnlyIcon && isSm && styles.tabIconOnlySm,
|
|
4205
|
+
isOnlyIcon && isLg && styles.tabIconOnlyLg,
|
|
3972
4206
|
isVertical && styles.tabVertical,
|
|
3973
4207
|
isPills && styles.tabPills,
|
|
4208
|
+
isPills && isOnlyIcon && styles.tabPillsIconOnly,
|
|
3974
4209
|
isSegmented && styles.tabSegmented,
|
|
3975
4210
|
isSegmented && isSm && styles.tabSegmentedSm,
|
|
3976
4211
|
isSegmented && isLg && styles.tabSegmentedLg,
|
|
3977
|
-
|
|
3978
|
-
|
|
3979
|
-
|
|
3980
|
-
},
|
|
4212
|
+
isSegmented && isOnlyIcon && styles.tabSegmentedIconOnly,
|
|
4213
|
+
isSegmented && isOnlyIcon && isSm && styles.tabSegmentedIconOnlySm,
|
|
4214
|
+
isSegmented && isOnlyIcon && isLg && styles.tabSegmentedIconOnlyLg,
|
|
3981
4215
|
{
|
|
3982
|
-
borderColor: state.border,
|
|
4216
|
+
borderColor: isLine ? "transparent" : state.border,
|
|
3983
4217
|
backgroundColor: pressed ? pressedState.bg : state.bg
|
|
3984
4218
|
},
|
|
3985
4219
|
isSegmented && isActive && {
|
|
3986
4220
|
borderColor: palette.segmented.active.border,
|
|
3987
|
-
backgroundColor:
|
|
4221
|
+
backgroundColor: "transparent"
|
|
4222
|
+
},
|
|
4223
|
+
isPills && isActive && {
|
|
4224
|
+
borderColor: "transparent",
|
|
4225
|
+
backgroundColor: "transparent"
|
|
3988
4226
|
},
|
|
3989
4227
|
isDisabled && styles.tabDisabled,
|
|
3990
4228
|
style
|
|
3991
4229
|
],
|
|
3992
|
-
children: (
|
|
3993
|
-
isLine && !isVertical && /* @__PURE__ */ jsx(View, {
|
|
3994
|
-
pointerEvents: "none",
|
|
3995
|
-
style: [styles.horizontalIndicator, isActive && { backgroundColor: palette.indicator.bg }]
|
|
3996
|
-
}),
|
|
3997
|
-
isLine && isVertical && /* @__PURE__ */ jsx(View, {
|
|
3998
|
-
pointerEvents: "none",
|
|
3999
|
-
style: [
|
|
4000
|
-
styles.verticalIndicator,
|
|
4001
|
-
isActive && { backgroundColor: palette.indicator.bg },
|
|
4002
|
-
pressed && !isActive && !isDisabled && { backgroundColor: palette.indicator.hoverBg }
|
|
4003
|
-
]
|
|
4004
|
-
}),
|
|
4230
|
+
children: () => /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
4005
4231
|
icon != null && /* @__PURE__ */ jsx(View, {
|
|
4006
4232
|
style: styles.tabIcon,
|
|
4007
4233
|
children: renderedIcon
|
|
@@ -4066,7 +4292,9 @@ const TabsRoot = ({ children, value: controlledValue, defaultValue, onValueChang
|
|
|
4066
4292
|
const styles = useThemeStyles(createStyles$4);
|
|
4067
4293
|
const isControlled = controlledValue !== void 0;
|
|
4068
4294
|
const [version, setVersion] = useState(0);
|
|
4295
|
+
const [indicatorVersion, setIndicatorVersion] = useState(0);
|
|
4069
4296
|
const triggersRef = useRef([]);
|
|
4297
|
+
const triggerLayoutsRef = useRef(/* @__PURE__ */ new Map());
|
|
4070
4298
|
const { value, setValue } = useTabs$1({
|
|
4071
4299
|
value: controlledValue,
|
|
4072
4300
|
defaultValue,
|
|
@@ -4089,6 +4317,14 @@ const TabsRoot = ({ children, value: controlledValue, defaultValue, onValueChang
|
|
|
4089
4317
|
else triggersRef.current.push(nextTab);
|
|
4090
4318
|
setVersion((current) => current + 1);
|
|
4091
4319
|
}, []);
|
|
4320
|
+
const registerTriggerLayout = useCallback((triggerValue, layout) => {
|
|
4321
|
+
if (!layout) triggerLayoutsRef.current.delete(triggerValue);
|
|
4322
|
+
else triggerLayoutsRef.current.set(triggerValue, layout);
|
|
4323
|
+
setIndicatorVersion((current) => current + 1);
|
|
4324
|
+
}, []);
|
|
4325
|
+
const getTriggerLayout = useCallback((triggerValue) => {
|
|
4326
|
+
return triggerLayoutsRef.current.get(triggerValue);
|
|
4327
|
+
}, []);
|
|
4092
4328
|
useEffect(() => {
|
|
4093
4329
|
const enabledTabs = triggersRef.current.filter((tab) => !tab.disabled);
|
|
4094
4330
|
const selectedExists = triggersRef.current.some((tab) => tab.value === value);
|
|
@@ -4118,7 +4354,10 @@ const TabsRoot = ({ children, value: controlledValue, defaultValue, onValueChang
|
|
|
4118
4354
|
keepMounted,
|
|
4119
4355
|
lazyMount,
|
|
4120
4356
|
disabled,
|
|
4121
|
-
registerTrigger
|
|
4357
|
+
registerTrigger,
|
|
4358
|
+
indicatorVersion,
|
|
4359
|
+
getTriggerLayout,
|
|
4360
|
+
registerTriggerLayout
|
|
4122
4361
|
}), [
|
|
4123
4362
|
activationMode,
|
|
4124
4363
|
color,
|
|
@@ -4126,6 +4365,9 @@ const TabsRoot = ({ children, value: controlledValue, defaultValue, onValueChang
|
|
|
4126
4365
|
keepMounted,
|
|
4127
4366
|
lazyMount,
|
|
4128
4367
|
orientation,
|
|
4368
|
+
getTriggerLayout,
|
|
4369
|
+
indicatorVersion,
|
|
4370
|
+
registerTriggerLayout,
|
|
4129
4371
|
registerTrigger,
|
|
4130
4372
|
setValue,
|
|
4131
4373
|
size,
|
|
@@ -4332,11 +4574,11 @@ const TooltipRoot = ({ children, open: openProp, defaultOpen = false, onOpenChan
|
|
|
4332
4574
|
setOpen,
|
|
4333
4575
|
updatePosition
|
|
4334
4576
|
]);
|
|
4335
|
-
const dismiss =
|
|
4577
|
+
const dismiss = useOverlayDismiss({
|
|
4336
4578
|
id: contentId,
|
|
4337
|
-
|
|
4579
|
+
active: open && !disabled,
|
|
4338
4580
|
closeOnOutsidePress,
|
|
4339
|
-
|
|
4581
|
+
requestClose: hide
|
|
4340
4582
|
});
|
|
4341
4583
|
useEffect(() => {
|
|
4342
4584
|
if (disabled && open) hide();
|