@vellira-ui/react-native 2.22.4 → 2.23.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 (3) hide show
  1. package/README.md +13 -1
  2. package/dist/index.js +143 -23
  3. package/package.json +3 -3
package/README.md CHANGED
@@ -42,11 +42,17 @@ import { View } from 'react-native';
42
42
 
43
43
  export function Example() {
44
44
  const [email, setEmail] = useState('');
45
+ const [accepted, setAccepted] = useState(false);
45
46
 
46
47
  return (
47
48
  <View style={{ gap: 16 }}>
48
49
  <Input label='Email' value={email} onChange={setEmail} />
49
- <Checkbox label='Accept terms' />
50
+ <Checkbox
51
+ label='Accept terms'
52
+ description='Required to create an account.'
53
+ checked={accepted}
54
+ onCheckedChange={setAccepted}
55
+ />
50
56
  <Button color='primary' variant='solid'>
51
57
  Continue
52
58
  </Button>
@@ -69,6 +75,12 @@ Button icons are React elements from `@vellira-ui/icons`; the component injects
69
75
  the current icon color and size. `loading` disables interaction and can replace
70
76
  the visible label with `loadingText`.
71
77
 
78
+ ### Checkbox Notes
79
+
80
+ Use `description` for settings-style helper text when the checkbox is not
81
+ wrapped in `FormField`. For checkbox rows without a visible label, provide
82
+ `accessibilityLabel`.
83
+
72
84
  ## Testing
73
85
 
74
86
  Run only native tests:
package/dist/index.js CHANGED
@@ -2036,23 +2036,45 @@ import { Pressable as Pressable12, Text as Text13, View as View19 } from "react-
2036
2036
  // src/primitives/Checkbox/Checkbox.styles.ts
2037
2037
  import { StyleSheet as StyleSheet22 } from "react-native";
2038
2038
  var createStyles22 = (theme) => StyleSheet22.create({
2039
+ container: {
2040
+ gap: theme.tokens.spacing[2]
2041
+ },
2039
2042
  wrapper: {
2040
2043
  flexDirection: "row",
2041
2044
  alignItems: "center",
2042
2045
  gap: theme.tokens.spacing[3]
2043
2046
  },
2047
+ iconOnly: {
2048
+ justifyContent: "center",
2049
+ minWidth: 44,
2050
+ minHeight: 44
2051
+ },
2044
2052
  disabled: {
2045
2053
  opacity: 1
2046
2054
  },
2047
2055
  box: {
2048
- width: 22,
2049
- height: 22,
2050
- borderWidth: 2,
2051
- borderColor: theme.components.checkbox.default.border,
2052
- borderRadius: theme.tokens.radius.md,
2056
+ flexShrink: 0,
2053
2057
  alignItems: "center",
2054
2058
  justifyContent: "center",
2055
- backgroundColor: theme.components.checkbox.default.bg
2059
+ backgroundColor: theme.components.checkbox.default.bg,
2060
+ borderWidth: 2,
2061
+ borderColor: theme.components.checkbox.default.border,
2062
+ borderRadius: theme.tokens.radius.xs
2063
+ },
2064
+ boxSm: {
2065
+ width: 16,
2066
+ height: 16,
2067
+ borderWidth: 1
2068
+ },
2069
+ boxMd: {
2070
+ width: 20,
2071
+ height: 20,
2072
+ borderWidth: 2
2073
+ },
2074
+ boxLg: {
2075
+ width: 24,
2076
+ height: 24,
2077
+ borderWidth: 2
2056
2078
  },
2057
2079
  boxChecked: {
2058
2080
  backgroundColor: theme.components.checkbox.checked.default.bg,
@@ -2065,40 +2087,102 @@ var createStyles22 = (theme) => StyleSheet22.create({
2065
2087
  boxError: {
2066
2088
  borderColor: theme.components.checkbox.error.border
2067
2089
  },
2090
+ indeterminateMark: {
2091
+ width: "60%",
2092
+ height: 2,
2093
+ backgroundColor: theme.components.checkbox.checked.default.fg,
2094
+ borderRadius: theme.tokens.radius.full
2095
+ },
2068
2096
  label: {
2097
+ flexShrink: 1,
2069
2098
  fontFamily: theme.tokens.typography.family.regular,
2070
- fontSize: theme.tokens.typography.size.md,
2071
2099
  color: theme.components.checkbox.default.fg
2072
2100
  },
2101
+ labelSm: {
2102
+ fontSize: theme.tokens.typography.size.sm,
2103
+ lineHeight: theme.tokens.typography.lineHeight.sm
2104
+ },
2105
+ labelMd: {
2106
+ fontSize: theme.tokens.typography.size.md,
2107
+ lineHeight: theme.tokens.typography.lineHeight.md
2108
+ },
2109
+ labelLg: {
2110
+ fontSize: theme.tokens.typography.size.lg,
2111
+ lineHeight: theme.tokens.typography.lineHeight.lg
2112
+ },
2073
2113
  labelDisabled: {
2074
2114
  color: theme.components.checkbox.disabled.fg
2075
2115
  },
2076
- container: {
2077
- gap: theme.tokens.spacing[2]
2116
+ requiredMark: {
2117
+ color: theme.components.checkbox.error.fg
2118
+ },
2119
+ descriptionText: {
2120
+ color: theme.components.formField.description.fg,
2121
+ fontFamily: theme.tokens.typography.family.regular,
2122
+ fontSize: theme.tokens.typography.size.sm,
2123
+ lineHeight: theme.tokens.typography.lineHeight.sm
2124
+ },
2125
+ descriptionTextDisabled: {
2126
+ color: theme.components.formField.disabled.descriptionFg
2078
2127
  },
2079
2128
  errorText: {
2080
2129
  color: theme.components.checkbox.error.fg,
2130
+ fontFamily: theme.tokens.typography.family.regular,
2081
2131
  fontSize: theme.tokens.typography.size.sm,
2082
- lineHeight: theme.tokens.typography.lineHeight.sm,
2083
- marginLeft: 22 + theme.tokens.spacing[3]
2132
+ lineHeight: theme.tokens.typography.lineHeight.sm
2133
+ },
2134
+ errorTextSm: {
2135
+ marginLeft: 16 + theme.tokens.spacing[3]
2136
+ },
2137
+ errorTextMd: {
2138
+ marginLeft: 20 + theme.tokens.spacing[3]
2139
+ },
2140
+ errorTextLg: {
2141
+ marginLeft: 24 + theme.tokens.spacing[3]
2084
2142
  }
2085
2143
  });
2086
2144
 
2087
2145
  // src/primitives/Checkbox/Checkbox.tsx
2088
2146
  import { jsx as jsx24, jsxs as jsxs14 } from "react/jsx-runtime";
2147
+ var iconSizeBySize = {
2148
+ sm: 10,
2149
+ md: 12,
2150
+ lg: 14
2151
+ };
2089
2152
  var Checkbox = forwardRef(
2090
2153
  ({
2091
2154
  label,
2155
+ description,
2092
2156
  checked,
2093
2157
  defaultChecked = false,
2094
2158
  disabled = false,
2159
+ required = false,
2160
+ indeterminate = false,
2161
+ size = "md",
2095
2162
  onCheckedChange,
2096
2163
  error,
2097
2164
  style,
2098
- ...props
2165
+ accessibilityLabel,
2166
+ accessibilityHint,
2167
+ ...PressableProps
2099
2168
  }, ref) => {
2100
2169
  const { theme } = useTheme();
2101
2170
  const styles = useThemeStyles(createStyles22);
2171
+ const boxSizeStyle = {
2172
+ sm: styles.boxSm,
2173
+ md: styles.boxMd,
2174
+ lg: styles.boxLg
2175
+ };
2176
+ const labelSizeStyle = {
2177
+ sm: styles.labelSm,
2178
+ md: styles.labelMd,
2179
+ lg: styles.labelLg
2180
+ };
2181
+ const helperTextSizeStyle = {
2182
+ sm: styles.errorTextSm,
2183
+ md: styles.errorTextMd,
2184
+ lg: styles.errorTextLg
2185
+ };
2102
2186
  const hasError = Boolean(error);
2103
2187
  const [isChecked, setIsChecked] = useControllableState4({
2104
2188
  value: checked,
@@ -2107,43 +2191,80 @@ var Checkbox = forwardRef(
2107
2191
  });
2108
2192
  const handlePress = () => {
2109
2193
  if (disabled) return;
2110
- setIsChecked(!isChecked);
2194
+ setIsChecked(indeterminate ? true : !isChecked);
2111
2195
  };
2196
+ const resolvedAccessibilityLabel = accessibilityLabel ?? label;
2197
+ const resolvedAccessibilityHint = [accessibilityHint, description, error].filter(Boolean).join(" ");
2198
+ const accessibilityChecked = indeterminate ? "mixed" : isChecked;
2112
2199
  const checkColor = disabled ? theme.components.checkbox.disabled.fg : theme.components.checkbox.checked.default.fg;
2200
+ devWarning(
2201
+ Boolean(resolvedAccessibilityLabel),
2202
+ "Checkbox: an accessible label must be provided through label or accessibilityLabel."
2203
+ );
2113
2204
  return /* @__PURE__ */ jsxs14(View19, { style: styles.container, children: [
2114
2205
  /* @__PURE__ */ jsxs14(
2115
2206
  Pressable12,
2116
2207
  {
2208
+ ...PressableProps,
2117
2209
  ref,
2118
2210
  onPress: handlePress,
2119
2211
  disabled,
2120
2212
  accessibilityRole: "checkbox",
2121
2213
  accessibilityState: {
2122
- checked: isChecked,
2214
+ checked: accessibilityChecked,
2123
2215
  disabled
2124
2216
  },
2125
- accessibilityHint: hasError ? error : void 0,
2126
- accessibilityLabel: label ?? "Checkbox",
2127
- style: [styles.wrapper, disabled && styles.disabled, style],
2128
- ...props,
2217
+ accessibilityHint: resolvedAccessibilityHint || void 0,
2218
+ accessibilityLabel: resolvedAccessibilityLabel,
2219
+ style: [
2220
+ styles.wrapper,
2221
+ !label && styles.iconOnly,
2222
+ disabled && styles.disabled,
2223
+ style
2224
+ ],
2129
2225
  children: [
2130
2226
  /* @__PURE__ */ jsx24(
2131
2227
  View19,
2132
2228
  {
2133
2229
  style: [
2134
2230
  styles.box,
2135
- isChecked && styles.boxChecked,
2231
+ boxSizeStyle[size],
2232
+ (isChecked || indeterminate) && styles.boxChecked,
2136
2233
  hasError && styles.boxError,
2137
2234
  disabled && styles.boxDisabled
2138
2235
  ],
2139
- children: isChecked && /* @__PURE__ */ jsx24(Check, { size: 12, color: checkColor })
2236
+ children: indeterminate ? /* @__PURE__ */ jsx24(View19, { style: styles.indeterminateMark }) : isChecked && /* @__PURE__ */ jsx24(Check, { size: iconSizeBySize[size], color: checkColor })
2140
2237
  }
2141
2238
  ),
2142
- label && /* @__PURE__ */ jsx24(Text13, { style: [styles.label, disabled && styles.labelDisabled], children: label })
2239
+ label && /* @__PURE__ */ jsxs14(
2240
+ Text13,
2241
+ {
2242
+ style: [
2243
+ styles.label,
2244
+ labelSizeStyle[size],
2245
+ disabled && styles.labelDisabled
2246
+ ],
2247
+ children: [
2248
+ label,
2249
+ required && /* @__PURE__ */ jsx24(Text13, { style: styles.requiredMark, children: " *" })
2250
+ ]
2251
+ }
2252
+ )
2143
2253
  ]
2144
2254
  }
2145
2255
  ),
2146
- hasError && /* @__PURE__ */ jsx24(Text13, { style: styles.errorText, children: error })
2256
+ description && /* @__PURE__ */ jsx24(
2257
+ Text13,
2258
+ {
2259
+ style: [
2260
+ styles.descriptionText,
2261
+ helperTextSizeStyle[size],
2262
+ disabled && styles.descriptionTextDisabled
2263
+ ],
2264
+ children: description
2265
+ }
2266
+ ),
2267
+ hasError && /* @__PURE__ */ jsx24(Text13, { style: [styles.errorText, helperTextSizeStyle[size]], children: error })
2147
2268
  ] });
2148
2269
  }
2149
2270
  );
@@ -2360,7 +2481,6 @@ var Input = forwardRef2(
2360
2481
  if (!isControlled) {
2361
2482
  setUncontrolledValue("");
2362
2483
  }
2363
- onChange?.("");
2364
2484
  onClear?.();
2365
2485
  };
2366
2486
  const showClearButton = clearable && hasValue && !disabled && !readOnly;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vellira-ui/react-native",
3
- "version": "2.22.4",
3
+ "version": "2.23.0",
4
4
  "description": "React Native components for Vellira Design System",
5
5
  "author": "Roman Bakurov",
6
6
  "license": "MIT",
@@ -49,12 +49,12 @@
49
49
  },
50
50
  "devDependencies": {
51
51
  "@types/react": "^19.2.3",
52
- "@vitest/coverage-v8": "^4.1.9",
52
+ "@vitest/coverage-v8": "^4.1.10",
53
53
  "jsdom": "^28.1.0",
54
54
  "react": "19.2.7",
55
55
  "tsup": "^8.5.1",
56
56
  "typescript": "6.0.3",
57
- "vitest": "^4.1.9"
57
+ "vitest": "^4.1.10"
58
58
  },
59
59
  "publishConfig": {
60
60
  "access": "public"