@vellira-ui/react-native 2.26.1 → 2.27.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 +2 -2
  2. package/dist/index.js +109 -29
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -54,7 +54,7 @@ export function Example() {
54
54
  checked={accepted}
55
55
  onCheckedChange={setAccepted}
56
56
  />
57
- <Button color='primary' variant='solid'>
57
+ <Button color='primary' appearance='solid'>
58
58
  Continue
59
59
  </Button>
60
60
  </View>
@@ -69,7 +69,7 @@ Use `accessibilityLabel` for icon-only native buttons:
69
69
  ```tsx
70
70
  import { Search } from '@vellira-ui/icons';
71
71
 
72
- <Button accessibilityLabel='Search' iconOnly leftIcon={<Search />} />;
72
+ <Button accessibilityLabel='Search' iconOnly iconStart={<Search />} />;
73
73
  ```
74
74
 
75
75
  Button icons are React elements from `@vellira-ui/icons`; the component injects
package/dist/index.js CHANGED
@@ -2207,7 +2207,7 @@ Tooltip.displayName = "Tooltip";
2207
2207
 
2208
2208
  // src/primitives/Button/Button.tsx
2209
2209
  import { cloneElement as cloneElement5, useState as useState5 } from "react";
2210
- import { ActivityIndicator, Pressable as Pressable10, Text as Text11 } from "react-native";
2210
+ import { ActivityIndicator, Pressable as Pressable10, Text as Text11, View as View19 } from "react-native";
2211
2211
 
2212
2212
  // src/utils/devWarning.ts
2213
2213
  var devWarning = (condition, message) => {
@@ -2225,7 +2225,6 @@ var createStyles21 = (theme) => StyleSheet21.create({
2225
2225
  alignItems: "center",
2226
2226
  justifyContent: "center",
2227
2227
  gap: 8,
2228
- borderRadius: theme.tokens.radius.md,
2229
2228
  borderWidth: 1
2230
2229
  },
2231
2230
  fullWidth: {
@@ -2239,10 +2238,32 @@ var createStyles21 = (theme) => StyleSheet21.create({
2239
2238
  // Fallback color.
2240
2239
  color: theme.components.button.primary.solid.default.fg
2241
2240
  },
2241
+ labelSlot: {
2242
+ position: "relative"
2243
+ },
2244
+ labelMeasure: {
2245
+ position: "absolute",
2246
+ opacity: 0
2247
+ },
2242
2248
  spinner: {
2243
2249
  fontSize: 12,
2244
2250
  lineHeight: theme.tokens.typography.lineHeight.md
2245
2251
  },
2252
+ badge: {
2253
+ minWidth: 18,
2254
+ height: 18,
2255
+ paddingHorizontal: 6,
2256
+ borderRadius: theme.tokens.radius.full,
2257
+ overflow: "hidden",
2258
+ textAlign: "center",
2259
+ fontSize: 11,
2260
+ lineHeight: 18,
2261
+ fontWeight: fontWeight3(theme.tokens.typography.weight.medium)
2262
+ },
2263
+ shortcut: {
2264
+ opacity: 0.8,
2265
+ fontSize: 12
2266
+ },
2246
2267
  disabled: {
2247
2268
  borderColor: theme.components.button.disabled.border
2248
2269
  },
@@ -2290,7 +2311,8 @@ var sizeMap = {
2290
2311
  function Button({
2291
2312
  children,
2292
2313
  color = "primary",
2293
- variant = "solid",
2314
+ appearance = "solid",
2315
+ shape = "pill",
2294
2316
  disabled = false,
2295
2317
  loading = false,
2296
2318
  loadingText,
@@ -2300,8 +2322,10 @@ function Button({
2300
2322
  onHoverIn,
2301
2323
  onHoverOut,
2302
2324
  size = "md",
2303
- leftIcon,
2304
- rightIcon,
2325
+ iconStart,
2326
+ iconEnd,
2327
+ badge,
2328
+ shortcut,
2305
2329
  fullWidth = false,
2306
2330
  iconOnly: iconOnlyProp = false,
2307
2331
  style,
@@ -2314,12 +2338,15 @@ function Button({
2314
2338
  const { theme } = useTheme();
2315
2339
  const styles = useThemeStyles(createStyles21);
2316
2340
  const config = sizeMap[size];
2317
- const variantTheme = theme.components.button[color][variant];
2341
+ const radius = shape === "square" ? theme.tokens.radius.sm : shape === "rounded" ? theme.tokens.radius.md : theme.tokens.radius.full;
2342
+ const appearanceTheme = theme.components.button[color][appearance];
2318
2343
  const [isHovered, setIsHovered] = useState5(false);
2319
2344
  const [isFocused, setIsFocused] = useState5(false);
2345
+ const [labelWidth, setLabelWidth] = useState5(0);
2320
2346
  const isDisabled = disabled || loading;
2321
- const iconOnly = iconOnlyProp || !children && Boolean(leftIcon || rightIcon);
2347
+ const iconOnly = iconOnlyProp || !children && Boolean(iconStart || iconEnd);
2322
2348
  const content = loading && loadingText ? loadingText : children;
2349
+ const measureLabel = loadingText && children && !iconOnly ? loading ? children : loadingText : void 0;
2323
2350
  devWarning(
2324
2351
  !iconOnly || Boolean(accessibilityLabel),
2325
2352
  "Button: icon-only buttons must provide an accessibilityLabel."
@@ -2345,7 +2372,13 @@ function Button({
2345
2372
  color: iconColor,
2346
2373
  size: resolvedIconSize
2347
2374
  });
2348
- const getInteractionTheme = (pressed) => isDisabled ? theme.components.button.disabled : pressed ? variantTheme.pressed : isHovered ? variantTheme.hover : variantTheme.default;
2375
+ const handleLabelLayout = (event) => {
2376
+ const width = event.nativeEvent.layout.width;
2377
+ setLabelWidth(
2378
+ (currentWidth) => width > currentWidth ? width : currentWidth
2379
+ );
2380
+ };
2381
+ const getInteractionTheme = (pressed) => isDisabled ? theme.components.button.disabled : pressed ? appearanceTheme.pressed : isHovered ? appearanceTheme.hover : appearanceTheme.default;
2349
2382
  return /* @__PURE__ */ jsx23(
2350
2383
  Pressable10,
2351
2384
  {
@@ -2367,6 +2400,7 @@ function Button({
2367
2400
  {
2368
2401
  backgroundColor: interactionTheme.bg,
2369
2402
  borderColor: interactionTheme.border,
2403
+ borderRadius: radius,
2370
2404
  paddingHorizontal: iconOnly ? 0 : config.px,
2371
2405
  paddingVertical: iconOnly ? 0 : config.py,
2372
2406
  width: iconOnly ? config.height : void 0,
@@ -2384,22 +2418,68 @@ function Button({
2384
2418
  const contentColor = interactionTheme.fg;
2385
2419
  return /* @__PURE__ */ jsxs12(Fragment3, { children: [
2386
2420
  loading && /* @__PURE__ */ jsx23(ActivityIndicator, { size: "small", color: contentColor }),
2387
- !loading && leftIcon && renderIcon(leftIcon, contentColor),
2388
- content && !iconOnly && /* @__PURE__ */ jsx23(
2421
+ !loading && iconStart && renderIcon(iconStart, contentColor),
2422
+ content && !iconOnly && /* @__PURE__ */ jsxs12(View19, { style: styles.labelSlot, children: [
2423
+ /* @__PURE__ */ jsx23(
2424
+ Text11,
2425
+ {
2426
+ onLayout: handleLabelLayout,
2427
+ style: [
2428
+ styles.text,
2429
+ labelWidth > 0 && { minWidth: labelWidth },
2430
+ {
2431
+ fontSize: config.fontSize,
2432
+ color: contentColor
2433
+ },
2434
+ textStyle
2435
+ ],
2436
+ children: content
2437
+ }
2438
+ ),
2439
+ measureLabel && /* @__PURE__ */ jsx23(
2440
+ Text11,
2441
+ {
2442
+ accessibilityElementsHidden: true,
2443
+ importantForAccessibility: "no-hide-descendants",
2444
+ onLayout: handleLabelLayout,
2445
+ style: [
2446
+ styles.text,
2447
+ styles.labelMeasure,
2448
+ {
2449
+ fontSize: config.fontSize
2450
+ },
2451
+ textStyle
2452
+ ],
2453
+ children: measureLabel
2454
+ }
2455
+ )
2456
+ ] }),
2457
+ badge && !iconOnly && /* @__PURE__ */ jsx23(
2389
2458
  Text11,
2390
2459
  {
2391
2460
  style: [
2392
- styles.text,
2461
+ styles.badge,
2393
2462
  {
2394
- fontSize: config.fontSize,
2463
+ backgroundColor: `${contentColor}24`,
2395
2464
  color: contentColor
2396
- },
2397
- textStyle
2465
+ }
2466
+ ],
2467
+ children: badge
2468
+ }
2469
+ ),
2470
+ shortcut && !iconOnly && /* @__PURE__ */ jsx23(
2471
+ Text11,
2472
+ {
2473
+ style: [
2474
+ styles.shortcut,
2475
+ {
2476
+ color: contentColor
2477
+ }
2398
2478
  ],
2399
- children: content
2479
+ children: shortcut
2400
2480
  }
2401
2481
  ),
2402
- !loading && rightIcon && renderIcon(rightIcon, contentColor)
2482
+ !loading && iconEnd && renderIcon(iconEnd, contentColor)
2403
2483
  ] });
2404
2484
  }
2405
2485
  }
@@ -2410,7 +2490,7 @@ function Button({
2410
2490
  import { forwardRef as forwardRef2, useEffect as useEffect4 } from "react";
2411
2491
  import { useControllableState as useControllableState3 } from "@vellira-ui/core";
2412
2492
  import { Check } from "@vellira-ui/icons";
2413
- import { Pressable as Pressable11, Text as Text12, View as View19 } from "react-native";
2493
+ import { Pressable as Pressable11, Text as Text12, View as View20 } from "react-native";
2414
2494
 
2415
2495
  // src/primitives/Checkbox/Checkbox.styles.ts
2416
2496
  import { StyleSheet as StyleSheet22 } from "react-native";
@@ -2613,7 +2693,7 @@ var Checkbox = forwardRef2(
2613
2693
  "Checkbox: an accessible label must be provided through label or accessibilityLabel."
2614
2694
  );
2615
2695
  }, [resolvedAccessibilityLabel]);
2616
- return /* @__PURE__ */ jsxs13(View19, { style: styles.container, children: [
2696
+ return /* @__PURE__ */ jsxs13(View20, { style: styles.container, children: [
2617
2697
  /* @__PURE__ */ jsx24(
2618
2698
  Pressable11,
2619
2699
  {
@@ -2639,7 +2719,7 @@ var Checkbox = forwardRef2(
2639
2719
  const checkColor = disabled ? theme.components.checkbox.disabled.fg : pressed && isSelected ? theme.components.checkbox.checked.pressed.fg : theme.components.checkbox.checked.default.fg;
2640
2720
  return /* @__PURE__ */ jsxs13(Fragment4, { children: [
2641
2721
  /* @__PURE__ */ jsx24(
2642
- View19,
2722
+ View20,
2643
2723
  {
2644
2724
  style: [
2645
2725
  styles.box,
@@ -2650,7 +2730,7 @@ var Checkbox = forwardRef2(
2650
2730
  disabled && styles.boxDisabled
2651
2731
  ],
2652
2732
  children: indeterminate ? /* @__PURE__ */ jsx24(
2653
- View19,
2733
+ View20,
2654
2734
  {
2655
2735
  style: [
2656
2736
  styles.indeterminateMark,
@@ -2699,7 +2779,7 @@ Checkbox.displayName = "Checkbox";
2699
2779
 
2700
2780
  // src/primitives/Input/Input.tsx
2701
2781
  import { cloneElement as cloneElement6, forwardRef as forwardRef3, useState as useState6 } from "react";
2702
- import { Pressable as Pressable12, Text as Text13, TextInput, View as View20 } from "react-native";
2782
+ import { Pressable as Pressable12, Text as Text13, TextInput, View as View21 } from "react-native";
2703
2783
 
2704
2784
  // src/primitives/Input/Input.styles.ts
2705
2785
  import { StyleSheet as StyleSheet23 } from "react-native";
@@ -2958,9 +3038,9 @@ var Input = forwardRef3(
2958
3038
  required,
2959
3039
  disabled,
2960
3040
  style: containerStyle,
2961
- children: /* @__PURE__ */ jsxs14(View20, { style: styles.inputWrapper, children: [
3041
+ children: /* @__PURE__ */ jsxs14(View21, { style: styles.inputWrapper, children: [
2962
3042
  leftIcon && /* @__PURE__ */ jsx25(
2963
- View20,
3043
+ View21,
2964
3044
  {
2965
3045
  pointerEvents: "none",
2966
3046
  style: styles.leftIcon,
@@ -3028,7 +3108,7 @@ var Input = forwardRef3(
3028
3108
  )
3029
3109
  }
3030
3110
  ) : showRightIcon && rightIcon && /* @__PURE__ */ jsx25(
3031
- View20,
3111
+ View21,
3032
3112
  {
3033
3113
  pointerEvents: "none",
3034
3114
  style: styles.rightIcon,
@@ -3053,7 +3133,7 @@ import { useControllableState as useControllableState4 } from "@vellira-ui/core"
3053
3133
  import {
3054
3134
  Pressable as Pressable13,
3055
3135
  Text as Text14,
3056
- View as View21
3136
+ View as View22
3057
3137
  } from "react-native";
3058
3138
 
3059
3139
  // src/primitives/Radio/Radio.styles.ts
@@ -3242,7 +3322,7 @@ var Radio = forwardRef4(
3242
3322
  state.pressed && !resolvedDisabled && styles.pressablePressed,
3243
3323
  typeof style === "function" ? style(state) : style
3244
3324
  ];
3245
- return /* @__PURE__ */ jsxs15(View21, { style: [styles.root, containerStyle], children: [
3325
+ return /* @__PURE__ */ jsxs15(View22, { style: [styles.root, containerStyle], children: [
3246
3326
  /* @__PURE__ */ jsxs15(
3247
3327
  Pressable13,
3248
3328
  {
@@ -3260,7 +3340,7 @@ var Radio = forwardRef4(
3260
3340
  style: resolvePressableStyle,
3261
3341
  children: [
3262
3342
  /* @__PURE__ */ jsx26(
3263
- View21,
3343
+ View22,
3264
3344
  {
3265
3345
  pointerEvents: "none",
3266
3346
  style: [
@@ -3275,7 +3355,7 @@ var Radio = forwardRef4(
3275
3355
  resolvedDisabled && styles.controlDisabled
3276
3356
  ],
3277
3357
  children: resolvedChecked && /* @__PURE__ */ jsx26(
3278
- View21,
3358
+ View22,
3279
3359
  {
3280
3360
  style: [
3281
3361
  styles.indicator,
@@ -3289,7 +3369,7 @@ var Radio = forwardRef4(
3289
3369
  )
3290
3370
  }
3291
3371
  ),
3292
- (label || description) && /* @__PURE__ */ jsxs15(View21, { pointerEvents: "none", style: styles.content, children: [
3372
+ (label || description) && /* @__PURE__ */ jsxs15(View22, { pointerEvents: "none", style: styles.content, children: [
3293
3373
  label && (typeof label === "string" ? /* @__PURE__ */ jsx26(
3294
3374
  Text14,
3295
3375
  {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vellira-ui/react-native",
3
- "version": "2.26.1",
3
+ "version": "2.27.0",
4
4
  "description": "React Native components for Vellira Design System",
5
5
  "author": "Roman Bakurov",
6
6
  "license": "MIT",