@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.
Files changed (112) hide show
  1. package/README.md +96 -0
  2. package/dist/components/Accordion.d.ts +54 -0
  3. package/dist/components/Accordion.js +149 -0
  4. package/dist/components/Alert.d.ts +30 -0
  5. package/dist/components/Alert.js +25 -0
  6. package/dist/components/AnimatedView.d.ts +55 -0
  7. package/dist/components/AnimatedView.js +39 -0
  8. package/dist/components/Badge.d.ts +23 -0
  9. package/dist/components/Badge.js +74 -0
  10. package/dist/components/BottomSheet.d.ts +74 -0
  11. package/dist/components/BottomSheet.js +513 -0
  12. package/dist/components/Button.d.ts +129 -0
  13. package/dist/components/Button.js +216 -0
  14. package/dist/components/Card.d.ts +42 -0
  15. package/dist/components/Card.js +126 -0
  16. package/dist/components/Checkbox.d.ts +39 -0
  17. package/dist/components/Checkbox.js +96 -0
  18. package/dist/components/Collapsible.d.ts +67 -0
  19. package/dist/components/Collapsible.js +38 -0
  20. package/dist/components/Dialog.d.ts +140 -0
  21. package/dist/components/Dialog.js +167 -0
  22. package/dist/components/DismissKeyboard.d.ts +15 -0
  23. package/dist/components/DismissKeyboard.js +13 -0
  24. package/dist/components/Drawer.d.ts +74 -0
  25. package/dist/components/Drawer.js +423 -0
  26. package/dist/components/DropdownMenu.d.ts +120 -0
  27. package/dist/components/DropdownMenu.js +211 -0
  28. package/dist/components/EmptyState.d.ts +42 -0
  29. package/dist/components/EmptyState.js +58 -0
  30. package/dist/components/ErrorBoundary.d.ts +53 -0
  31. package/dist/components/ErrorBoundary.js +75 -0
  32. package/dist/components/Icon.d.ts +46 -0
  33. package/dist/components/Icon.js +40 -0
  34. package/dist/components/InputOTP.d.ts +72 -0
  35. package/dist/components/InputOTP.js +155 -0
  36. package/dist/components/Label.d.ts +61 -0
  37. package/dist/components/Label.js +72 -0
  38. package/dist/components/MaxWidthContainer.d.ts +58 -0
  39. package/dist/components/MaxWidthContainer.js +64 -0
  40. package/dist/components/Notification.d.ts +26 -0
  41. package/dist/components/Notification.js +230 -0
  42. package/dist/components/Popover.d.ts +79 -0
  43. package/dist/components/Popover.js +91 -0
  44. package/dist/components/Progress.d.ts +28 -0
  45. package/dist/components/Progress.js +107 -0
  46. package/dist/components/RadioGroup.d.ts +65 -0
  47. package/dist/components/RadioGroup.js +142 -0
  48. package/dist/components/Select.d.ts +88 -0
  49. package/dist/components/Select.js +172 -0
  50. package/dist/components/Separator.d.ts +83 -0
  51. package/dist/components/Separator.js +85 -0
  52. package/dist/components/Skeleton.d.ts +68 -0
  53. package/dist/components/Skeleton.js +99 -0
  54. package/dist/components/Slider.d.ts +24 -0
  55. package/dist/components/Slider.js +162 -0
  56. package/dist/components/StatusBar.d.ts +1 -0
  57. package/dist/components/StatusBar.js +19 -0
  58. package/dist/components/StyledText.d.ts +161 -0
  59. package/dist/components/StyledText.js +193 -0
  60. package/dist/components/Switch.d.ts +44 -0
  61. package/dist/components/Switch.js +129 -0
  62. package/dist/components/Tabs.d.ts +31 -0
  63. package/dist/components/Tabs.js +127 -0
  64. package/dist/components/TextInput.d.ts +120 -0
  65. package/dist/components/TextInput.js +263 -0
  66. package/dist/components/Toggle.d.ts +106 -0
  67. package/dist/components/Toggle.js +150 -0
  68. package/dist/components/ToggleGroup.d.ts +80 -0
  69. package/dist/components/ToggleGroup.js +189 -0
  70. package/dist/components/Tooltip.d.ts +121 -0
  71. package/dist/components/Tooltip.js +132 -0
  72. package/dist/components/index.d.ts +35 -0
  73. package/dist/components/index.js +35 -0
  74. package/dist/constants/colors.d.ts +82 -0
  75. package/dist/constants/colors.js +116 -0
  76. package/dist/constants/fonts.d.ts +32 -0
  77. package/dist/constants/fonts.js +91 -0
  78. package/dist/constants/index.d.ts +3 -0
  79. package/dist/constants/index.js +3 -0
  80. package/dist/constants/spacing.d.ts +40 -0
  81. package/dist/constants/spacing.js +48 -0
  82. package/dist/hooks/index.d.ts +6 -0
  83. package/dist/hooks/index.js +6 -0
  84. package/dist/hooks/useDimensions.d.ts +19 -0
  85. package/dist/hooks/useDimensions.js +55 -0
  86. package/dist/hooks/useReduceMotion.d.ts +5 -0
  87. package/dist/hooks/useReduceMotion.js +64 -0
  88. package/dist/hooks/useResources.d.ts +12 -0
  89. package/dist/hooks/useResources.js +56 -0
  90. package/dist/hooks/useScalePress.d.ts +57 -0
  91. package/dist/hooks/useScalePress.js +55 -0
  92. package/dist/hooks/useStaggeredEntrance.d.ts +67 -0
  93. package/dist/hooks/useStaggeredEntrance.js +74 -0
  94. package/dist/hooks/useTheme.d.ts +88 -0
  95. package/dist/hooks/useTheme.js +328 -0
  96. package/dist/index.d.ts +5 -0
  97. package/dist/index.js +5 -0
  98. package/dist/lib/animations.d.ts +1 -0
  99. package/dist/lib/animations.js +3 -0
  100. package/dist/lib/haptics.d.ts +3 -0
  101. package/dist/lib/haptics.js +29 -0
  102. package/dist/lib/index.d.ts +3 -0
  103. package/dist/lib/index.js +3 -0
  104. package/dist/lib/sentry.d.ts +16 -0
  105. package/dist/lib/sentry.js +55 -0
  106. package/dist/state/globalUIStore.d.ts +30 -0
  107. package/dist/state/globalUIStore.js +8 -0
  108. package/dist/state/index.d.ts +2 -0
  109. package/dist/state/index.js +2 -0
  110. package/dist/state/themeStore.d.ts +6 -0
  111. package/dist/state/themeStore.js +38 -0
  112. 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 };