@mrmeg/expo-ui 0.1.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 +96 -0
- package/dist/components/Accordion.d.ts +54 -0
- package/dist/components/Accordion.js +149 -0
- package/dist/components/Alert.d.ts +30 -0
- package/dist/components/Alert.js +25 -0
- package/dist/components/AnimatedView.d.ts +55 -0
- package/dist/components/AnimatedView.js +39 -0
- package/dist/components/Badge.d.ts +23 -0
- package/dist/components/Badge.js +74 -0
- package/dist/components/BottomSheet.d.ts +74 -0
- package/dist/components/BottomSheet.js +513 -0
- package/dist/components/Button.d.ts +129 -0
- package/dist/components/Button.js +216 -0
- package/dist/components/Card.d.ts +42 -0
- package/dist/components/Card.js +126 -0
- package/dist/components/Checkbox.d.ts +39 -0
- package/dist/components/Checkbox.js +96 -0
- package/dist/components/Collapsible.d.ts +67 -0
- package/dist/components/Collapsible.js +38 -0
- package/dist/components/Dialog.d.ts +140 -0
- package/dist/components/Dialog.js +167 -0
- package/dist/components/DismissKeyboard.d.ts +15 -0
- package/dist/components/DismissKeyboard.js +13 -0
- package/dist/components/Drawer.d.ts +74 -0
- package/dist/components/Drawer.js +423 -0
- package/dist/components/DropdownMenu.d.ts +120 -0
- package/dist/components/DropdownMenu.js +211 -0
- package/dist/components/EmptyState.d.ts +42 -0
- package/dist/components/EmptyState.js +58 -0
- package/dist/components/ErrorBoundary.d.ts +53 -0
- package/dist/components/ErrorBoundary.js +75 -0
- package/dist/components/Icon.d.ts +46 -0
- package/dist/components/Icon.js +40 -0
- package/dist/components/InputOTP.d.ts +72 -0
- package/dist/components/InputOTP.js +155 -0
- package/dist/components/Label.d.ts +61 -0
- package/dist/components/Label.js +72 -0
- package/dist/components/MaxWidthContainer.d.ts +58 -0
- package/dist/components/MaxWidthContainer.js +64 -0
- package/dist/components/Notification.d.ts +26 -0
- package/dist/components/Notification.js +230 -0
- package/dist/components/Popover.d.ts +79 -0
- package/dist/components/Popover.js +91 -0
- package/dist/components/Progress.d.ts +28 -0
- package/dist/components/Progress.js +107 -0
- package/dist/components/RadioGroup.d.ts +65 -0
- package/dist/components/RadioGroup.js +142 -0
- package/dist/components/Select.d.ts +88 -0
- package/dist/components/Select.js +172 -0
- package/dist/components/Separator.d.ts +83 -0
- package/dist/components/Separator.js +85 -0
- package/dist/components/Skeleton.d.ts +68 -0
- package/dist/components/Skeleton.js +99 -0
- package/dist/components/Slider.d.ts +24 -0
- package/dist/components/Slider.js +162 -0
- package/dist/components/StatusBar.d.ts +1 -0
- package/dist/components/StatusBar.js +19 -0
- package/dist/components/StyledText.d.ts +161 -0
- package/dist/components/StyledText.js +193 -0
- package/dist/components/Switch.d.ts +44 -0
- package/dist/components/Switch.js +129 -0
- package/dist/components/Tabs.d.ts +31 -0
- package/dist/components/Tabs.js +127 -0
- package/dist/components/TextInput.d.ts +120 -0
- package/dist/components/TextInput.js +263 -0
- package/dist/components/Toggle.d.ts +106 -0
- package/dist/components/Toggle.js +150 -0
- package/dist/components/ToggleGroup.d.ts +80 -0
- package/dist/components/ToggleGroup.js +189 -0
- package/dist/components/Tooltip.d.ts +121 -0
- package/dist/components/Tooltip.js +132 -0
- package/dist/components/index.d.ts +35 -0
- package/dist/components/index.js +35 -0
- package/dist/constants/colors.d.ts +82 -0
- package/dist/constants/colors.js +116 -0
- package/dist/constants/fonts.d.ts +32 -0
- package/dist/constants/fonts.js +91 -0
- package/dist/constants/index.d.ts +3 -0
- package/dist/constants/index.js +3 -0
- package/dist/constants/spacing.d.ts +40 -0
- package/dist/constants/spacing.js +48 -0
- package/dist/hooks/index.d.ts +6 -0
- package/dist/hooks/index.js +6 -0
- package/dist/hooks/useDimensions.d.ts +19 -0
- package/dist/hooks/useDimensions.js +55 -0
- package/dist/hooks/useReduceMotion.d.ts +5 -0
- package/dist/hooks/useReduceMotion.js +64 -0
- package/dist/hooks/useResources.d.ts +12 -0
- package/dist/hooks/useResources.js +56 -0
- package/dist/hooks/useScalePress.d.ts +57 -0
- package/dist/hooks/useScalePress.js +55 -0
- package/dist/hooks/useStaggeredEntrance.d.ts +67 -0
- package/dist/hooks/useStaggeredEntrance.js +74 -0
- package/dist/hooks/useTheme.d.ts +88 -0
- package/dist/hooks/useTheme.js +328 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.js +5 -0
- package/dist/lib/animations.d.ts +1 -0
- package/dist/lib/animations.js +3 -0
- package/dist/lib/haptics.d.ts +3 -0
- package/dist/lib/haptics.js +29 -0
- package/dist/lib/index.d.ts +3 -0
- package/dist/lib/index.js +3 -0
- package/dist/lib/sentry.d.ts +16 -0
- package/dist/lib/sentry.js +55 -0
- package/dist/state/globalUIStore.d.ts +30 -0
- package/dist/state/globalUIStore.js +8 -0
- package/dist/state/index.d.ts +2 -0
- package/dist/state/index.js +2 -0
- package/dist/state/themeStore.d.ts +6 -0
- package/dist/state/themeStore.js +38 -0
- package/package.json +92 -0
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import * as TogglePrimitive from "@rn-primitives/toggle";
|
|
2
|
+
import { ViewStyle, StyleProp } from "react-native";
|
|
3
|
+
import type { IconName } from "./Icon";
|
|
4
|
+
export type ToggleVariant = "default" | "outline";
|
|
5
|
+
export type ToggleSize = "sm" | "default" | "lg";
|
|
6
|
+
export type ToggleShape = "default" | "square" | "circle";
|
|
7
|
+
interface ToggleProps extends Omit<TogglePrimitive.RootProps, "style"> {
|
|
8
|
+
/**
|
|
9
|
+
* Visual style variant
|
|
10
|
+
* - default: transparent background with subtle border
|
|
11
|
+
* - outline: primary border with transparent background
|
|
12
|
+
* @default "default"
|
|
13
|
+
*/
|
|
14
|
+
variant?: ToggleVariant;
|
|
15
|
+
/**
|
|
16
|
+
* Size of the toggle button
|
|
17
|
+
* - sm: 32px height
|
|
18
|
+
* - default: 40px height
|
|
19
|
+
* - lg: 48px height
|
|
20
|
+
* @default "default"
|
|
21
|
+
*/
|
|
22
|
+
size?: ToggleSize;
|
|
23
|
+
/**
|
|
24
|
+
* Shape of the toggle button
|
|
25
|
+
* - default: rounded corners (radiusMd)
|
|
26
|
+
* - square: sharp corners (0)
|
|
27
|
+
* - circle: fully rounded (radiusFull)
|
|
28
|
+
* @default "default"
|
|
29
|
+
*/
|
|
30
|
+
shape?: ToggleShape;
|
|
31
|
+
/**
|
|
32
|
+
* Whether the toggle is in a loading state
|
|
33
|
+
* Shows spinner and disables interaction
|
|
34
|
+
*/
|
|
35
|
+
loading?: boolean;
|
|
36
|
+
/**
|
|
37
|
+
* Whether the toggle is icon-only (equal padding)
|
|
38
|
+
* Optimizes padding for icon buttons
|
|
39
|
+
*/
|
|
40
|
+
iconOnly?: boolean;
|
|
41
|
+
/**
|
|
42
|
+
* Custom style override (uses StyleSheet.flatten for web compatibility)
|
|
43
|
+
*/
|
|
44
|
+
style?: StyleProp<ViewStyle>;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Enhanced Toggle Component
|
|
48
|
+
*
|
|
49
|
+
* Features:
|
|
50
|
+
* - 2 variants (default, outline)
|
|
51
|
+
* - 3 sizes (sm, default, lg)
|
|
52
|
+
* - 3 shapes (default, square, circle)
|
|
53
|
+
* - Loading state with spinner
|
|
54
|
+
* - Icon-only optimization
|
|
55
|
+
* - Style prop support
|
|
56
|
+
* - Full accessibility
|
|
57
|
+
*
|
|
58
|
+
* Usage:
|
|
59
|
+
* ```tsx
|
|
60
|
+
* // Basic
|
|
61
|
+
* const [pressed, setPressed] = useState(false);
|
|
62
|
+
* <Toggle pressed={pressed} onPressedChange={setPressed}>
|
|
63
|
+
* <SansSerifText>Toggle Me</SansSerifText>
|
|
64
|
+
* </Toggle>
|
|
65
|
+
*
|
|
66
|
+
* // With icon
|
|
67
|
+
* <Toggle pressed={pressed} onPressedChange={setPressed} iconOnly>
|
|
68
|
+
* <ToggleIcon name="bold" />
|
|
69
|
+
* </Toggle>
|
|
70
|
+
*
|
|
71
|
+
* // Different shapes
|
|
72
|
+
* <Toggle shape="square" pressed={pressed} onPressedChange={setPressed}>
|
|
73
|
+
* <SansSerifText>Square</SansSerifText>
|
|
74
|
+
* </Toggle>
|
|
75
|
+
*
|
|
76
|
+
* <Toggle shape="circle" iconOnly pressed={pressed} onPressedChange={setPressed}>
|
|
77
|
+
* <ToggleIcon name="bold" />
|
|
78
|
+
* </Toggle>
|
|
79
|
+
*
|
|
80
|
+
* // Loading state
|
|
81
|
+
* <Toggle loading pressed={pressed} onPressedChange={setPressed}>
|
|
82
|
+
* <SansSerifText>Loading...</SansSerifText>
|
|
83
|
+
* </Toggle>
|
|
84
|
+
* ```
|
|
85
|
+
*/
|
|
86
|
+
declare function Toggle({ variant, size, shape, loading, iconOnly, style: styleOverride, ...props }: ToggleProps): import("react/jsx-runtime").JSX.Element;
|
|
87
|
+
/**
|
|
88
|
+
* ToggleIcon Component
|
|
89
|
+
* Icon wrapper for use inside Toggle buttons
|
|
90
|
+
* Automatically inherits sizing from parent Toggle
|
|
91
|
+
*
|
|
92
|
+
* Usage:
|
|
93
|
+
* ```tsx
|
|
94
|
+
* <Toggle pressed={pressed} onPressedChange={setPressed}>
|
|
95
|
+
* <ToggleIcon name="bold" />
|
|
96
|
+
* </Toggle>
|
|
97
|
+
* ```
|
|
98
|
+
*/
|
|
99
|
+
interface ToggleIconProps {
|
|
100
|
+
name: IconName;
|
|
101
|
+
size?: number;
|
|
102
|
+
color?: string;
|
|
103
|
+
}
|
|
104
|
+
declare function ToggleIcon({ name, size, color }: ToggleIconProps): import("react/jsx-runtime").JSX.Element;
|
|
105
|
+
export { Toggle, ToggleIcon };
|
|
106
|
+
export type { ToggleProps };
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import React from "react";
|
|
3
|
+
import { Icon } from "./Icon";
|
|
4
|
+
import { TextClassContext, TextColorContext } from "./StyledText";
|
|
5
|
+
import { useTheme } from "../hooks/useTheme";
|
|
6
|
+
import { spacing } from "../constants/spacing";
|
|
7
|
+
import * as TogglePrimitive from "@rn-primitives/toggle";
|
|
8
|
+
import { Platform, StyleSheet, ActivityIndicator } from "react-native";
|
|
9
|
+
import { palette } from "../constants/colors";
|
|
10
|
+
const DEFAULT_HIT_SLOP = 8;
|
|
11
|
+
// Size configurations
|
|
12
|
+
const TOGGLE_SIZES = {
|
|
13
|
+
sm: {
|
|
14
|
+
height: 32,
|
|
15
|
+
minWidth: 32,
|
|
16
|
+
paddingHorizontal: spacing.sm,
|
|
17
|
+
fontSize: 12,
|
|
18
|
+
iconSize: spacing.iconSm,
|
|
19
|
+
},
|
|
20
|
+
default: {
|
|
21
|
+
height: 36,
|
|
22
|
+
minWidth: 36,
|
|
23
|
+
paddingHorizontal: spacing.md,
|
|
24
|
+
fontSize: 13,
|
|
25
|
+
iconSize: spacing.iconMd,
|
|
26
|
+
},
|
|
27
|
+
lg: {
|
|
28
|
+
height: 40,
|
|
29
|
+
minWidth: 40,
|
|
30
|
+
paddingHorizontal: spacing.lg,
|
|
31
|
+
fontSize: 14,
|
|
32
|
+
iconSize: spacing.iconMd,
|
|
33
|
+
},
|
|
34
|
+
};
|
|
35
|
+
/**
|
|
36
|
+
* Enhanced Toggle Component
|
|
37
|
+
*
|
|
38
|
+
* Features:
|
|
39
|
+
* - 2 variants (default, outline)
|
|
40
|
+
* - 3 sizes (sm, default, lg)
|
|
41
|
+
* - 3 shapes (default, square, circle)
|
|
42
|
+
* - Loading state with spinner
|
|
43
|
+
* - Icon-only optimization
|
|
44
|
+
* - Style prop support
|
|
45
|
+
* - Full accessibility
|
|
46
|
+
*
|
|
47
|
+
* Usage:
|
|
48
|
+
* ```tsx
|
|
49
|
+
* // Basic
|
|
50
|
+
* const [pressed, setPressed] = useState(false);
|
|
51
|
+
* <Toggle pressed={pressed} onPressedChange={setPressed}>
|
|
52
|
+
* <SansSerifText>Toggle Me</SansSerifText>
|
|
53
|
+
* </Toggle>
|
|
54
|
+
*
|
|
55
|
+
* // With icon
|
|
56
|
+
* <Toggle pressed={pressed} onPressedChange={setPressed} iconOnly>
|
|
57
|
+
* <ToggleIcon name="bold" />
|
|
58
|
+
* </Toggle>
|
|
59
|
+
*
|
|
60
|
+
* // Different shapes
|
|
61
|
+
* <Toggle shape="square" pressed={pressed} onPressedChange={setPressed}>
|
|
62
|
+
* <SansSerifText>Square</SansSerifText>
|
|
63
|
+
* </Toggle>
|
|
64
|
+
*
|
|
65
|
+
* <Toggle shape="circle" iconOnly pressed={pressed} onPressedChange={setPressed}>
|
|
66
|
+
* <ToggleIcon name="bold" />
|
|
67
|
+
* </Toggle>
|
|
68
|
+
*
|
|
69
|
+
* // Loading state
|
|
70
|
+
* <Toggle loading pressed={pressed} onPressedChange={setPressed}>
|
|
71
|
+
* <SansSerifText>Loading...</SansSerifText>
|
|
72
|
+
* </Toggle>
|
|
73
|
+
* ```
|
|
74
|
+
*/
|
|
75
|
+
function Toggle({ variant = "default", size = "default", shape = "default", loading = false, iconOnly = false, style: styleOverride, ...props }) {
|
|
76
|
+
const { theme, getContrastingColor, withAlpha } = useTheme();
|
|
77
|
+
const sizeConfig = TOGGLE_SIZES[size];
|
|
78
|
+
// Calculate text color based on state and variant
|
|
79
|
+
const getTextColor = () => {
|
|
80
|
+
if (props.pressed) {
|
|
81
|
+
if (variant === "outline") {
|
|
82
|
+
// When pressed with outline variant, background is primary
|
|
83
|
+
return getContrastingColor(theme.colors.primary, palette.white, palette.black);
|
|
84
|
+
}
|
|
85
|
+
// When pressed with default variant, use primary color
|
|
86
|
+
return theme.colors.primary;
|
|
87
|
+
}
|
|
88
|
+
// When not pressed, use base content or primary for outline
|
|
89
|
+
return variant === "outline" ? theme.colors.primary : theme.colors.text;
|
|
90
|
+
};
|
|
91
|
+
const textColor = getTextColor();
|
|
92
|
+
// Determine border radius based on shape
|
|
93
|
+
const getBorderRadius = () => {
|
|
94
|
+
if (shape === "square")
|
|
95
|
+
return 0;
|
|
96
|
+
if (shape === "circle")
|
|
97
|
+
return spacing.radiusFull;
|
|
98
|
+
return spacing.radiusMd;
|
|
99
|
+
};
|
|
100
|
+
// Flatten style override for web compatibility
|
|
101
|
+
const flattenedStyle = styleOverride ? StyleSheet.flatten(styleOverride) : undefined;
|
|
102
|
+
const isDisabled = props.disabled || loading;
|
|
103
|
+
return (_jsx(TextColorContext.Provider, { value: textColor, children: _jsx(TextClassContext.Provider, { value: "", children: _jsx(TogglePrimitive.Root, { ...props, disabled: isDisabled, style: {
|
|
104
|
+
flexDirection: "row",
|
|
105
|
+
alignItems: "center",
|
|
106
|
+
justifyContent: "center",
|
|
107
|
+
gap: spacing.sm,
|
|
108
|
+
height: sizeConfig.height,
|
|
109
|
+
minWidth: sizeConfig.minWidth,
|
|
110
|
+
paddingHorizontal: iconOnly ? sizeConfig.height / 2 - sizeConfig.iconSize / 2 : sizeConfig.paddingHorizontal,
|
|
111
|
+
borderRadius: getBorderRadius(),
|
|
112
|
+
borderWidth: 1,
|
|
113
|
+
// Base variant styles
|
|
114
|
+
...(variant === "default" && !props.pressed && {
|
|
115
|
+
backgroundColor: "transparent",
|
|
116
|
+
borderColor: theme.colors.border,
|
|
117
|
+
}),
|
|
118
|
+
...(variant === "default" && props.pressed && {
|
|
119
|
+
backgroundColor: withAlpha(theme.colors.primary, 0.1),
|
|
120
|
+
borderColor: theme.colors.primary,
|
|
121
|
+
}),
|
|
122
|
+
// Outline variant styles
|
|
123
|
+
...(variant === "outline" && !props.pressed && {
|
|
124
|
+
backgroundColor: "transparent",
|
|
125
|
+
borderColor: theme.colors.primary,
|
|
126
|
+
}),
|
|
127
|
+
...(variant === "outline" && props.pressed && {
|
|
128
|
+
backgroundColor: theme.colors.primary,
|
|
129
|
+
borderColor: theme.colors.primary,
|
|
130
|
+
}),
|
|
131
|
+
// Disabled state
|
|
132
|
+
opacity: isDisabled ? 0.5 : 1,
|
|
133
|
+
// Web-specific styles
|
|
134
|
+
...(Platform.OS === "web" && {
|
|
135
|
+
cursor: isDisabled ? "not-allowed" : "pointer",
|
|
136
|
+
transition: "all 150ms",
|
|
137
|
+
}),
|
|
138
|
+
// Apply custom style override
|
|
139
|
+
...(flattenedStyle || {}),
|
|
140
|
+
}, hitSlop: DEFAULT_HIT_SLOP, accessibilityRole: "button", accessibilityState: {
|
|
141
|
+
selected: props.pressed,
|
|
142
|
+
disabled: !!isDisabled,
|
|
143
|
+
busy: loading,
|
|
144
|
+
}, children: loading ? (_jsx(ActivityIndicator, { size: "small", color: textColor })) : (props.children) }) }) }));
|
|
145
|
+
}
|
|
146
|
+
function ToggleIcon({ name, size, color }) {
|
|
147
|
+
const contextColor = React.useContext(TextColorContext);
|
|
148
|
+
return _jsx(Icon, { name: name, size: size || spacing.iconMd, color: color || contextColor });
|
|
149
|
+
}
|
|
150
|
+
export { Toggle, ToggleIcon };
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import type { IconName } from "./Icon";
|
|
2
|
+
import * as ToggleGroupPrimitive from "@rn-primitives/toggle-group";
|
|
3
|
+
type ToggleGroupVariant = "default" | "outline";
|
|
4
|
+
type ToggleGroupSize = "sm" | "default" | "lg";
|
|
5
|
+
type ToggleGroupProps = ToggleGroupPrimitive.RootProps & {
|
|
6
|
+
/**
|
|
7
|
+
* Visual style variant
|
|
8
|
+
* - default: transparent background with subtle border
|
|
9
|
+
* - outline: primary border with grouped appearance
|
|
10
|
+
*/
|
|
11
|
+
variant?: ToggleGroupVariant;
|
|
12
|
+
/**
|
|
13
|
+
* Size of the toggle buttons
|
|
14
|
+
* - sm: 32px height
|
|
15
|
+
* - default: 40px height
|
|
16
|
+
* - lg: 48px height
|
|
17
|
+
*/
|
|
18
|
+
size?: ToggleGroupSize;
|
|
19
|
+
};
|
|
20
|
+
/**
|
|
21
|
+
* ToggleGroup Component
|
|
22
|
+
* A group of toggle buttons for single or multiple selection
|
|
23
|
+
* Using @rn-primitives/toggle-group with DaisyUI theme integration
|
|
24
|
+
*
|
|
25
|
+
* Usage (Single Selection):
|
|
26
|
+
* ```tsx
|
|
27
|
+
* const [alignment, setAlignment] = useState('left');
|
|
28
|
+
* <ToggleGroup type="single" value={alignment} onValueChange={setAlignment}>
|
|
29
|
+
* <ToggleGroupItem value="left">Left</ToggleGroupItem>
|
|
30
|
+
* <ToggleGroupItem value="center">Center</ToggleGroupItem>
|
|
31
|
+
* <ToggleGroupItem value="right">Right</ToggleGroupItem>
|
|
32
|
+
* </ToggleGroup>
|
|
33
|
+
* ```
|
|
34
|
+
*
|
|
35
|
+
* Usage (Multiple Selection):
|
|
36
|
+
* ```tsx
|
|
37
|
+
* const [formats, setFormats] = useState(['bold']);
|
|
38
|
+
* <ToggleGroup type="multiple" value={formats} onValueChange={setFormats}>
|
|
39
|
+
* <ToggleGroupItem value="bold">Bold</ToggleGroupItem>
|
|
40
|
+
* <ToggleGroupItem value="italic">Italic</ToggleGroupItem>
|
|
41
|
+
* </ToggleGroup>
|
|
42
|
+
* ```
|
|
43
|
+
*/
|
|
44
|
+
declare function ToggleGroup({ variant, size, children, ...props }: ToggleGroupProps): import("react/jsx-runtime").JSX.Element;
|
|
45
|
+
type ToggleGroupItemProps = ToggleGroupPrimitive.ItemProps & {
|
|
46
|
+
/**
|
|
47
|
+
* Automatically set by ToggleGroup parent - don't set manually
|
|
48
|
+
*/
|
|
49
|
+
isFirst?: boolean;
|
|
50
|
+
/**
|
|
51
|
+
* Automatically set by ToggleGroup parent - don't set manually
|
|
52
|
+
*/
|
|
53
|
+
isLast?: boolean;
|
|
54
|
+
};
|
|
55
|
+
/**
|
|
56
|
+
* ToggleGroupItem Component
|
|
57
|
+
* Individual toggle button within a ToggleGroup
|
|
58
|
+
* Position (first/last) is automatically detected for rounded corners
|
|
59
|
+
*/
|
|
60
|
+
declare function ToggleGroupItem({ isFirst, isLast, children, ...props }: ToggleGroupItemProps): import("react/jsx-runtime").JSX.Element;
|
|
61
|
+
/**
|
|
62
|
+
* ToggleGroupIcon Component
|
|
63
|
+
* Icon wrapper for use inside ToggleGroup items
|
|
64
|
+
* Automatically inherits sizing from parent ToggleGroup
|
|
65
|
+
*
|
|
66
|
+
* Usage:
|
|
67
|
+
* ```tsx
|
|
68
|
+
* <ToggleGroupItem value="bold">
|
|
69
|
+
* <ToggleGroupIcon name="bold" />
|
|
70
|
+
* </ToggleGroupItem>
|
|
71
|
+
* ```
|
|
72
|
+
*/
|
|
73
|
+
interface ToggleGroupIconProps {
|
|
74
|
+
name: IconName;
|
|
75
|
+
size?: number;
|
|
76
|
+
color?: string;
|
|
77
|
+
}
|
|
78
|
+
declare function ToggleGroupIcon({ name, size, color }: ToggleGroupIconProps): import("react/jsx-runtime").JSX.Element;
|
|
79
|
+
export { ToggleGroup, ToggleGroupIcon, ToggleGroupItem };
|
|
80
|
+
export type { ToggleGroupProps, ToggleGroupSize, ToggleGroupVariant };
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { Icon } from "./Icon";
|
|
3
|
+
import { TextClassContext, TextColorContext } from "./StyledText";
|
|
4
|
+
import { spacing } from "../constants/spacing";
|
|
5
|
+
import { useTheme } from "../hooks/useTheme";
|
|
6
|
+
import * as ToggleGroupPrimitive from "@rn-primitives/toggle-group";
|
|
7
|
+
import * as React from "react";
|
|
8
|
+
import { Platform } from "react-native";
|
|
9
|
+
const DEFAULT_HIT_SLOP = 8;
|
|
10
|
+
// Size configurations (same as Toggle)
|
|
11
|
+
const TOGGLE_GROUP_SIZES = {
|
|
12
|
+
sm: {
|
|
13
|
+
height: 32,
|
|
14
|
+
minWidth: 32,
|
|
15
|
+
paddingHorizontal: spacing.sm,
|
|
16
|
+
fontSize: 12,
|
|
17
|
+
iconSize: spacing.iconSm,
|
|
18
|
+
},
|
|
19
|
+
default: {
|
|
20
|
+
height: 36,
|
|
21
|
+
minWidth: 36,
|
|
22
|
+
paddingHorizontal: spacing.md,
|
|
23
|
+
fontSize: 13,
|
|
24
|
+
iconSize: spacing.iconMd,
|
|
25
|
+
},
|
|
26
|
+
lg: {
|
|
27
|
+
height: 40,
|
|
28
|
+
minWidth: 40,
|
|
29
|
+
paddingHorizontal: spacing.lg,
|
|
30
|
+
fontSize: 14,
|
|
31
|
+
iconSize: spacing.iconMd,
|
|
32
|
+
},
|
|
33
|
+
};
|
|
34
|
+
const ToggleGroupContext = React.createContext(null);
|
|
35
|
+
function useToggleGroupContext() {
|
|
36
|
+
const context = React.useContext(ToggleGroupContext);
|
|
37
|
+
if (context === null) {
|
|
38
|
+
throw new Error("ToggleGroup compound components cannot be rendered outside the ToggleGroup component");
|
|
39
|
+
}
|
|
40
|
+
return context;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* ToggleGroup Component
|
|
44
|
+
* A group of toggle buttons for single or multiple selection
|
|
45
|
+
* Using @rn-primitives/toggle-group with DaisyUI theme integration
|
|
46
|
+
*
|
|
47
|
+
* Usage (Single Selection):
|
|
48
|
+
* ```tsx
|
|
49
|
+
* const [alignment, setAlignment] = useState('left');
|
|
50
|
+
* <ToggleGroup type="single" value={alignment} onValueChange={setAlignment}>
|
|
51
|
+
* <ToggleGroupItem value="left">Left</ToggleGroupItem>
|
|
52
|
+
* <ToggleGroupItem value="center">Center</ToggleGroupItem>
|
|
53
|
+
* <ToggleGroupItem value="right">Right</ToggleGroupItem>
|
|
54
|
+
* </ToggleGroup>
|
|
55
|
+
* ```
|
|
56
|
+
*
|
|
57
|
+
* Usage (Multiple Selection):
|
|
58
|
+
* ```tsx
|
|
59
|
+
* const [formats, setFormats] = useState(['bold']);
|
|
60
|
+
* <ToggleGroup type="multiple" value={formats} onValueChange={setFormats}>
|
|
61
|
+
* <ToggleGroupItem value="bold">Bold</ToggleGroupItem>
|
|
62
|
+
* <ToggleGroupItem value="italic">Italic</ToggleGroupItem>
|
|
63
|
+
* </ToggleGroup>
|
|
64
|
+
* ```
|
|
65
|
+
*/
|
|
66
|
+
function ToggleGroup({ variant = "default", size = "default", children, ...props }) {
|
|
67
|
+
const { theme } = useTheme();
|
|
68
|
+
// Count valid children for first/last detection
|
|
69
|
+
const childrenArray = React.Children.toArray(children);
|
|
70
|
+
const validChildren = childrenArray.filter((child) => React.isValidElement(child) && child.type === ToggleGroupItem);
|
|
71
|
+
const childCount = validChildren.length;
|
|
72
|
+
// Clone children with position props
|
|
73
|
+
let itemIndex = 0;
|
|
74
|
+
const enhancedChildren = React.Children.map(children, (child) => {
|
|
75
|
+
if (React.isValidElement(child) && child.type === ToggleGroupItem) {
|
|
76
|
+
const isFirst = itemIndex === 0;
|
|
77
|
+
const isLast = itemIndex === childCount - 1;
|
|
78
|
+
itemIndex++;
|
|
79
|
+
return React.cloneElement(child, {
|
|
80
|
+
isFirst,
|
|
81
|
+
isLast,
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
return child;
|
|
85
|
+
});
|
|
86
|
+
return (_jsx(ToggleGroupPrimitive.Root, { ...props, style: {
|
|
87
|
+
flexDirection: "row",
|
|
88
|
+
alignItems: "center",
|
|
89
|
+
borderRadius: spacing.radiusMd,
|
|
90
|
+
// No shadow on Android - causes text background artifact
|
|
91
|
+
...(variant === "outline" && Platform.OS === "ios" && {
|
|
92
|
+
shadowColor: theme.colors.overlay,
|
|
93
|
+
shadowOffset: { width: 0, height: 1 },
|
|
94
|
+
shadowOpacity: 0.05,
|
|
95
|
+
shadowRadius: 2,
|
|
96
|
+
}),
|
|
97
|
+
...(Platform.OS === "web" && {
|
|
98
|
+
width: "fit-content",
|
|
99
|
+
}),
|
|
100
|
+
}, children: _jsx(ToggleGroupContext.Provider, { value: { variant, size }, children: enhancedChildren }) }));
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* ToggleGroupItem Component
|
|
104
|
+
* Individual toggle button within a ToggleGroup
|
|
105
|
+
* Position (first/last) is automatically detected for rounded corners
|
|
106
|
+
*/
|
|
107
|
+
function ToggleGroupItem({ isFirst = false, isLast = false, children, ...props }) {
|
|
108
|
+
const { theme, withAlpha, getContrastingColor } = useTheme();
|
|
109
|
+
const context = useToggleGroupContext();
|
|
110
|
+
const { value: groupValue } = ToggleGroupPrimitive.useRootContext();
|
|
111
|
+
const sizeConfig = TOGGLE_GROUP_SIZES[context.size];
|
|
112
|
+
// Check if this item is selected
|
|
113
|
+
const isSelected = ToggleGroupPrimitive.utils.getIsSelected(groupValue, props.value);
|
|
114
|
+
// Determine the actual background color for this item
|
|
115
|
+
const itemBgColor = (() => {
|
|
116
|
+
if (context.variant === "outline" && isSelected)
|
|
117
|
+
return theme.colors.primary;
|
|
118
|
+
if (context.variant === "default" && isSelected)
|
|
119
|
+
return theme.colors.background;
|
|
120
|
+
return theme.colors.background;
|
|
121
|
+
})();
|
|
122
|
+
// Calculate text color with contrast against the actual background
|
|
123
|
+
const textColor = isSelected
|
|
124
|
+
? getContrastingColor(itemBgColor, theme.colors.foreground, theme.colors.background)
|
|
125
|
+
: theme.colors.foreground;
|
|
126
|
+
return (_jsx(TextColorContext.Provider, { value: textColor, children: _jsx(TextClassContext.Provider, { value: "", children: _jsx(ToggleGroupPrimitive.Item, { ...props, style: {
|
|
127
|
+
flexDirection: "row",
|
|
128
|
+
alignItems: "center",
|
|
129
|
+
justifyContent: "center",
|
|
130
|
+
gap: spacing.sm,
|
|
131
|
+
height: sizeConfig.height,
|
|
132
|
+
minWidth: sizeConfig.minWidth,
|
|
133
|
+
paddingHorizontal: sizeConfig.paddingHorizontal,
|
|
134
|
+
borderWidth: 1,
|
|
135
|
+
flexShrink: 0,
|
|
136
|
+
// Base variant styles
|
|
137
|
+
...(context.variant === "default" && !isSelected && {
|
|
138
|
+
backgroundColor: "transparent",
|
|
139
|
+
borderColor: theme.colors.border,
|
|
140
|
+
}),
|
|
141
|
+
...(context.variant === "default" && isSelected && {
|
|
142
|
+
backgroundColor: withAlpha(theme.colors.primary, 0.1),
|
|
143
|
+
borderColor: theme.colors.primary,
|
|
144
|
+
}),
|
|
145
|
+
// Outline variant styles
|
|
146
|
+
...(context.variant === "outline" && !isSelected && {
|
|
147
|
+
backgroundColor: "transparent",
|
|
148
|
+
borderColor: theme.colors.border,
|
|
149
|
+
}),
|
|
150
|
+
...(context.variant === "outline" && isSelected && {
|
|
151
|
+
backgroundColor: theme.colors.primary,
|
|
152
|
+
borderColor: theme.colors.primary,
|
|
153
|
+
}),
|
|
154
|
+
// Remove borders between items (except first)
|
|
155
|
+
...(context.variant === "outline" && !isFirst && {
|
|
156
|
+
borderLeftWidth: 0,
|
|
157
|
+
}),
|
|
158
|
+
// Border radius handling
|
|
159
|
+
borderRadius: 0, // Remove all radius by default
|
|
160
|
+
...(isFirst && {
|
|
161
|
+
borderTopLeftRadius: spacing.radiusMd,
|
|
162
|
+
borderBottomLeftRadius: spacing.radiusMd,
|
|
163
|
+
}),
|
|
164
|
+
...(isLast && {
|
|
165
|
+
borderTopRightRadius: spacing.radiusMd,
|
|
166
|
+
borderBottomRightRadius: spacing.radiusMd,
|
|
167
|
+
}),
|
|
168
|
+
// Single item (both first and last)
|
|
169
|
+
...(isFirst && isLast && {
|
|
170
|
+
borderRadius: spacing.radiusMd,
|
|
171
|
+
}),
|
|
172
|
+
// Disabled state
|
|
173
|
+
opacity: props.disabled ? 0.5 : 1,
|
|
174
|
+
// Web-specific styles
|
|
175
|
+
...(Platform.OS === "web" && {
|
|
176
|
+
cursor: props.disabled ? "not-allowed" : "pointer",
|
|
177
|
+
transition: "all 150ms",
|
|
178
|
+
// Ensure proper z-index on focus
|
|
179
|
+
...(isSelected && {
|
|
180
|
+
zIndex: 10,
|
|
181
|
+
}),
|
|
182
|
+
}),
|
|
183
|
+
}, hitSlop: DEFAULT_HIT_SLOP, children: children }) }) }));
|
|
184
|
+
}
|
|
185
|
+
function ToggleGroupIcon({ name, size, color }) {
|
|
186
|
+
const contextColor = React.useContext(TextColorContext);
|
|
187
|
+
return _jsx(Icon, { name: name, size: size || spacing.iconMd, color: color || contextColor });
|
|
188
|
+
}
|
|
189
|
+
export { ToggleGroup, ToggleGroupIcon, ToggleGroupItem };
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import { View, ViewProps } from "react-native";
|
|
3
|
+
import * as TooltipPrimitive from "@rn-primitives/tooltip";
|
|
4
|
+
/**
|
|
5
|
+
* Tooltip Trigger Component
|
|
6
|
+
* The element that triggers the tooltip to appear on hover (web) or press (native)
|
|
7
|
+
*/
|
|
8
|
+
declare const TooltipTrigger: {
|
|
9
|
+
({ asChild, onPress: onPressProp, disabled, ref, ...props }: Omit<import("react-native").PressableProps & React.RefAttributes<View>, "ref"> & {
|
|
10
|
+
asChild?: boolean;
|
|
11
|
+
} & {
|
|
12
|
+
onKeyDown?: (ev: React.KeyboardEvent) => void;
|
|
13
|
+
onKeyUp?: (ev: React.KeyboardEvent) => void;
|
|
14
|
+
} & React.RefAttributes<import("@rn-primitives/tooltip").TriggerRef>): React.JSX.Element;
|
|
15
|
+
displayName: string;
|
|
16
|
+
};
|
|
17
|
+
/**
|
|
18
|
+
* Tooltip variant styles
|
|
19
|
+
*/
|
|
20
|
+
export type TooltipVariant = "default" | "dark" | "light";
|
|
21
|
+
interface TooltipContentProps extends TooltipPrimitive.ContentProps {
|
|
22
|
+
/**
|
|
23
|
+
* Optional portal host name for custom portal mounting
|
|
24
|
+
*/
|
|
25
|
+
portalHost?: string;
|
|
26
|
+
/**
|
|
27
|
+
* Visual variant
|
|
28
|
+
* @default "default"
|
|
29
|
+
*/
|
|
30
|
+
variant?: TooltipVariant;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Tooltip Content Component
|
|
34
|
+
* The content that appears in the tooltip overlay
|
|
35
|
+
* Supports smart positioning, animations, and theme integration
|
|
36
|
+
*
|
|
37
|
+
* Features:
|
|
38
|
+
* - Side positioning (top, bottom, left, right - left/right web only)
|
|
39
|
+
* - Alignment options (start, center, end)
|
|
40
|
+
* - Visual variants (default, dark, light)
|
|
41
|
+
* - Smooth animations
|
|
42
|
+
* - Portal-based rendering for proper z-index
|
|
43
|
+
*/
|
|
44
|
+
declare function TooltipContent({ side, align, sideOffset, portalHost, variant, ...props }: TooltipContentProps): import("react/jsx-runtime").JSX.Element;
|
|
45
|
+
/**
|
|
46
|
+
* Tooltip Body Component
|
|
47
|
+
* Simple wrapper for tooltip content with padding
|
|
48
|
+
*/
|
|
49
|
+
interface TooltipBodyProps extends ViewProps {
|
|
50
|
+
children: React.ReactNode;
|
|
51
|
+
}
|
|
52
|
+
declare function TooltipBody({ children, style, ...props }: TooltipBodyProps): import("react/jsx-runtime").JSX.Element;
|
|
53
|
+
interface TooltipProps extends TooltipPrimitive.RootProps {
|
|
54
|
+
/**
|
|
55
|
+
* Time to wait before showing tooltip (web only)
|
|
56
|
+
* @default 700
|
|
57
|
+
*/
|
|
58
|
+
delayDuration?: number;
|
|
59
|
+
/**
|
|
60
|
+
* Time between tooltips when moving cursor (web only)
|
|
61
|
+
* @default 300
|
|
62
|
+
*/
|
|
63
|
+
skipDelayDuration?: number;
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Tooltip Root Component
|
|
67
|
+
* Manages tooltip state and provides context for trigger and content
|
|
68
|
+
*
|
|
69
|
+
* Usage:
|
|
70
|
+
* ```tsx
|
|
71
|
+
* // Basic tooltip
|
|
72
|
+
* <Tooltip>
|
|
73
|
+
* <TooltipTrigger asChild>
|
|
74
|
+
* <Button><Text>Hover me</Text></Button>
|
|
75
|
+
* </TooltipTrigger>
|
|
76
|
+
* <TooltipContent>
|
|
77
|
+
* <StyledText>Tooltip text</StyledText>
|
|
78
|
+
* </TooltipContent>
|
|
79
|
+
* </Tooltip>
|
|
80
|
+
*
|
|
81
|
+
* // With positioning
|
|
82
|
+
* <Tooltip>
|
|
83
|
+
* <TooltipTrigger asChild>
|
|
84
|
+
* <Icon as={Info} size={20} />
|
|
85
|
+
* </TooltipTrigger>
|
|
86
|
+
* <TooltipContent side="bottom" align="start">
|
|
87
|
+
* <StyledText>Information tooltip</StyledText>
|
|
88
|
+
* </TooltipContent>
|
|
89
|
+
* </Tooltip>
|
|
90
|
+
*
|
|
91
|
+
* // Dark variant
|
|
92
|
+
* <Tooltip>
|
|
93
|
+
* <TooltipTrigger asChild>
|
|
94
|
+
* <Button><Text>Help</Text></Button>
|
|
95
|
+
* </TooltipTrigger>
|
|
96
|
+
* <TooltipContent variant="dark">
|
|
97
|
+
* <StyledText>Dark tooltip</StyledText>
|
|
98
|
+
* </TooltipContent>
|
|
99
|
+
* </Tooltip>
|
|
100
|
+
* ```
|
|
101
|
+
*/
|
|
102
|
+
declare function Tooltip({ delayDuration, skipDelayDuration, ...props }: TooltipProps): import("react/jsx-runtime").JSX.Element;
|
|
103
|
+
/**
|
|
104
|
+
* Tooltip Component with Sub-components
|
|
105
|
+
* Properly typed interface for dot notation access (e.g., Tooltip.Trigger)
|
|
106
|
+
*/
|
|
107
|
+
declare const TooltipComponent: typeof Tooltip & {
|
|
108
|
+
Trigger: {
|
|
109
|
+
({ asChild, onPress: onPressProp, disabled, ref, ...props }: Omit<import("react-native").PressableProps & React.RefAttributes<View>, "ref"> & {
|
|
110
|
+
asChild?: boolean;
|
|
111
|
+
} & {
|
|
112
|
+
onKeyDown?: (ev: React.KeyboardEvent) => void;
|
|
113
|
+
onKeyUp?: (ev: React.KeyboardEvent) => void;
|
|
114
|
+
} & React.RefAttributes<import("@rn-primitives/tooltip").TriggerRef>): React.JSX.Element;
|
|
115
|
+
displayName: string;
|
|
116
|
+
};
|
|
117
|
+
Content: typeof TooltipContent;
|
|
118
|
+
Body: typeof TooltipBody;
|
|
119
|
+
};
|
|
120
|
+
export { TooltipComponent as Tooltip, TooltipTrigger, TooltipContent, TooltipBody, };
|
|
121
|
+
export type { TooltipContentProps, TooltipBodyProps, TooltipProps, };
|