@mrmeg/expo-ui 0.8.0 → 0.9.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/LLM_USAGE.md +3 -2
- package/dist/components/ToggleGroup.js +2 -7
- package/dist/hooks/useTheme.d.ts +1 -1
- package/dist/hooks/useTheme.js +28 -93
- package/package.json +1 -1
package/LLM_USAGE.md
CHANGED
|
@@ -125,8 +125,9 @@ Token intent:
|
|
|
125
125
|
|
|
126
126
|
Use `getShadowStyle()` for package surfaces that need elevation. It supports
|
|
127
127
|
`base`, `soft`, `sharp`, `subtle`, `elevated`, `glow`, `glass`, `card`,
|
|
128
|
-
`cardHover`, and `cardSubtle`, returning
|
|
129
|
-
|
|
128
|
+
`cardHover`, and `cardSubtle`, returning a cross-platform `boxShadow` value
|
|
129
|
+
(RN 0.85 + react-native-web 0.21 deprecate the legacy `shadow*` props). Use
|
|
130
|
+
`getFocusRingStyle()` for web focus styling. Keep
|
|
130
131
|
web controls compact, but preserve mobile tap comfort with package controls
|
|
131
132
|
that already provide native hit slop or 44px touch rows.
|
|
132
133
|
|
|
@@ -64,7 +64,7 @@ function useToggleGroupContext() {
|
|
|
64
64
|
* ```
|
|
65
65
|
*/
|
|
66
66
|
function ToggleGroup({ variant = "default", size = "default", children, ...props }) {
|
|
67
|
-
const {
|
|
67
|
+
const { getShadowStyle } = useTheme();
|
|
68
68
|
const contextValue = React.useMemo(() => ({ variant, size }), [variant, size]);
|
|
69
69
|
// Count valid children for first/last detection
|
|
70
70
|
const childrenArray = React.Children.toArray(children);
|
|
@@ -89,12 +89,7 @@ function ToggleGroup({ variant = "default", size = "default", children, ...props
|
|
|
89
89
|
alignItems: "center",
|
|
90
90
|
borderRadius: spacing.radiusMd,
|
|
91
91
|
// No shadow on Android - causes text background artifact
|
|
92
|
-
...(variant === "outline" && Platform.OS === "ios" &&
|
|
93
|
-
shadowColor: theme.colors.overlay,
|
|
94
|
-
shadowOffset: { width: 0, height: 1 },
|
|
95
|
-
shadowOpacity: 0.05,
|
|
96
|
-
shadowRadius: 2,
|
|
97
|
-
}),
|
|
92
|
+
...(variant === "outline" && Platform.OS === "ios" && getShadowStyle("subtle")),
|
|
98
93
|
...(Platform.OS === "web" && {
|
|
99
94
|
width: "fit-content",
|
|
100
95
|
}),
|
package/dist/hooks/useTheme.d.ts
CHANGED
|
@@ -32,7 +32,7 @@ interface ExtendedColorScheme {
|
|
|
32
32
|
* - getTextColorForBackground("#000") → "light"
|
|
33
33
|
* - getContrastingColor("#f4f4f4", "#222", "#fff") → "#222"
|
|
34
34
|
* - withAlpha("#336699", 0.6) → "rgba(51,102,153,0.6)"
|
|
35
|
-
* - getShadowStyle('base') → {
|
|
35
|
+
* - getShadowStyle('base') → { boxShadow: "0px 1px 3px rgba(0, 0, 0, 0.1)" }
|
|
36
36
|
*/
|
|
37
37
|
export declare function useTheme(): ExtendedColorScheme & {
|
|
38
38
|
toggleTheme: () => void;
|
package/dist/hooks/useTheme.js
CHANGED
|
@@ -42,7 +42,7 @@ function getCachedOrCompute(key, compute) {
|
|
|
42
42
|
* - getTextColorForBackground("#000") → "light"
|
|
43
43
|
* - getContrastingColor("#f4f4f4", "#222", "#fff") → "#222"
|
|
44
44
|
* - withAlpha("#336699", 0.6) → "rgba(51,102,153,0.6)"
|
|
45
|
-
* - getShadowStyle('base') → {
|
|
45
|
+
* - getShadowStyle('base') → { boxShadow: "0px 1px 3px rgba(0, 0, 0, 0.1)" }
|
|
46
46
|
*/
|
|
47
47
|
export function useTheme() {
|
|
48
48
|
const userTheme = useThemeStore((s) => s.userTheme);
|
|
@@ -93,102 +93,37 @@ export function useTheme() {
|
|
|
93
93
|
}, [setTheme, userTheme]);
|
|
94
94
|
/**
|
|
95
95
|
* getShadowStyle
|
|
96
|
-
* Returns platform
|
|
97
|
-
*
|
|
98
|
-
* -
|
|
96
|
+
* Returns a cross-platform shadow style using the `boxShadow` style prop.
|
|
97
|
+
*
|
|
98
|
+
* RN 0.85 + react-native-web 0.21 deprecate the legacy `shadow*` props in
|
|
99
|
+
* favor of `boxShadow`, which is supported on both native and web. Because
|
|
100
|
+
* `boxShadow` has no separate opacity field, each preset's opacity is folded
|
|
101
|
+
* into the color's alpha via `withAlpha`. `elevation` is dropped — `boxShadow`
|
|
102
|
+
* renders shadows on Android in 0.85+.
|
|
99
103
|
*/
|
|
100
104
|
const getShadowStyle = useCallback((type) => {
|
|
105
|
+
// Each preset: [offsetX, offsetY, blurRadius, color, opacity].
|
|
106
|
+
// Darker themes get a stronger alpha so shadows stay visible.
|
|
107
|
+
const boost = theme.dark ? 3 : 1;
|
|
108
|
+
const overlay = theme.colors.overlay;
|
|
101
109
|
const shadowConfigs = {
|
|
102
|
-
base: {
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
},
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
shadowOffset: { width: 0, height: 1 },
|
|
119
|
-
shadowOpacity: 0.15,
|
|
120
|
-
shadowRadius: 1,
|
|
121
|
-
elevation: 2,
|
|
122
|
-
},
|
|
123
|
-
subtle: {
|
|
124
|
-
shadowColor: theme.colors.overlay,
|
|
125
|
-
shadowOffset: { width: 0, height: 1 },
|
|
126
|
-
shadowOpacity: 0.05,
|
|
127
|
-
shadowRadius: 2,
|
|
128
|
-
elevation: 1,
|
|
129
|
-
},
|
|
130
|
-
elevated: {
|
|
131
|
-
shadowColor: theme.colors.overlay,
|
|
132
|
-
shadowOffset: { width: 0, height: 20 },
|
|
133
|
-
shadowOpacity: 0.15,
|
|
134
|
-
shadowRadius: 40,
|
|
135
|
-
elevation: 16,
|
|
136
|
-
},
|
|
137
|
-
glow: {
|
|
138
|
-
shadowColor: theme.colors.primary,
|
|
139
|
-
shadowOffset: { width: 0, height: 4 },
|
|
140
|
-
shadowOpacity: 0.4,
|
|
141
|
-
shadowRadius: 20,
|
|
142
|
-
elevation: 10,
|
|
143
|
-
},
|
|
144
|
-
glass: {
|
|
145
|
-
shadowColor: theme.colors.overlay,
|
|
146
|
-
shadowOffset: { width: 0, height: 4 },
|
|
147
|
-
shadowOpacity: 0.05,
|
|
148
|
-
shadowRadius: 30,
|
|
149
|
-
elevation: 4,
|
|
150
|
-
},
|
|
151
|
-
card: {
|
|
152
|
-
shadowColor: theme.colors.overlay,
|
|
153
|
-
shadowOffset: { width: 0, height: 2 },
|
|
154
|
-
shadowOpacity: 0.08,
|
|
155
|
-
shadowRadius: 8,
|
|
156
|
-
elevation: 4,
|
|
157
|
-
},
|
|
158
|
-
cardHover: {
|
|
159
|
-
shadowColor: theme.colors.overlay,
|
|
160
|
-
shadowOffset: { width: 0, height: 8 },
|
|
161
|
-
shadowOpacity: 0.12,
|
|
162
|
-
shadowRadius: 24,
|
|
163
|
-
elevation: 8,
|
|
164
|
-
},
|
|
165
|
-
cardSubtle: {
|
|
166
|
-
shadowColor: theme.colors.overlay,
|
|
167
|
-
shadowOffset: { width: 0, height: 1 },
|
|
168
|
-
shadowOpacity: 0.08,
|
|
169
|
-
shadowRadius: 3,
|
|
170
|
-
elevation: 2,
|
|
171
|
-
},
|
|
110
|
+
base: { x: 0, y: 1, blur: 3, color: overlay, opacity: 0.1 },
|
|
111
|
+
soft: { x: 0, y: 4, blur: 6, color: overlay, opacity: 0.1 },
|
|
112
|
+
sharp: { x: 0, y: 1, blur: 1, color: overlay, opacity: 0.15 },
|
|
113
|
+
subtle: { x: 0, y: 1, blur: 2, color: overlay, opacity: 0.05 },
|
|
114
|
+
elevated: { x: 0, y: 20, blur: 40, color: overlay, opacity: 0.15 },
|
|
115
|
+
glow: { x: 0, y: 4, blur: 20, color: theme.colors.primary, opacity: 0.4 },
|
|
116
|
+
glass: { x: 0, y: 4, blur: 30, color: overlay, opacity: 0.05 },
|
|
117
|
+
card: { x: 0, y: 2, blur: 8, color: overlay, opacity: 0.08 },
|
|
118
|
+
cardHover: { x: 0, y: 8, blur: 24, color: overlay, opacity: 0.12 },
|
|
119
|
+
cardSubtle: { x: 0, y: 1, blur: 3, color: overlay, opacity: 0.08 },
|
|
120
|
+
};
|
|
121
|
+
const { x, y, blur, color, opacity } = shadowConfigs[type];
|
|
122
|
+
// Don't boost the glow accent — it's already a deliberate, vivid alpha.
|
|
123
|
+
const alpha = color === theme.colors.primary ? opacity : Math.min(opacity * boost, 1);
|
|
124
|
+
return {
|
|
125
|
+
boxShadow: `${x}px ${y}px ${blur}px ${withAlpha(color, alpha)}`,
|
|
172
126
|
};
|
|
173
|
-
const config = shadowConfigs[type];
|
|
174
|
-
if (Platform.OS === "web") {
|
|
175
|
-
const webShadows = {
|
|
176
|
-
base: { boxShadow: theme.dark ? "0 1px 2px rgba(0, 0, 0, 0.45)" : "0 1px 2px rgba(0, 0, 0, 0.08)" },
|
|
177
|
-
soft: { boxShadow: theme.dark ? "0 8px 24px rgba(0, 0, 0, 0.36)" : "0 8px 24px rgba(0, 0, 0, 0.10)" },
|
|
178
|
-
sharp: { boxShadow: theme.dark ? "0 1px 1px rgba(0, 0, 0, 0.55)" : "0 1px 1px rgba(0, 0, 0, 0.12)" },
|
|
179
|
-
subtle: { boxShadow: theme.dark ? "0 1px 2px rgba(0, 0, 0, 0.32)" : "0 1px 2px rgba(0, 0, 0, 0.05)" },
|
|
180
|
-
elevated: { boxShadow: theme.dark ? "0 20px 40px rgba(0, 0, 0, 0.38)" : "0 20px 40px rgba(0, 0, 0, 0.15)" },
|
|
181
|
-
glow: { boxShadow: `0 0 20px ${theme.colors.primary}` },
|
|
182
|
-
glass: { boxShadow: theme.dark ? "0 4px 30px rgba(0, 0, 0, 0.32)" : "0 4px 30px rgba(0, 0, 0, 0.05)" },
|
|
183
|
-
card: { boxShadow: theme.dark ? "0 1px 2px rgba(0, 0, 0, 0.32)" : "0 1px 3px rgba(0, 0, 0, 0.08)" },
|
|
184
|
-
cardHover: { boxShadow: theme.dark ? "0 8px 24px rgba(0, 0, 0, 0.36)" : "0 8px 24px rgba(0, 0, 0, 0.12)" },
|
|
185
|
-
cardSubtle: { boxShadow: theme.dark ? "0 1px 2px rgba(0, 0, 0, 0.32)" : "0 1px 3px rgba(0, 0, 0, 0.05)" },
|
|
186
|
-
};
|
|
187
|
-
return webShadows[type];
|
|
188
|
-
}
|
|
189
|
-
return Platform.select({
|
|
190
|
-
default: config,
|
|
191
|
-
});
|
|
192
127
|
}, [theme]);
|
|
193
128
|
const getFocusRingStyle = useCallback((offset = 2) => {
|
|
194
129
|
if (Platform.OS !== "web") {
|