@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,162 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { palette } from "../constants/colors";
|
|
3
|
+
import { useTheme } from "../hooks/useTheme";
|
|
4
|
+
import { hapticLight } from "../lib/haptics";
|
|
5
|
+
import { useCallback, useRef } from "react";
|
|
6
|
+
import { Platform, StyleSheet, View } from "react-native";
|
|
7
|
+
import { Gesture, GestureDetector } from "react-native-gesture-handler";
|
|
8
|
+
import Animated, { runOnJS, useAnimatedStyle, useSharedValue, withTiming, } from "react-native-reanimated";
|
|
9
|
+
import { StyledText } from "./StyledText";
|
|
10
|
+
const SIZES = {
|
|
11
|
+
sm: { track: 4, thumb: 16 },
|
|
12
|
+
md: { track: 6, thumb: 20 },
|
|
13
|
+
};
|
|
14
|
+
function clampAndSnap(raw, min, max, step) {
|
|
15
|
+
"worklet";
|
|
16
|
+
const clamped = Math.min(Math.max(raw, min), max);
|
|
17
|
+
const stepped = Math.round((clamped - min) / step) * step + min;
|
|
18
|
+
// Avoid floating-point drift
|
|
19
|
+
return Math.round(stepped * 1e6) / 1e6;
|
|
20
|
+
}
|
|
21
|
+
function Slider({ value = 0, onValueChange, min = 0, max = 100, step = 1, size = "md", disabled = false, showValue = false, style: styleOverride, }) {
|
|
22
|
+
const { theme } = useTheme();
|
|
23
|
+
const dims = SIZES[size];
|
|
24
|
+
// Track layout width captured via onLayout
|
|
25
|
+
const trackWidth = useSharedValue(0);
|
|
26
|
+
// Thumb position in pixels along the track
|
|
27
|
+
const thumbX = useSharedValue(0);
|
|
28
|
+
// Last snapped value (worklet-side) to detect step changes for haptics
|
|
29
|
+
const lastSnappedValue = useSharedValue(value);
|
|
30
|
+
// Keep a ref to onValueChange so the worklet always calls the latest version
|
|
31
|
+
const onValueChangeRef = useRef(onValueChange);
|
|
32
|
+
onValueChangeRef.current = onValueChange;
|
|
33
|
+
const jsOnValueChange = useCallback((v) => {
|
|
34
|
+
onValueChangeRef.current?.(v);
|
|
35
|
+
}, []);
|
|
36
|
+
const jsHaptic = useCallback(() => {
|
|
37
|
+
hapticLight();
|
|
38
|
+
}, []);
|
|
39
|
+
// Sync external value prop changes with animation
|
|
40
|
+
const prevExternalValue = useRef(value);
|
|
41
|
+
if (value !== prevExternalValue.current) {
|
|
42
|
+
prevExternalValue.current = value;
|
|
43
|
+
if (trackWidth.value > 0) {
|
|
44
|
+
const ratio = (value - min) / (max - min || 1);
|
|
45
|
+
thumbX.value = withTiming(ratio * trackWidth.value, { duration: 80 });
|
|
46
|
+
}
|
|
47
|
+
lastSnappedValue.value = value;
|
|
48
|
+
}
|
|
49
|
+
const onTrackLayout = useCallback((e) => {
|
|
50
|
+
const w = e.nativeEvent.layout.width;
|
|
51
|
+
trackWidth.value = w;
|
|
52
|
+
// Set initial thumb position without animation
|
|
53
|
+
const ratio = (value - min) / (max - min || 1);
|
|
54
|
+
thumbX.value = ratio * w;
|
|
55
|
+
}, [value, min, max]);
|
|
56
|
+
const panGesture = Gesture.Pan()
|
|
57
|
+
.enabled(!disabled)
|
|
58
|
+
.onBegin((e) => {
|
|
59
|
+
"worklet";
|
|
60
|
+
// Jump to touch position
|
|
61
|
+
const x = Math.min(Math.max(e.x, 0), trackWidth.value);
|
|
62
|
+
thumbX.value = x;
|
|
63
|
+
const ratio = trackWidth.value > 0 ? x / trackWidth.value : 0;
|
|
64
|
+
const raw = min + ratio * (max - min);
|
|
65
|
+
const snapped = clampAndSnap(raw, min, max, step);
|
|
66
|
+
if (snapped !== lastSnappedValue.value) {
|
|
67
|
+
lastSnappedValue.value = snapped;
|
|
68
|
+
runOnJS(jsHaptic)();
|
|
69
|
+
}
|
|
70
|
+
runOnJS(jsOnValueChange)(snapped);
|
|
71
|
+
})
|
|
72
|
+
.onUpdate((e) => {
|
|
73
|
+
"worklet";
|
|
74
|
+
const x = Math.min(Math.max(e.x, 0), trackWidth.value);
|
|
75
|
+
thumbX.value = x;
|
|
76
|
+
const ratio = trackWidth.value > 0 ? x / trackWidth.value : 0;
|
|
77
|
+
const raw = min + ratio * (max - min);
|
|
78
|
+
const snapped = clampAndSnap(raw, min, max, step);
|
|
79
|
+
if (snapped !== lastSnappedValue.value) {
|
|
80
|
+
lastSnappedValue.value = snapped;
|
|
81
|
+
runOnJS(jsHaptic)();
|
|
82
|
+
}
|
|
83
|
+
runOnJS(jsOnValueChange)(snapped);
|
|
84
|
+
});
|
|
85
|
+
const fillStyle = useAnimatedStyle(() => ({
|
|
86
|
+
width: thumbX.value,
|
|
87
|
+
}));
|
|
88
|
+
const thumbAnimatedStyle = useAnimatedStyle(() => ({
|
|
89
|
+
transform: [{ translateX: thumbX.value - dims.thumb / 2 }],
|
|
90
|
+
}));
|
|
91
|
+
const valueLabelStyle = useAnimatedStyle(() => ({
|
|
92
|
+
transform: [{ translateX: thumbX.value - 14 }],
|
|
93
|
+
}));
|
|
94
|
+
const flattenedStyle = styleOverride ? StyleSheet.flatten(styleOverride) : undefined;
|
|
95
|
+
// Accessibility action handler
|
|
96
|
+
const handleAccessibilityAction = useCallback((event) => {
|
|
97
|
+
const action = event.nativeEvent.actionName;
|
|
98
|
+
let next = value;
|
|
99
|
+
if (action === "increment") {
|
|
100
|
+
next = Math.min(value + step, max);
|
|
101
|
+
}
|
|
102
|
+
else if (action === "decrement") {
|
|
103
|
+
next = Math.max(value - step, min);
|
|
104
|
+
}
|
|
105
|
+
if (next !== value) {
|
|
106
|
+
onValueChange?.(next);
|
|
107
|
+
}
|
|
108
|
+
}, [value, step, min, max, onValueChange]);
|
|
109
|
+
return (_jsxs(View, { style: [{ opacity: disabled ? 0.5 : 1 }, flattenedStyle], accessibilityRole: "adjustable", accessibilityValue: { min, max, now: value }, accessibilityActions: [
|
|
110
|
+
{ name: "increment", label: "Increment" },
|
|
111
|
+
{ name: "decrement", label: "Decrement" },
|
|
112
|
+
], onAccessibilityAction: handleAccessibilityAction, children: [showValue && (_jsx(Animated.View, { style: [
|
|
113
|
+
{
|
|
114
|
+
position: "absolute",
|
|
115
|
+
top: -20,
|
|
116
|
+
width: 28,
|
|
117
|
+
alignItems: "center",
|
|
118
|
+
},
|
|
119
|
+
valueLabelStyle,
|
|
120
|
+
], pointerEvents: "none", children: _jsx(StyledText, { style: {
|
|
121
|
+
fontSize: 11,
|
|
122
|
+
color: theme.colors.textDim,
|
|
123
|
+
userSelect: "none",
|
|
124
|
+
}, children: value }) })), _jsx(GestureDetector, { gesture: panGesture, children: _jsxs(View, { style: {
|
|
125
|
+
height: dims.thumb,
|
|
126
|
+
justifyContent: "center",
|
|
127
|
+
...(Platform.OS === "web" && { cursor: disabled ? "default" : "pointer" }),
|
|
128
|
+
}, onLayout: onTrackLayout, children: [_jsx(View, { style: {
|
|
129
|
+
height: dims.track,
|
|
130
|
+
borderRadius: dims.track / 2,
|
|
131
|
+
backgroundColor: theme.colors.muted,
|
|
132
|
+
overflow: "hidden",
|
|
133
|
+
}, children: _jsx(Animated.View, { style: [
|
|
134
|
+
{
|
|
135
|
+
height: dims.track,
|
|
136
|
+
borderRadius: dims.track / 2,
|
|
137
|
+
backgroundColor: theme.colors.primary,
|
|
138
|
+
},
|
|
139
|
+
fillStyle,
|
|
140
|
+
] }) }), _jsx(Animated.View, { style: [
|
|
141
|
+
{
|
|
142
|
+
position: "absolute",
|
|
143
|
+
top: 0,
|
|
144
|
+
left: 0,
|
|
145
|
+
width: dims.thumb,
|
|
146
|
+
height: dims.thumb,
|
|
147
|
+
borderRadius: dims.thumb / 2,
|
|
148
|
+
backgroundColor: palette.white,
|
|
149
|
+
borderWidth: 1,
|
|
150
|
+
borderColor: theme.colors.border,
|
|
151
|
+
...(Platform.OS !== "web" && {
|
|
152
|
+
shadowColor: "#000",
|
|
153
|
+
shadowOffset: { width: 0, height: 1 },
|
|
154
|
+
shadowOpacity: 0.15,
|
|
155
|
+
shadowRadius: 2,
|
|
156
|
+
elevation: 2,
|
|
157
|
+
}),
|
|
158
|
+
},
|
|
159
|
+
thumbAnimatedStyle,
|
|
160
|
+
] })] }) })] }));
|
|
161
|
+
}
|
|
162
|
+
export { Slider };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const StatusBar: () => import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { useEffect } from "react";
|
|
3
|
+
import { useTheme } from "../hooks/useTheme";
|
|
4
|
+
import { StatusBar as RNStatusBar, Platform } from "react-native";
|
|
5
|
+
export const StatusBar = () => {
|
|
6
|
+
const { scheme, theme } = useTheme();
|
|
7
|
+
const barStyle = scheme === "dark" ? "light-content" : "dark-content";
|
|
8
|
+
/**
|
|
9
|
+
* Switching from system theme to light/dark would not properly update the status bar, so it is done imperatively
|
|
10
|
+
*/
|
|
11
|
+
useEffect(() => {
|
|
12
|
+
RNStatusBar.setBarStyle(barStyle, true);
|
|
13
|
+
if (Platform.OS === "android") {
|
|
14
|
+
RNStatusBar.setBackgroundColor("transparent", true);
|
|
15
|
+
RNStatusBar.setTranslucent(true);
|
|
16
|
+
}
|
|
17
|
+
}, [barStyle]);
|
|
18
|
+
return (_jsx(RNStatusBar, { barStyle: barStyle, backgroundColor: Platform.OS === "android" ? "transparent" : undefined, translucent: true }));
|
|
19
|
+
};
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { Text as RNText, TextProps as RNTextProps } from "react-native";
|
|
3
|
+
/**
|
|
4
|
+
* TextClassContext provides className context for nested text components
|
|
5
|
+
* Used by @rn-primitives to apply consistent styling through the component tree
|
|
6
|
+
*/
|
|
7
|
+
export declare const TextClassContext: React.Context<string | undefined>;
|
|
8
|
+
/**
|
|
9
|
+
* TextColorContext provides color context for nested text components
|
|
10
|
+
* Allows parent components (like Button) to override text color for all children
|
|
11
|
+
*/
|
|
12
|
+
export declare const TextColorContext: React.Context<string | undefined>;
|
|
13
|
+
/**
|
|
14
|
+
* Font size variants following the DM Sans / DM Serif Display scale
|
|
15
|
+
*/
|
|
16
|
+
export type FontSize = "xs" | "sm" | "base" | "body" | "lg" | "xl" | "xxl" | "display";
|
|
17
|
+
/**
|
|
18
|
+
* Semantic text variants for different use cases
|
|
19
|
+
*/
|
|
20
|
+
export type SemanticVariant = "title" | "heading" | "subheading" | "body" | "caption" | "label";
|
|
21
|
+
/**
|
|
22
|
+
* Font weight options
|
|
23
|
+
*/
|
|
24
|
+
export type FontWeight = "light" | "regular" | "medium" | "semibold" | "bold";
|
|
25
|
+
/**
|
|
26
|
+
* Text alignment options
|
|
27
|
+
*/
|
|
28
|
+
export type TextAlign = "left" | "center" | "right" | "justify" | "auto";
|
|
29
|
+
export type TextProps = RNTextProps & {
|
|
30
|
+
/**
|
|
31
|
+
* Font variant - serif (DM Serif Display) or sans-serif (DM Sans)
|
|
32
|
+
*/
|
|
33
|
+
variant?: "serif" | "sansSerif";
|
|
34
|
+
/**
|
|
35
|
+
* Font weight - light, regular, medium, semibold, bold
|
|
36
|
+
*/
|
|
37
|
+
fontWeight?: FontWeight;
|
|
38
|
+
/**
|
|
39
|
+
* Font size variant
|
|
40
|
+
*/
|
|
41
|
+
size?: FontSize;
|
|
42
|
+
/**
|
|
43
|
+
* Semantic variant - automatically sets size and weight
|
|
44
|
+
* Overrides individual size/fontWeight if provided
|
|
45
|
+
*/
|
|
46
|
+
semantic?: SemanticVariant;
|
|
47
|
+
/**
|
|
48
|
+
* Text alignment
|
|
49
|
+
*/
|
|
50
|
+
align?: TextAlign;
|
|
51
|
+
/**
|
|
52
|
+
* Text which is looked up via i18n.
|
|
53
|
+
*/
|
|
54
|
+
tx?: string;
|
|
55
|
+
/**
|
|
56
|
+
* The text to display if not using `tx` or nested components.
|
|
57
|
+
*/
|
|
58
|
+
text?: string;
|
|
59
|
+
/**
|
|
60
|
+
* Optional options to pass to i18n. Useful for interpolation
|
|
61
|
+
* as well as explicitly setting locale or translation fallbacks.
|
|
62
|
+
*/
|
|
63
|
+
txOptions?: object;
|
|
64
|
+
};
|
|
65
|
+
/**
|
|
66
|
+
* Base Text component with theme and variant support
|
|
67
|
+
* Uses theme colors automatically - text by default
|
|
68
|
+
*
|
|
69
|
+
* Features:
|
|
70
|
+
* - Size variants (xs, sm, base, body, lg, xl, xxl, display)
|
|
71
|
+
* - Semantic variants (title, heading, subheading, body, caption, label)
|
|
72
|
+
* - Text alignment prop
|
|
73
|
+
* - Font weight options (light, regular, medium, semibold, bold)
|
|
74
|
+
* - Text selection enabled by default (userSelect: "auto")
|
|
75
|
+
* - numberOfLines and ellipsizeMode support from RN TextProps
|
|
76
|
+
*/
|
|
77
|
+
export declare const StyledText: React.ForwardRefExoticComponent<RNTextProps & {
|
|
78
|
+
/**
|
|
79
|
+
* Font variant - serif (DM Serif Display) or sans-serif (DM Sans)
|
|
80
|
+
*/
|
|
81
|
+
variant?: "serif" | "sansSerif";
|
|
82
|
+
/**
|
|
83
|
+
* Font weight - light, regular, medium, semibold, bold
|
|
84
|
+
*/
|
|
85
|
+
fontWeight?: FontWeight;
|
|
86
|
+
/**
|
|
87
|
+
* Font size variant
|
|
88
|
+
*/
|
|
89
|
+
size?: FontSize;
|
|
90
|
+
/**
|
|
91
|
+
* Semantic variant - automatically sets size and weight
|
|
92
|
+
* Overrides individual size/fontWeight if provided
|
|
93
|
+
*/
|
|
94
|
+
semantic?: SemanticVariant;
|
|
95
|
+
/**
|
|
96
|
+
* Text alignment
|
|
97
|
+
*/
|
|
98
|
+
align?: TextAlign;
|
|
99
|
+
/**
|
|
100
|
+
* Text which is looked up via i18n.
|
|
101
|
+
*/
|
|
102
|
+
tx?: string;
|
|
103
|
+
/**
|
|
104
|
+
* The text to display if not using `tx` or nested components.
|
|
105
|
+
*/
|
|
106
|
+
text?: string;
|
|
107
|
+
/**
|
|
108
|
+
* Optional options to pass to i18n. Useful for interpolation
|
|
109
|
+
* as well as explicitly setting locale or translation fallbacks.
|
|
110
|
+
*/
|
|
111
|
+
txOptions?: object;
|
|
112
|
+
} & React.RefAttributes<RNText>>;
|
|
113
|
+
/**
|
|
114
|
+
* Serif Text Component
|
|
115
|
+
* Uses serif font family (DM Serif Display)
|
|
116
|
+
*/
|
|
117
|
+
export declare function SerifText(props: TextProps): import("react/jsx-runtime").JSX.Element;
|
|
118
|
+
/**
|
|
119
|
+
* Sans-Serif Text Component
|
|
120
|
+
* Uses sans-serif font family (DM Sans)
|
|
121
|
+
*/
|
|
122
|
+
export declare function SansSerifText(props: TextProps): import("react/jsx-runtime").JSX.Element;
|
|
123
|
+
/**
|
|
124
|
+
* Serif Bold Text Component
|
|
125
|
+
* Uses serif font family — DM Serif Display only has regular weight
|
|
126
|
+
*/
|
|
127
|
+
export declare function SerifBoldText(props: TextProps): import("react/jsx-runtime").JSX.Element;
|
|
128
|
+
/**
|
|
129
|
+
* Sans-Serif Bold Text Component
|
|
130
|
+
* Uses sans-serif font family with semibold weight (DM Sans 600)
|
|
131
|
+
*/
|
|
132
|
+
export declare function SansSerifBoldText(props: TextProps): import("react/jsx-runtime").JSX.Element;
|
|
133
|
+
/**
|
|
134
|
+
* Display Text Component
|
|
135
|
+
* Uses DM Serif Display at display size — for hero text and splash screens
|
|
136
|
+
*/
|
|
137
|
+
export declare function DisplayText(props: TextProps): import("react/jsx-runtime").JSX.Element;
|
|
138
|
+
/**
|
|
139
|
+
* Title Text - Large semibold text for page titles
|
|
140
|
+
*/
|
|
141
|
+
export declare function TitleText(props: TextProps): import("react/jsx-runtime").JSX.Element;
|
|
142
|
+
/**
|
|
143
|
+
* Heading Text - Section heading text
|
|
144
|
+
*/
|
|
145
|
+
export declare function HeadingText(props: TextProps): import("react/jsx-runtime").JSX.Element;
|
|
146
|
+
/**
|
|
147
|
+
* Subheading Text - Subsection heading text
|
|
148
|
+
*/
|
|
149
|
+
export declare function SubheadingText(props: TextProps): import("react/jsx-runtime").JSX.Element;
|
|
150
|
+
/**
|
|
151
|
+
* Body Text - Default text for paragraphs and content
|
|
152
|
+
*/
|
|
153
|
+
export declare function BodyText(props: TextProps): import("react/jsx-runtime").JSX.Element;
|
|
154
|
+
/**
|
|
155
|
+
* Caption Text - Small text for captions and secondary content
|
|
156
|
+
*/
|
|
157
|
+
export declare function CaptionText(props: TextProps): import("react/jsx-runtime").JSX.Element;
|
|
158
|
+
/**
|
|
159
|
+
* Label Text - Medium weight text for form labels
|
|
160
|
+
*/
|
|
161
|
+
export declare function LabelText(props: TextProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import React, { forwardRef } from "react";
|
|
3
|
+
import { Text as RNText, StyleSheet } from "react-native";
|
|
4
|
+
import { useTranslation } from "react-i18next";
|
|
5
|
+
import { useTheme } from "../hooks/useTheme";
|
|
6
|
+
import { fontFamilies } from "../constants/fonts";
|
|
7
|
+
/**
|
|
8
|
+
* TextClassContext provides className context for nested text components
|
|
9
|
+
* Used by @rn-primitives to apply consistent styling through the component tree
|
|
10
|
+
*/
|
|
11
|
+
export const TextClassContext = React.createContext(undefined);
|
|
12
|
+
/**
|
|
13
|
+
* TextColorContext provides color context for nested text components
|
|
14
|
+
* Allows parent components (like Button) to override text color for all children
|
|
15
|
+
*/
|
|
16
|
+
export const TextColorContext = React.createContext(undefined);
|
|
17
|
+
const FONT_SIZES = {
|
|
18
|
+
xs: 11,
|
|
19
|
+
sm: 12,
|
|
20
|
+
base: 14,
|
|
21
|
+
body: 15,
|
|
22
|
+
lg: 18,
|
|
23
|
+
xl: 22,
|
|
24
|
+
xxl: 28,
|
|
25
|
+
display: 34,
|
|
26
|
+
};
|
|
27
|
+
const LINE_HEIGHTS = {
|
|
28
|
+
xs: 16.5,
|
|
29
|
+
sm: 18,
|
|
30
|
+
base: 21,
|
|
31
|
+
body: 24.75,
|
|
32
|
+
lg: 27,
|
|
33
|
+
xl: 26.4,
|
|
34
|
+
xxl: 33.6,
|
|
35
|
+
display: 40.8,
|
|
36
|
+
};
|
|
37
|
+
const LETTER_SPACING = {
|
|
38
|
+
sm: 0.5,
|
|
39
|
+
xxl: -0.3,
|
|
40
|
+
display: -0.5,
|
|
41
|
+
};
|
|
42
|
+
const SEMANTIC_CONFIGS = {
|
|
43
|
+
title: { size: "xxl", weight: "semibold" },
|
|
44
|
+
heading: { size: "xl", weight: "semibold" },
|
|
45
|
+
subheading: { size: "lg", weight: "medium" },
|
|
46
|
+
body: { size: "body", weight: "regular" },
|
|
47
|
+
caption: { size: "sm", weight: "regular" },
|
|
48
|
+
label: { size: "base", weight: "medium" },
|
|
49
|
+
};
|
|
50
|
+
// Map font weights to actual font family weight keys
|
|
51
|
+
// DM Sans has: light, regular, medium, semibold
|
|
52
|
+
// DM Serif Display has: regular only
|
|
53
|
+
const getFontFamilyWeight = (weight) => {
|
|
54
|
+
if (!weight || weight === "regular")
|
|
55
|
+
return "regular";
|
|
56
|
+
if (weight === "light")
|
|
57
|
+
return "light";
|
|
58
|
+
if (weight === "medium")
|
|
59
|
+
return "medium";
|
|
60
|
+
// semibold and bold both map to semibold (DM Sans's heaviest weight)
|
|
61
|
+
return "semibold";
|
|
62
|
+
};
|
|
63
|
+
/**
|
|
64
|
+
* Base Text component with theme and variant support
|
|
65
|
+
* Uses theme colors automatically - text by default
|
|
66
|
+
*
|
|
67
|
+
* Features:
|
|
68
|
+
* - Size variants (xs, sm, base, body, lg, xl, xxl, display)
|
|
69
|
+
* - Semantic variants (title, heading, subheading, body, caption, label)
|
|
70
|
+
* - Text alignment prop
|
|
71
|
+
* - Font weight options (light, regular, medium, semibold, bold)
|
|
72
|
+
* - Text selection enabled by default (userSelect: "auto")
|
|
73
|
+
* - numberOfLines and ellipsizeMode support from RN TextProps
|
|
74
|
+
*/
|
|
75
|
+
export const StyledText = forwardRef((props, ref) => {
|
|
76
|
+
const { tx, text, txOptions, style, variant = "sansSerif", fontWeight, size, semantic, align, children, ...otherProps } = props;
|
|
77
|
+
const { theme } = useTheme();
|
|
78
|
+
const { t } = useTranslation();
|
|
79
|
+
// Check if there's a color override from parent context (e.g., Button)
|
|
80
|
+
const contextColor = React.useContext(TextColorContext);
|
|
81
|
+
// Use context color if provided, otherwise use theme default
|
|
82
|
+
const color = contextColor ?? theme.colors.text;
|
|
83
|
+
// If semantic variant is provided, use its config
|
|
84
|
+
const semanticConfig = semantic ? SEMANTIC_CONFIGS[semantic] : undefined;
|
|
85
|
+
const finalSize = semanticConfig?.size ?? size ?? "body";
|
|
86
|
+
const finalFontWeight = semanticConfig?.weight ?? fontWeight ?? "regular";
|
|
87
|
+
// Get font family based on variant and weight
|
|
88
|
+
const fontFamilyWeight = getFontFamilyWeight(finalFontWeight);
|
|
89
|
+
// DM Serif Display only has regular — use it regardless of requested weight
|
|
90
|
+
const fontFamily = variant === "serif"
|
|
91
|
+
? fontFamilies.serif.regular
|
|
92
|
+
: fontFamilies.sansSerif[fontFamilyWeight] ?? fontFamilies.sansSerif.regular;
|
|
93
|
+
// Get fontSize and lineHeight from size variant
|
|
94
|
+
const fontSize = FONT_SIZES[finalSize];
|
|
95
|
+
const lineHeight = LINE_HEIGHTS[finalSize];
|
|
96
|
+
const letterSpacing = LETTER_SPACING[finalSize];
|
|
97
|
+
// If style overrides fontSize without lineHeight, drop the preset lineHeight
|
|
98
|
+
// so RN uses its default (avoids clipping text with a mismatched lineHeight)
|
|
99
|
+
const flatStyle = style ? StyleSheet.flatten(style) : undefined;
|
|
100
|
+
const styleHasFontSize = flatStyle && "fontSize" in flatStyle;
|
|
101
|
+
const styleHasLineHeight = flatStyle && "lineHeight" in flatStyle;
|
|
102
|
+
const resolvedLineHeight = styleHasFontSize && !styleHasLineHeight ? undefined : lineHeight;
|
|
103
|
+
const i18nText = tx ? String(t(tx, txOptions)) : text;
|
|
104
|
+
const content = i18nText || children;
|
|
105
|
+
return (_jsx(RNText, { ref: ref, style: [
|
|
106
|
+
{
|
|
107
|
+
color,
|
|
108
|
+
fontFamily,
|
|
109
|
+
fontSize,
|
|
110
|
+
...(resolvedLineHeight !== undefined && { lineHeight: resolvedLineHeight }),
|
|
111
|
+
userSelect: "auto", // Changed from "none" to allow text selection
|
|
112
|
+
...(letterSpacing !== undefined && { letterSpacing }),
|
|
113
|
+
...(align && { textAlign: align }),
|
|
114
|
+
},
|
|
115
|
+
style,
|
|
116
|
+
// When a parent (Button, ToggleGroupItem) sets TextColorContext,
|
|
117
|
+
// that color must win over any color in the style prop
|
|
118
|
+
contextColor != null && { color: contextColor },
|
|
119
|
+
], ...otherProps, children: content }));
|
|
120
|
+
});
|
|
121
|
+
StyledText.displayName = "StyledText";
|
|
122
|
+
/**
|
|
123
|
+
* Serif Text Component
|
|
124
|
+
* Uses serif font family (DM Serif Display)
|
|
125
|
+
*/
|
|
126
|
+
export function SerifText(props) {
|
|
127
|
+
return _jsx(StyledText, { ...props, variant: "serif" });
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Sans-Serif Text Component
|
|
131
|
+
* Uses sans-serif font family (DM Sans)
|
|
132
|
+
*/
|
|
133
|
+
export function SansSerifText(props) {
|
|
134
|
+
return _jsx(StyledText, { ...props, variant: "sansSerif" });
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Serif Bold Text Component
|
|
138
|
+
* Uses serif font family — DM Serif Display only has regular weight
|
|
139
|
+
*/
|
|
140
|
+
export function SerifBoldText(props) {
|
|
141
|
+
return _jsx(StyledText, { ...props, variant: "serif", fontWeight: "regular" });
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* Sans-Serif Bold Text Component
|
|
145
|
+
* Uses sans-serif font family with semibold weight (DM Sans 600)
|
|
146
|
+
*/
|
|
147
|
+
export function SansSerifBoldText(props) {
|
|
148
|
+
return _jsx(StyledText, { ...props, variant: "sansSerif", fontWeight: "semibold" });
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* Display Text Component
|
|
152
|
+
* Uses DM Serif Display at display size — for hero text and splash screens
|
|
153
|
+
*/
|
|
154
|
+
export function DisplayText(props) {
|
|
155
|
+
return _jsx(StyledText, { ...props, variant: "serif", size: "display" });
|
|
156
|
+
}
|
|
157
|
+
// Export convenience components for semantic variants
|
|
158
|
+
/**
|
|
159
|
+
* Title Text - Large semibold text for page titles
|
|
160
|
+
*/
|
|
161
|
+
export function TitleText(props) {
|
|
162
|
+
return _jsx(StyledText, { ...props, semantic: "title" });
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* Heading Text - Section heading text
|
|
166
|
+
*/
|
|
167
|
+
export function HeadingText(props) {
|
|
168
|
+
return _jsx(StyledText, { ...props, semantic: "heading" });
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* Subheading Text - Subsection heading text
|
|
172
|
+
*/
|
|
173
|
+
export function SubheadingText(props) {
|
|
174
|
+
return _jsx(StyledText, { ...props, semantic: "subheading" });
|
|
175
|
+
}
|
|
176
|
+
/**
|
|
177
|
+
* Body Text - Default text for paragraphs and content
|
|
178
|
+
*/
|
|
179
|
+
export function BodyText(props) {
|
|
180
|
+
return _jsx(StyledText, { ...props, semantic: "body" });
|
|
181
|
+
}
|
|
182
|
+
/**
|
|
183
|
+
* Caption Text - Small text for captions and secondary content
|
|
184
|
+
*/
|
|
185
|
+
export function CaptionText(props) {
|
|
186
|
+
return _jsx(StyledText, { ...props, semantic: "caption" });
|
|
187
|
+
}
|
|
188
|
+
/**
|
|
189
|
+
* Label Text - Medium weight text for form labels
|
|
190
|
+
*/
|
|
191
|
+
export function LabelText(props) {
|
|
192
|
+
return _jsx(StyledText, { ...props, semantic: "label" });
|
|
193
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import * as SwitchPrimitives from "@rn-primitives/switch";
|
|
2
|
+
import { StyleProp, ViewStyle } from "react-native";
|
|
3
|
+
/**
|
|
4
|
+
* Switch variant styles
|
|
5
|
+
*/
|
|
6
|
+
export type SwitchVariant = "default" | "ios";
|
|
7
|
+
interface SwitchProps extends Omit<SwitchPrimitives.RootProps, "style"> {
|
|
8
|
+
/**
|
|
9
|
+
* Visual variant
|
|
10
|
+
* @default "default"
|
|
11
|
+
*/
|
|
12
|
+
variant?: SwitchVariant;
|
|
13
|
+
/**
|
|
14
|
+
* Optional label to display when switch is ON (checked)
|
|
15
|
+
*/
|
|
16
|
+
labelOn?: string;
|
|
17
|
+
/**
|
|
18
|
+
* Optional label to display when switch is OFF (unchecked)
|
|
19
|
+
*/
|
|
20
|
+
labelOff?: string;
|
|
21
|
+
/**
|
|
22
|
+
* Custom size for the switch container
|
|
23
|
+
* Default: { width: 44, height: 24 }
|
|
24
|
+
*/
|
|
25
|
+
size?: {
|
|
26
|
+
width: number;
|
|
27
|
+
height: number;
|
|
28
|
+
};
|
|
29
|
+
/**
|
|
30
|
+
* Custom size for the thumb (sliding circle)
|
|
31
|
+
* Default: 20
|
|
32
|
+
*/
|
|
33
|
+
thumbSize?: number;
|
|
34
|
+
/**
|
|
35
|
+
* Whether to show a loading spinner inside the thumb
|
|
36
|
+
*/
|
|
37
|
+
loading?: boolean;
|
|
38
|
+
/**
|
|
39
|
+
* Custom style override (uses StyleSheet.flatten for web compatibility)
|
|
40
|
+
*/
|
|
41
|
+
style?: StyleProp<ViewStyle>;
|
|
42
|
+
}
|
|
43
|
+
declare function Switch({ variant, labelOn, labelOff, size, thumbSize, loading, style: styleOverride, ...props }: SwitchProps): import("react/jsx-runtime").JSX.Element;
|
|
44
|
+
export { Switch };
|