@mrmeg/expo-ui 0.10.0 → 0.10.1

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/CHANGELOG.md ADDED
@@ -0,0 +1,24 @@
1
+ # Changelog
2
+
3
+ All notable changes to `@mrmeg/expo-ui` are documented here. This project
4
+ adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
5
+
6
+ ## [0.10.1]
7
+
8
+ ### Fixed
9
+
10
+ - Fix TextInput rounded-corner fill leak on New Architecture. On Fabric, the
11
+ `outline`/`filled` variants stroked a rounded border but painted the
12
+ background fill as an un-clipped rect, so the fill's square corners poked past
13
+ the rounded stroke (most visible on dark themes and the `filled` variant). The
14
+ fill, border, and radius now live on the RN wrapper `View` with
15
+ `overflow: "hidden"`, and the native `@expo/ui` host renders transparent inside
16
+ that clipped rounded surface. The `underlined` variant (bottom border only),
17
+ error state, `forceLight` mode, and the secure-entry eye toggle are unchanged.
18
+
19
+ ## [0.10.0]
20
+
21
+ ### Added
22
+
23
+ - Drawer collapsible rail mode (`variant="rail"`, `Drawer.ToggleCollapse`).
24
+ - Theme-aware Icon color resolution.
@@ -243,16 +243,26 @@ leftElement, rightElement, clearable, focusedStyle, style, ...rest }) {
243
243
  const textColor = forceLight
244
244
  ? "#1f2937"
245
245
  : getContrastingColor(backgroundColor === "transparent" ? theme.colors.background : backgroundColor, theme.colors.text, palette.white);
246
- // Map variant/size to @expo/ui's UniversalStyle (translated to SwiftUI /
247
- // Compose modifiers natively).
248
- const boxStyle = {
246
+ // The rounded surface (fill + border + radius) lives on the RN wrapper View,
247
+ // NOT on the native field. On the New Architecture (Fabric), @expo/ui's host
248
+ // paints `backgroundColor` as an un-clipped rect and strokes the rounded border
249
+ // on top, so a fill handed to the host leaks square corners past the stroke.
250
+ // Letting the RN View own the surface (with `overflow: "hidden"`) keeps the
251
+ // fill clipped to `borderRadius`; the native host sits transparent inside it.
252
+ const surfaceStyle = {
249
253
  backgroundColor,
250
254
  borderColor,
251
255
  borderRadius: variant === "underlined" ? 0 : spacing.radiusMd,
252
256
  borderWidth: variant === "outline" ? 1 : 0,
257
+ opacity: editable === false ? 0.6 : 1,
258
+ overflow: "hidden",
259
+ };
260
+ // Native field: transparent, padding + height only. The visible surface is
261
+ // drawn by `surfaceStyle` on the wrapper above.
262
+ const boxStyle = {
263
+ backgroundColor: "transparent",
253
264
  paddingHorizontal: sizeConfig.paddingHorizontal,
254
265
  paddingVertical: sizeConfig.paddingVertical,
255
- opacity: editable === false ? 0.6 : 1,
256
266
  ...(multiline ? null : { height: sizeConfig.height }),
257
267
  };
258
268
  // "System" is an RN-only sentinel (RCTFont resolves it to the system font).
@@ -268,7 +278,7 @@ leftElement, rightElement, clearable, focusedStyle, style, ...rest }) {
268
278
  fontSize: sizeConfig.fontSize,
269
279
  ...(nativeFontFamily ? { fontFamily: nativeFontFamily } : null),
270
280
  };
271
- return (_jsxs(View, { style: wrapperStyle, children: [!!label && (_jsx(View, { style: styles.labelContainer, children: _jsxs(StyledText, { selectable: false, style: styles.label, children: [label, required && _jsx(StyledText, { selectable: false, style: styles.required, children: " *" })] }) })), _jsxs(View, { style: hasSecureToggle ? styles.nativeRow : undefined, children: [_jsx(Host, { matchContents: { vertical: true }, style: hasSecureToggle ? styles.nativeHostFlex : styles.nativeHost, children: _jsx(ExpoTextInput, { ...rest, ref: innerRef, value: state, defaultValue: defaultValue, onChangeText: onChangeText, editable: editable, multiline: multiline, rows: rows, inputMode: inputMode, secureTextEntry: effectiveSecureTextEntry, placeholderTextColor: theme.colors.textDim, style: boxStyle, textStyle: textStyle }) }), hasSecureToggle && (_jsx(Pressable, { style: styles.nativePasswordToggle, onPress: () => setPasswordVisible((v) => !v), accessibilityLabel: passwordVisible ? "Hide password" : "Show password", accessibilityRole: "button", children: _jsx(Icon, { name: passwordVisible ? "eye-off" : "eye", size: spacing.iconSm + 4, color: "textDim" }) }))] }), !!(helperText || errorText) && (_jsx(StyledText, { selectable: false, style: [styles.helperText, hasError && styles.errorText], children: errorText || helperText }))] }));
281
+ return (_jsxs(View, { style: wrapperStyle, children: [!!label && (_jsx(View, { style: styles.labelContainer, children: _jsxs(StyledText, { selectable: false, style: styles.label, children: [label, required && _jsx(StyledText, { selectable: false, style: styles.required, children: " *" })] }) })), _jsxs(View, { style: [surfaceStyle, hasSecureToggle && styles.nativeRow], children: [_jsx(Host, { matchContents: { vertical: true }, style: hasSecureToggle ? styles.nativeHostFlex : styles.nativeHost, children: _jsx(ExpoTextInput, { ...rest, ref: innerRef, value: state, defaultValue: defaultValue, onChangeText: onChangeText, editable: editable, multiline: multiline, rows: rows, inputMode: inputMode, secureTextEntry: effectiveSecureTextEntry, placeholderTextColor: theme.colors.textDim, style: boxStyle, textStyle: textStyle }) }), hasSecureToggle && (_jsx(Pressable, { style: styles.nativePasswordToggle, onPress: () => setPasswordVisible((v) => !v), accessibilityLabel: passwordVisible ? "Hide password" : "Show password", accessibilityRole: "button", children: _jsx(Icon, { name: passwordVisible ? "eye-off" : "eye", size: spacing.iconSm + 4, color: "textDim" }) }))] }), !!(helperText || errorText) && (_jsx(StyledText, { selectable: false, style: [styles.helperText, hasError && styles.errorText], children: errorText || helperText }))] }));
272
282
  }
273
283
  const createStyles = (theme, variant, size) => StyleSheet.create({
274
284
  nativeHost: {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mrmeg/expo-ui",
3
- "version": "0.10.0",
3
+ "version": "0.10.1",
4
4
  "private": false,
5
5
  "description": "Reusable Expo and React Native UI primitives for MrMeg projects.",
6
6
  "keywords": [
@@ -33,6 +33,7 @@
33
33
  "dist",
34
34
  "package.json",
35
35
  "README.md",
36
+ "CHANGELOG.md",
36
37
  "LLM_USAGE.md",
37
38
  "llms.txt",
38
39
  "llms-full.md"