@webority-technologies/mobile 0.0.7 → 0.0.9

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 (105) hide show
  1. package/lib/commonjs/components/Accordion/Accordion.js +3 -3
  2. package/lib/commonjs/components/Avatar/Avatar.js +1 -1
  3. package/lib/commonjs/components/Badge/Badge.js +24 -14
  4. package/lib/commonjs/components/Banner/Banner.js +2 -2
  5. package/lib/commonjs/components/BottomNavigation/BottomNavigation.js +1 -1
  6. package/lib/commonjs/components/BottomSheet/BottomSheet.js +39 -5
  7. package/lib/commonjs/components/Button/Button.js +25 -6
  8. package/lib/commonjs/components/Card/Card.js +13 -1
  9. package/lib/commonjs/components/Carousel/Carousel.js +2 -2
  10. package/lib/commonjs/components/Checkbox/Checkbox.js +6 -4
  11. package/lib/commonjs/components/Chip/Chip.js +12 -3
  12. package/lib/commonjs/components/DatePicker/DatePicker.js +8 -8
  13. package/lib/commonjs/components/DateRangePicker/DateRangePicker.js +4 -4
  14. package/lib/commonjs/components/Dialog/Dialog.js +15 -8
  15. package/lib/commonjs/components/EmptyState/EmptyState.js +32 -26
  16. package/lib/commonjs/components/FloatingActionButton/FloatingActionButton.js +2 -2
  17. package/lib/commonjs/components/FormField/FormField.js +4 -4
  18. package/lib/commonjs/components/Input/Input.js +18 -10
  19. package/lib/commonjs/components/ListItem/ListItem.js +33 -27
  20. package/lib/commonjs/components/Modal/Modal.js +4 -4
  21. package/lib/commonjs/components/OTPInput/OTPInput.js +7 -4
  22. package/lib/commonjs/components/ProgressBar/ProgressBar.js +2 -2
  23. package/lib/commonjs/components/Radio/Radio.js +8 -7
  24. package/lib/commonjs/components/SearchBar/SearchBar.js +10 -6
  25. package/lib/commonjs/components/SegmentedControl/SegmentedControl.js +2 -2
  26. package/lib/commonjs/components/Select/Select.js +3 -3
  27. package/lib/commonjs/components/Skeleton/Skeleton.js +1 -1
  28. package/lib/commonjs/components/Slider/Slider.js +6 -6
  29. package/lib/commonjs/components/Spinner/Spinner.js +2 -2
  30. package/lib/commonjs/components/Stepper/Stepper.js +3 -3
  31. package/lib/commonjs/components/Switch/Switch.js +33 -4
  32. package/lib/commonjs/components/Tabs/Tabs.js +2 -2
  33. package/lib/commonjs/components/TimePicker/TimePicker.js +3 -3
  34. package/lib/commonjs/components/Toast/Toast.js +19 -14
  35. package/lib/commonjs/components/Tooltip/Tooltip.js +2 -2
  36. package/lib/commonjs/theme/Gradient.js +57 -0
  37. package/lib/commonjs/theme/animatedValue.js +28 -0
  38. package/lib/commonjs/theme/index.js +27 -0
  39. package/lib/commonjs/theme/textStyle.js +37 -0
  40. package/lib/commonjs/theme/tokens.js +260 -2
  41. package/lib/module/components/Accordion/Accordion.js +4 -4
  42. package/lib/module/components/Avatar/Avatar.js +2 -2
  43. package/lib/module/components/Badge/Badge.js +25 -15
  44. package/lib/module/components/Banner/Banner.js +3 -3
  45. package/lib/module/components/BottomNavigation/BottomNavigation.js +2 -2
  46. package/lib/module/components/BottomSheet/BottomSheet.js +40 -6
  47. package/lib/module/components/Button/Button.js +26 -7
  48. package/lib/module/components/Card/Card.js +14 -2
  49. package/lib/module/components/Carousel/Carousel.js +3 -3
  50. package/lib/module/components/Checkbox/Checkbox.js +7 -5
  51. package/lib/module/components/Chip/Chip.js +13 -4
  52. package/lib/module/components/DatePicker/DatePicker.js +9 -9
  53. package/lib/module/components/DateRangePicker/DateRangePicker.js +5 -5
  54. package/lib/module/components/Dialog/Dialog.js +16 -9
  55. package/lib/module/components/EmptyState/EmptyState.js +33 -27
  56. package/lib/module/components/FloatingActionButton/FloatingActionButton.js +3 -3
  57. package/lib/module/components/FormField/FormField.js +5 -5
  58. package/lib/module/components/Input/Input.js +19 -11
  59. package/lib/module/components/ListItem/ListItem.js +34 -28
  60. package/lib/module/components/Modal/Modal.js +5 -5
  61. package/lib/module/components/OTPInput/OTPInput.js +8 -5
  62. package/lib/module/components/ProgressBar/ProgressBar.js +3 -3
  63. package/lib/module/components/Radio/Radio.js +9 -8
  64. package/lib/module/components/SearchBar/SearchBar.js +11 -7
  65. package/lib/module/components/SegmentedControl/SegmentedControl.js +3 -3
  66. package/lib/module/components/Select/Select.js +4 -4
  67. package/lib/module/components/Skeleton/Skeleton.js +2 -2
  68. package/lib/module/components/Slider/Slider.js +7 -7
  69. package/lib/module/components/Spinner/Spinner.js +3 -3
  70. package/lib/module/components/Stepper/Stepper.js +4 -4
  71. package/lib/module/components/Switch/Switch.js +34 -5
  72. package/lib/module/components/Tabs/Tabs.js +3 -3
  73. package/lib/module/components/TimePicker/TimePicker.js +4 -4
  74. package/lib/module/components/Toast/Toast.js +20 -15
  75. package/lib/module/components/Tooltip/Tooltip.js +3 -3
  76. package/lib/module/theme/Gradient.js +50 -0
  77. package/lib/module/theme/animatedValue.js +24 -0
  78. package/lib/module/theme/index.js +3 -0
  79. package/lib/module/theme/textStyle.js +32 -0
  80. package/lib/module/theme/tokens.js +260 -2
  81. package/lib/typescript/commonjs/components/BottomSheet/BottomSheet.d.ts +10 -0
  82. package/lib/typescript/commonjs/components/Button/Button.d.ts +8 -0
  83. package/lib/typescript/commonjs/components/Card/Card.d.ts +8 -0
  84. package/lib/typescript/commonjs/components/Dialog/Dialog.d.ts +5 -0
  85. package/lib/typescript/commonjs/components/Input/Input.d.ts +12 -0
  86. package/lib/typescript/commonjs/components/Switch/Switch.d.ts +5 -0
  87. package/lib/typescript/commonjs/components/Toast/Toast.d.ts +5 -0
  88. package/lib/typescript/commonjs/theme/Gradient.d.ts +11 -0
  89. package/lib/typescript/commonjs/theme/animatedValue.d.ts +21 -0
  90. package/lib/typescript/commonjs/theme/index.d.ts +6 -1
  91. package/lib/typescript/commonjs/theme/textStyle.d.ts +18 -0
  92. package/lib/typescript/commonjs/theme/types.d.ts +178 -0
  93. package/lib/typescript/module/components/BottomSheet/BottomSheet.d.ts +10 -0
  94. package/lib/typescript/module/components/Button/Button.d.ts +8 -0
  95. package/lib/typescript/module/components/Card/Card.d.ts +8 -0
  96. package/lib/typescript/module/components/Dialog/Dialog.d.ts +5 -0
  97. package/lib/typescript/module/components/Input/Input.d.ts +12 -0
  98. package/lib/typescript/module/components/Switch/Switch.d.ts +5 -0
  99. package/lib/typescript/module/components/Toast/Toast.d.ts +5 -0
  100. package/lib/typescript/module/theme/Gradient.d.ts +11 -0
  101. package/lib/typescript/module/theme/animatedValue.d.ts +21 -0
  102. package/lib/typescript/module/theme/index.d.ts +6 -1
  103. package/lib/typescript/module/theme/textStyle.d.ts +18 -0
  104. package/lib/typescript/module/theme/types.d.ts +178 -0
  105. package/package.json +5 -1
@@ -5,7 +5,7 @@ import { Animated, Easing, Pressable, StyleSheet, Text, TextInput, View } from '
5
5
  // eslint-disable-next-line @typescript-eslint/ban-ts-comment
6
6
  // @ts-ignore - react-native-vector-icons ships no bundled types in this version
7
7
  import Feather from 'react-native-vector-icons/Feather';
8
- import { useTheme } from "../../theme/index.js";
8
+ import { createAnimatedValue, fontFor, useTheme } from "../../theme/index.js";
9
9
  import { triggerHaptic } from "../../utils/index.js";
10
10
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
11
11
  const sizeMap = {
@@ -55,6 +55,8 @@ const Input = /*#__PURE__*/forwardRef((props, ref) => {
55
55
  variant = 'outlined',
56
56
  required = false,
57
57
  maxLength,
58
+ format,
59
+ parse,
58
60
  style,
59
61
  inputStyle,
60
62
  labelStyle,
@@ -67,7 +69,10 @@ const Input = /*#__PURE__*/forwardRef((props, ref) => {
67
69
  } = props;
68
70
  const theme = useTheme();
69
71
  const styles = useMemo(() => buildStyles(theme), [theme]);
70
- const sizeStyles = sizeMap[size];
72
+ const sizeStyles = {
73
+ ...sizeMap[size],
74
+ ...(theme.components.input?.[size] ?? {})
75
+ };
71
76
  const [isFocused, setIsFocused] = useState(false);
72
77
  const [isPasswordVisible, setIsPasswordVisible] = useState(false);
73
78
  const hasValue = typeof value === 'string' && value.length > 0;
@@ -77,11 +82,11 @@ const Input = /*#__PURE__*/forwardRef((props, ref) => {
77
82
  const showFloatingLabel = Boolean(label) && !multiline;
78
83
 
79
84
  // Animations
80
- const focusAnim = useRef(new Animated.Value(0)).current; // 0 -> blurred, 1 -> focused
81
- const errorAnim = useRef(new Animated.Value(0)).current; // 0 -> no error, 1 -> error
82
- const labelAnim = useRef(new Animated.Value(shouldFloat ? 1 : 0)).current;
83
- const shakeAnim = useRef(new Animated.Value(0)).current;
84
- const messageAnim = useRef(new Animated.Value(hasError || helperText ? 1 : 0)).current;
85
+ const focusAnim = useRef(createAnimatedValue(0)).current;
86
+ const errorAnim = useRef(createAnimatedValue(0)).current;
87
+ const labelAnim = useRef(createAnimatedValue(shouldFloat ? 1 : 0)).current;
88
+ const shakeAnim = useRef(createAnimatedValue(0)).current;
89
+ const messageAnim = useRef(createAnimatedValue(hasError || helperText ? 1 : 0)).current;
85
90
 
86
91
  // Focus border animation
87
92
  useEffect(() => {
@@ -217,7 +222,7 @@ const Input = /*#__PURE__*/forwardRef((props, ref) => {
217
222
  style: [styles.staticLabel, {
218
223
  color: hasError ? theme.colors.error : isFocused ? theme.colors.border.focus : theme.colors.text.secondary,
219
224
  fontSize: theme.typography.fontSize.sm,
220
- fontWeight: theme.typography.fontWeight.medium,
225
+ ...fontFor(theme, 'medium'),
221
226
  marginBottom: theme.spacing.xxs
222
227
  }, labelStyle],
223
228
  children: [label, required ? /*#__PURE__*/_jsx(Text, {
@@ -251,7 +256,7 @@ const Input = /*#__PURE__*/forwardRef((props, ref) => {
251
256
  left: leftPad,
252
257
  color: labelColor,
253
258
  fontSize: sizeStyles.fontSize,
254
- fontWeight: theme.typography.fontWeight.medium,
259
+ ...fontFor(theme, 'medium'),
255
260
  backgroundColor: shouldFloat && variant === 'outlined' ? theme.colors.background.primary : 'transparent',
256
261
  paddingHorizontal: shouldFloat && variant === 'outlined' ? 4 : 0,
257
262
  transform: [{
@@ -277,8 +282,11 @@ const Input = /*#__PURE__*/forwardRef((props, ref) => {
277
282
  }, inputStyle],
278
283
  placeholder: showFloatingLabel && !shouldFloat ? undefined : placeholder,
279
284
  placeholderTextColor: placeholderTextColor,
280
- value: value,
281
- onChangeText: onChangeText,
285
+ value: format && value != null ? format(value) : value,
286
+ onChangeText: text => {
287
+ if (!onChangeText) return;
288
+ onChangeText(parse ? parse(text) : text);
289
+ },
282
290
  onFocus: handleFocus,
283
291
  onBlur: handleBlur,
284
292
  editable: isEditable,
@@ -2,38 +2,44 @@
2
2
 
3
3
  import React, { forwardRef, useMemo } from 'react';
4
4
  import { Animated, Pressable, StyleSheet, Text, View } from 'react-native';
5
- import { useTheme } from "../../theme/index.js";
5
+ import { fontFor, useTheme } from "../../theme/index.js";
6
6
  import { usePressAnimation } from "../../hooks/usePressAnimation.js";
7
7
  import { triggerHaptic } from "../../utils/hapticUtils.js";
8
8
  import { Swipeable } from "../Swipeable/index.js";
9
9
  import { SkeletonContent } from "../Skeleton/index.js";
10
10
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
11
- const sizeFor = (theme, size) => {
12
- switch (size) {
13
- case 'sm':
14
- return {
15
- paddingVertical: theme.spacing.sm,
16
- titleSize: theme.typography.fontSize.sm,
17
- subtitleSize: theme.typography.fontSize.xs,
18
- minHeight: 44
19
- };
20
- case 'lg':
21
- return {
22
- paddingVertical: theme.spacing.lg,
23
- titleSize: theme.typography.fontSize.lg,
24
- subtitleSize: theme.typography.fontSize.sm,
25
- minHeight: 72
26
- };
27
- case 'md':
28
- default:
29
- return {
30
- paddingVertical: theme.spacing.md,
31
- titleSize: theme.typography.fontSize.base,
32
- subtitleSize: theme.typography.fontSize.sm,
33
- minHeight: 56
34
- };
11
+ const SIZE_FALLBACK = {
12
+ sm: {
13
+ paddingVertical: 'sm',
14
+ titleFontSize: 'sm',
15
+ subtitleFontSize: 'xs',
16
+ minHeight: 44
17
+ },
18
+ md: {
19
+ paddingVertical: 'md',
20
+ titleFontSize: 'base',
21
+ subtitleFontSize: 'sm',
22
+ minHeight: 56
23
+ },
24
+ lg: {
25
+ paddingVertical: 'lg',
26
+ titleFontSize: 'lg',
27
+ subtitleFontSize: 'sm',
28
+ minHeight: 72
35
29
  }
36
30
  };
31
+ const sizeFor = (theme, size) => {
32
+ const tokens = {
33
+ ...SIZE_FALLBACK[size],
34
+ ...(theme.components.listItem?.[size] ?? {})
35
+ };
36
+ return {
37
+ paddingVertical: theme.spacing[tokens.paddingVertical],
38
+ titleSize: theme.typography.fontSize[tokens.titleFontSize],
39
+ subtitleSize: theme.typography.fontSize[tokens.subtitleFontSize],
40
+ minHeight: tokens.minHeight
41
+ };
42
+ };
37
43
  const Chevron = ({
38
44
  color
39
45
  }) => /*#__PURE__*/_jsx(Text, {
@@ -101,7 +107,7 @@ const ListItem = /*#__PURE__*/forwardRef((props, ref) => {
101
107
  children: [/*#__PURE__*/_jsx(Text, {
102
108
  style: [styles.title, {
103
109
  fontSize: sz.titleSize,
104
- fontWeight: theme.typography.fontWeight.medium,
110
+ ...fontFor(theme, 'medium'),
105
111
  color: disabled ? theme.colors.text.disabled : theme.colors.text.primary
106
112
  }],
107
113
  numberOfLines: 1,
@@ -232,11 +238,11 @@ const buildStyles = theme => StyleSheet.create({
232
238
  },
233
239
  subtitle: {
234
240
  marginTop: 2,
235
- fontWeight: theme.typography.fontWeight.normal
241
+ ...fontFor(theme, 'normal')
236
242
  },
237
243
  description: {
238
244
  marginTop: 2,
239
- fontWeight: theme.typography.fontWeight.normal
245
+ ...fontFor(theme, 'normal')
240
246
  }
241
247
  });
242
248
  export { ListItem };
@@ -2,7 +2,7 @@
2
2
 
3
3
  import React, { forwardRef, useCallback, useEffect, useMemo, useRef } from 'react';
4
4
  import { AccessibilityInfo, Animated, Dimensions, findNodeHandle, Modal as RNModal, Pressable, StyleSheet, View } from 'react-native';
5
- import { useTheme } from "../../theme/index.js";
5
+ import { useTheme, createAnimatedValue } from "../../theme/index.js";
6
6
  import { triggerHaptic } from "../../utils/hapticUtils.js";
7
7
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
8
8
  const Modal = /*#__PURE__*/forwardRef((props, ref) => {
@@ -24,10 +24,10 @@ const Modal = /*#__PURE__*/forwardRef((props, ref) => {
24
24
  const theme = useTheme();
25
25
  const duration = animationDuration ?? theme.motion.duration.normal;
26
26
  const screenHeight = Dimensions.get('window').height;
27
- const backdropAnim = useRef(new Animated.Value(0)).current;
28
- const scaleAnim = useRef(new Animated.Value(0.9)).current;
29
- const opacityAnim = useRef(new Animated.Value(0)).current;
30
- const translateYAnim = useRef(new Animated.Value(screenHeight)).current;
27
+ const backdropAnim = useRef(createAnimatedValue(0)).current;
28
+ const scaleAnim = useRef(createAnimatedValue(0.9)).current;
29
+ const opacityAnim = useRef(createAnimatedValue(0)).current;
30
+ const translateYAnim = useRef(createAnimatedValue(screenHeight)).current;
31
31
  const containerRef = useRef(null);
32
32
  const wasVisibleRef = useRef(false);
33
33
  const styles = useMemo(() => buildStyles(theme), [theme]);
@@ -2,7 +2,7 @@
2
2
 
3
3
  import React, { forwardRef, useCallback, useEffect, useImperativeHandle, useMemo, useRef, useState } from 'react';
4
4
  import { Animated, Easing, Pressable, StyleSheet, Text, TextInput, View } from 'react-native';
5
- import { useTheme } from "../../theme/index.js";
5
+ import { fontFor, useTheme, createAnimatedValue } from "../../theme/index.js";
6
6
  import { triggerHaptic } from "../../utils/index.js";
7
7
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
8
8
  const sizeMap = {
@@ -52,11 +52,14 @@ const OTPInput = /*#__PURE__*/forwardRef((props, ref) => {
52
52
  } = props;
53
53
  const theme = useTheme();
54
54
  const styles = useMemo(() => buildStyles(theme), [theme]);
55
- const sizeStyles = sizeMap[size];
55
+ const sizeStyles = {
56
+ ...sizeMap[size],
57
+ ...(theme.components.otpInput?.[size] ?? {})
58
+ };
56
59
  const inputsRef = useRef([]);
57
60
  const [focusedIndex, setFocusedIndex] = useState(-1);
58
61
  const previousErrorRef = useRef(null);
59
- const shake = useRef(new Animated.Value(0)).current;
62
+ const shake = useRef(createAnimatedValue(0)).current;
60
63
  const underlines = useRef(Array.from({
61
64
  length
62
65
  }, () => new Animated.Value(0))).current;
@@ -297,7 +300,7 @@ const OTPInput = /*#__PURE__*/forwardRef((props, ref) => {
297
300
  style: [styles.input, {
298
301
  fontSize: sizeStyles.fontSize,
299
302
  color: theme.colors.text.primary,
300
- fontWeight: theme.typography.fontWeight.semibold
303
+ ...fontFor(theme, 'semibold')
301
304
  }, textStyle]
302
305
  }), secure && isFilled ? /*#__PURE__*/_jsx(View, {
303
306
  pointerEvents: "none",
@@ -306,7 +309,7 @@ const OTPInput = /*#__PURE__*/forwardRef((props, ref) => {
306
309
  style: [{
307
310
  fontSize: sizeStyles.fontSize,
308
311
  color: theme.colors.text.primary,
309
- fontWeight: theme.typography.fontWeight.semibold
312
+ ...fontFor(theme, 'semibold')
310
313
  }, textStyle],
311
314
  children: display
312
315
  })
@@ -2,7 +2,7 @@
2
2
 
3
3
  import React, { forwardRef, useEffect, useMemo, useRef } from 'react';
4
4
  import { Animated, Easing, StyleSheet, View } from 'react-native';
5
- import { useTheme } from "../../theme/index.js";
5
+ import { useTheme, createAnimatedValue } from "../../theme/index.js";
6
6
  import { jsx as _jsx } from "react/jsx-runtime";
7
7
  const toneColor = (theme, tone) => {
8
8
  switch (tone) {
@@ -40,8 +40,8 @@ const ProgressBar = /*#__PURE__*/forwardRef((props, ref) => {
40
40
  } = props;
41
41
  const isIndeterminate = indeterminateProp ?? typeof progress !== 'number';
42
42
  const clamped = clampProgress(progress);
43
- const fillAnim = useRef(new Animated.Value(clamped)).current;
44
- const loopAnim = useRef(new Animated.Value(0)).current;
43
+ const fillAnim = useRef(createAnimatedValue(clamped)).current;
44
+ const loopAnim = useRef(createAnimatedValue(0)).current;
45
45
  const widthRef = useRef(0);
46
46
  const styles = useMemo(() => buildStyles(theme), [theme]);
47
47
  const resolvedRadius = radius ?? theme.radius.full;
@@ -2,7 +2,7 @@
2
2
 
3
3
  import React, { createContext, forwardRef, useContext, useEffect, useMemo, useRef } from 'react';
4
4
  import { Animated, Pressable, StyleSheet, Text, View } from 'react-native';
5
- import { useTheme } from "../../theme/index.js";
5
+ import { useTheme, createAnimatedValue } from "../../theme/index.js";
6
6
  import { triggerHaptic } from "../../utils/hapticUtils.js";
7
7
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
8
8
  export const RadioGroupContext = /*#__PURE__*/createContext(null);
@@ -56,11 +56,12 @@ const Radio = /*#__PURE__*/forwardRef((props, ref) => {
56
56
  const selected = ctx ? ctx.selectedValue === value : !!selectedProp;
57
57
  const disabled = ctx ? ctx.disabled || disabledProp : disabledProp;
58
58
  const fillColor = toneColor(theme, tone);
59
- const {
60
- outer,
61
- inner
62
- } = sizeMap[size];
63
- const progress = useRef(new Animated.Value(selected ? 1 : 0)).current;
59
+ const sizeOverrides = theme.components.radio?.[size];
60
+ const outer = sizeOverrides?.outer ?? sizeMap[size].outer;
61
+ const inner = sizeOverrides?.inner ?? sizeMap[size].inner;
62
+ const radioBorderWidth = theme.components.radio?.borderWidth ?? 1.5;
63
+ const radioLabelGap = theme.components.radio?.labelGap ?? 10;
64
+ const progress = useRef(createAnimatedValue(selected ? 1 : 0)).current;
64
65
  useEffect(() => {
65
66
  Animated.spring(progress, {
66
67
  toValue: selected ? 1 : 0,
@@ -108,6 +109,7 @@ const Radio = /*#__PURE__*/forwardRef((props, ref) => {
108
109
  style: [styles.outer, {
109
110
  width: outer,
110
111
  height: outer,
112
+ borderWidth: radioBorderWidth,
111
113
  borderRadius: outer / 2,
112
114
  borderColor
113
115
  }, circleStyle],
@@ -125,6 +127,7 @@ const Radio = /*#__PURE__*/forwardRef((props, ref) => {
125
127
  })
126
128
  }), label ? /*#__PURE__*/_jsx(Text, {
127
129
  style: [styles.label, {
130
+ marginLeft: radioLabelGap,
128
131
  color: disabled ? theme.colors.text.disabled : theme.colors.text.primary,
129
132
  fontSize: theme.typography.fontSize.base
130
133
  }],
@@ -140,13 +143,11 @@ const buildStyles = _theme => StyleSheet.create({
140
143
  alignItems: 'center'
141
144
  },
142
145
  outer: {
143
- borderWidth: 1.5,
144
146
  alignItems: 'center',
145
147
  justifyContent: 'center'
146
148
  },
147
149
  inner: {},
148
150
  label: {
149
- marginLeft: 10,
150
151
  flexShrink: 1
151
152
  }
152
153
  });
@@ -2,7 +2,7 @@
2
2
 
3
3
  import React, { forwardRef, useCallback, useEffect, useMemo, useRef, useState } from 'react';
4
4
  import { Animated, Easing, Pressable, StyleSheet, Text, TextInput, View } from 'react-native';
5
- import { useTheme } from "../../theme/index.js";
5
+ import { fontFor, useTheme, createAnimatedValue } from "../../theme/index.js";
6
6
  import { triggerHaptic } from "../../utils/hapticUtils.js";
7
7
  import { useDebounce } from "../../hooks/useDebounce.js";
8
8
  import { AppIcon } from "../AppIcon/index.js";
@@ -53,12 +53,16 @@ const SearchBar = /*#__PURE__*/forwardRef((props, ref) => {
53
53
  ...rest
54
54
  } = props;
55
55
  const theme = useTheme();
56
- const sizeStyles = sizeMap[size];
56
+ const sizeStyles = {
57
+ ...sizeMap[size],
58
+ ...(theme.components.searchBar?.[size] ?? {})
59
+ };
60
+ const cancelWidth = theme.components.searchBar?.cancelButtonWidth ?? CANCEL_WIDTH;
57
61
  const styles = useMemo(() => buildStyles(theme), [theme]);
58
62
  const [isFocused, setIsFocused] = useState(false);
59
63
  const [internalValue, setInternalValue] = useState(value);
60
64
  const debouncedValue = useDebounce(internalValue, debounceMs ?? 0);
61
- const cancelAnim = useRef(new Animated.Value(0)).current;
65
+ const cancelAnim = useRef(createAnimatedValue(0)).current;
62
66
 
63
67
  // Keep internal value in sync with controlled value when debouncing.
64
68
  useEffect(() => {
@@ -122,7 +126,7 @@ const SearchBar = /*#__PURE__*/forwardRef((props, ref) => {
122
126
  // Container shrinks left to make room for cancel button on right.
123
127
  const cancelTranslateX = cancelAnim.interpolate({
124
128
  inputRange: [0, 1],
125
- outputRange: [CANCEL_WIDTH, 0]
129
+ outputRange: [cancelWidth, 0]
126
130
  });
127
131
  const cancelOpacity = cancelAnim;
128
132
  return /*#__PURE__*/_jsxs(View, {
@@ -139,7 +143,7 @@ const SearchBar = /*#__PURE__*/forwardRef((props, ref) => {
139
143
  opacity: disabled ? 0.55 : 1,
140
144
  marginRight: cancelAnim.interpolate({
141
145
  inputRange: [0, 1],
142
- outputRange: [0, CANCEL_WIDTH + theme.spacing.sm]
146
+ outputRange: [0, cancelWidth + theme.spacing.sm]
143
147
  })
144
148
  }],
145
149
  accessibilityRole: "search",
@@ -194,7 +198,7 @@ const SearchBar = /*#__PURE__*/forwardRef((props, ref) => {
194
198
  }), showCancel ? /*#__PURE__*/_jsx(Animated.View, {
195
199
  pointerEvents: showCancelButton ? 'auto' : 'none',
196
200
  style: [styles.cancelWrap, {
197
- width: CANCEL_WIDTH,
201
+ width: cancelWidth,
198
202
  transform: [{
199
203
  translateX: cancelTranslateX
200
204
  }],
@@ -210,7 +214,7 @@ const SearchBar = /*#__PURE__*/forwardRef((props, ref) => {
210
214
  style: [styles.cancelText, {
211
215
  color: theme.colors.primary,
212
216
  fontSize: sizeStyles.fontSize,
213
- fontWeight: theme.typography.fontWeight.medium
217
+ ...fontFor(theme, 'medium')
214
218
  }],
215
219
  numberOfLines: 1,
216
220
  children: cancelLabel
@@ -10,7 +10,7 @@
10
10
 
11
11
  import React, { forwardRef, useCallback, useEffect, useMemo, useRef } from 'react';
12
12
  import { Animated, Pressable, StyleSheet, Text, View } from 'react-native';
13
- import { useTheme } from "../../theme/index.js";
13
+ import { useTheme, createAnimatedValue } from "../../theme/index.js";
14
14
  import { triggerHaptic } from "../../utils/index.js";
15
15
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
16
16
  const sizeMap = {
@@ -47,8 +47,8 @@ const SegmentedControl = /*#__PURE__*/forwardRef((props, ref) => {
47
47
 
48
48
  // Total track width — measured from onLayout; thumb width = trackWidth / segments.length.
49
49
  const trackWidthRef = useRef(0);
50
- const thumbTranslateX = useRef(new Animated.Value(0)).current;
51
- const thumbWidth = useRef(new Animated.Value(0)).current;
50
+ const thumbTranslateX = useRef(createAnimatedValue(0)).current;
51
+ const thumbWidth = useRef(createAnimatedValue(0)).current;
52
52
  const activeIndex = Math.max(0, segments.findIndex(s => s.value === value));
53
53
  const animateThumb = useCallback((index, totalWidth) => {
54
54
  if (totalWidth <= 0 || segments.length === 0) return;
@@ -10,7 +10,7 @@
10
10
 
11
11
  import React, { forwardRef, useCallback, useEffect, useMemo, useRef, useState } from 'react';
12
12
  import { Animated, Dimensions, Easing, FlatList, Modal, Pressable, StyleSheet, Text, TextInput, View } from 'react-native';
13
- import { useTheme } from "../../theme/index.js";
13
+ import { useTheme, createAnimatedValue } from "../../theme/index.js";
14
14
  import { triggerHaptic } from "../../utils/index.js";
15
15
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
16
16
  const sizeMap = {
@@ -64,8 +64,8 @@ const Select = /*#__PURE__*/forwardRef((props, ref) => {
64
64
  const sheetMaxHeight = Math.round(screenHeight * 0.7);
65
65
 
66
66
  // Animations: backdrop fade + sheet slide-up.
67
- const backdropAnim = useRef(new Animated.Value(0)).current;
68
- const sheetAnim = useRef(new Animated.Value(sheetMaxHeight)).current;
67
+ const backdropAnim = useRef(createAnimatedValue(0)).current;
68
+ const sheetAnim = useRef(createAnimatedValue(sheetMaxHeight)).current;
69
69
  useEffect(() => {
70
70
  if (open) {
71
71
  Animated.parallel([Animated.timing(backdropAnim, {
@@ -390,7 +390,7 @@ const Chevron = ({
390
390
  size,
391
391
  open
392
392
  }) => {
393
- const rotate = useRef(new Animated.Value(open ? 1 : 0)).current;
393
+ const rotate = useRef(createAnimatedValue(open ? 1 : 0)).current;
394
394
  useEffect(() => {
395
395
  Animated.timing(rotate, {
396
396
  toValue: open ? 1 : 0,
@@ -2,7 +2,7 @@
2
2
 
3
3
  import React, { useEffect, useMemo, useRef, useState } from 'react';
4
4
  import { Animated, Easing, StyleSheet, View } from 'react-native';
5
- import { useTheme } from "../../theme/index.js";
5
+ import { useTheme, createAnimatedValue } from "../../theme/index.js";
6
6
  import { Responsive } from "../../utils/index.js";
7
7
  import { useSkeletonDefaults } from "./SkeletonProvider.js";
8
8
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
@@ -47,7 +47,7 @@ const Skeleton = ({
47
47
  const borderRadius = resolveRadius(theme, resolvedRadiusToken);
48
48
  const resolvedWidth = resolveWidth(width);
49
49
  const resolvedHeight = Responsive.size(height);
50
- const progress = useRef(new Animated.Value(0)).current;
50
+ const progress = useRef(createAnimatedValue(0)).current;
51
51
  const [containerWidth, setContainerWidth] = useState(0);
52
52
  useEffect(() => {
53
53
  progress.setValue(0);
@@ -2,7 +2,7 @@
2
2
 
3
3
  import React, { forwardRef, useCallback, useEffect, useMemo, useRef, useState } from 'react';
4
4
  import { Animated, Easing, PanResponder, Platform, Pressable, StyleSheet, Text, View } from 'react-native';
5
- import { useTheme } from "../../theme/index.js";
5
+ import { useTheme, createAnimatedValue } from "../../theme/index.js";
6
6
  import { triggerHaptic } from "../../utils/index.js";
7
7
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
8
8
  const SIZE_MAP = {
@@ -65,16 +65,16 @@ const Slider = /*#__PURE__*/forwardRef((props, ref) => {
65
65
  const lastReportedHigh = useRef(highRef.current);
66
66
 
67
67
  // Animated x positions (px) for thumbs.
68
- const lowX = useRef(new Animated.Value(0)).current;
69
- const highX = useRef(new Animated.Value(0)).current;
68
+ const lowX = useRef(createAnimatedValue(0)).current;
69
+ const highX = useRef(createAnimatedValue(0)).current;
70
70
 
71
71
  // Press / drag scale animations.
72
- const lowScale = useRef(new Animated.Value(1)).current;
73
- const highScale = useRef(new Animated.Value(1)).current;
72
+ const lowScale = useRef(createAnimatedValue(1)).current;
73
+ const highScale = useRef(createAnimatedValue(1)).current;
74
74
 
75
75
  // Label opacity per thumb.
76
- const lowLabelOpacity = useRef(new Animated.Value(0)).current;
77
- const highLabelOpacity = useRef(new Animated.Value(0)).current;
76
+ const lowLabelOpacity = useRef(createAnimatedValue(0)).current;
77
+ const highLabelOpacity = useRef(createAnimatedValue(0)).current;
78
78
 
79
79
  // Track which thumb is actively dragging (to anchor gesture math).
80
80
  const dragOffsetRef = useRef(0);
@@ -2,7 +2,7 @@
2
2
 
3
3
  import React, { forwardRef, useEffect, useMemo, useRef } from 'react';
4
4
  import { ActivityIndicator, Animated, Easing, StyleSheet, Text, View } from 'react-native';
5
- import { useTheme } from "../../theme/index.js";
5
+ import { useTheme, createAnimatedValue } from "../../theme/index.js";
6
6
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
7
7
  const sizeMap = {
8
8
  small: 20,
@@ -18,7 +18,7 @@ const Dot = ({
18
18
  delay,
19
19
  duration
20
20
  }) => {
21
- const scale = useRef(new Animated.Value(1)).current;
21
+ const scale = useRef(createAnimatedValue(1)).current;
22
22
  useEffect(() => {
23
23
  const animation = Animated.loop(Animated.sequence([Animated.delay(delay), Animated.timing(scale, {
24
24
  toValue: 1.4,
@@ -61,7 +61,7 @@ const Spinner = /*#__PURE__*/forwardRef((props, ref) => {
61
61
  testID
62
62
  } = props;
63
63
  const theme = useTheme();
64
- const fade = useRef(new Animated.Value(0)).current;
64
+ const fade = useRef(createAnimatedValue(0)).current;
65
65
  useEffect(() => {
66
66
  Animated.timing(fade, {
67
67
  toValue: 1,
@@ -2,7 +2,7 @@
2
2
 
3
3
  import React, { forwardRef, useEffect, useMemo, useRef } from 'react';
4
4
  import { Animated, Easing, Pressable, StyleSheet, Text, View } from 'react-native';
5
- import { useTheme } from "../../theme/index.js";
5
+ import { useTheme, createAnimatedValue } from "../../theme/index.js";
6
6
  import { triggerHaptic } from "../../utils/hapticUtils.js";
7
7
  import { SkeletonContent } from "../Skeleton/index.js";
8
8
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
@@ -30,8 +30,8 @@ const StepCircle = ({
30
30
  onPress
31
31
  }) => {
32
32
  const isActive = status === 'active';
33
- const pulseScale = useRef(new Animated.Value(1)).current;
34
- const pulseOpacity = useRef(new Animated.Value(0.5)).current;
33
+ const pulseScale = useRef(createAnimatedValue(1)).current;
34
+ const pulseOpacity = useRef(createAnimatedValue(0.5)).current;
35
35
  useEffect(() => {
36
36
  if (!isActive) {
37
37
  pulseScale.setValue(1);
@@ -176,7 +176,7 @@ const Stepper = /*#__PURE__*/forwardRef((props, ref) => {
176
176
 
177
177
  // Connector progress: animates as activeStep changes.
178
178
  const initialProgress = total <= 1 ? 0 : activeStep / (total - 1);
179
- const progress = useRef(new Animated.Value(initialProgress)).current;
179
+ const progress = useRef(createAnimatedValue(initialProgress)).current;
180
180
  const lastTargetRef = useRef(initialProgress);
181
181
  useEffect(() => {
182
182
  const target = total <= 1 ? 0 : activeStep / (total - 1);
@@ -2,7 +2,7 @@
2
2
 
3
3
  import React, { forwardRef, useEffect, useMemo, useRef } from 'react';
4
4
  import { Animated, Easing, Pressable, StyleSheet, Text, View } from 'react-native';
5
- import { useTheme } from "../../theme/index.js";
5
+ import { useTheme, createAnimatedValue } from "../../theme/index.js";
6
6
  import { triggerHaptic } from "../../utils/hapticUtils.js";
7
7
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
8
8
  const sizeMap = {
@@ -48,6 +48,7 @@ const Switch = /*#__PURE__*/forwardRef((props, ref) => {
48
48
  label,
49
49
  accessibilityLabel,
50
50
  haptic = 'selection',
51
+ bounce = false,
51
52
  style,
52
53
  trackStyle,
53
54
  thumbStyle,
@@ -55,11 +56,15 @@ const Switch = /*#__PURE__*/forwardRef((props, ref) => {
55
56
  ...rest
56
57
  } = props;
57
58
  const theme = useTheme();
58
- const sizeStyles = sizeMap[size];
59
+ const sizeStyles = {
60
+ ...sizeMap[size],
61
+ ...(theme.components.switch?.[size] ?? {})
62
+ };
63
+ const switchThumbColor = theme.components.switch?.thumbColor ?? '#FFFFFF';
59
64
  const styles = useMemo(() => buildStyles(theme), [theme]);
60
65
  const offTrackColor = theme.mode === 'dark' ? theme.colors.secondary : theme.colors.surface.disabled;
61
66
  const onTrackColor = toneColor(theme, tone);
62
- const progress = useRef(new Animated.Value(value ? 1 : 0)).current;
67
+ const progress = useRef(createAnimatedValue(value ? 1 : 0)).current;
63
68
  useEffect(() => {
64
69
  Animated.spring(progress, {
65
70
  toValue: value ? 1 : 0,
@@ -69,7 +74,7 @@ const Switch = /*#__PURE__*/forwardRef((props, ref) => {
69
74
  useNativeDriver: true
70
75
  }).start();
71
76
  }, [value, progress, theme.motion.spring.snappy]);
72
- const trackBgAnim = useRef(new Animated.Value(value ? 1 : 0)).current;
77
+ const trackBgAnim = useRef(createAnimatedValue(value ? 1 : 0)).current;
73
78
  useEffect(() => {
74
79
  Animated.timing(trackBgAnim, {
75
80
  toValue: value ? 1 : 0,
@@ -88,6 +93,28 @@ const Switch = /*#__PURE__*/forwardRef((props, ref) => {
88
93
  inputRange: [0, 1],
89
94
  outputRange: [offTrackColor, onTrackColor]
90
95
  });
96
+ const bounceScale = useRef(createAnimatedValue(1)).current;
97
+ const isFirstRender = useRef(true);
98
+ useEffect(() => {
99
+ if (!bounce) return;
100
+ if (isFirstRender.current) {
101
+ isFirstRender.current = false;
102
+ return;
103
+ }
104
+ Animated.sequence([Animated.spring(bounceScale, {
105
+ toValue: 1.15,
106
+ damping: 10,
107
+ stiffness: 220,
108
+ mass: 1,
109
+ useNativeDriver: true
110
+ }), Animated.spring(bounceScale, {
111
+ toValue: 1,
112
+ damping: 14,
113
+ stiffness: 240,
114
+ mass: 1,
115
+ useNativeDriver: true
116
+ })]).start();
117
+ }, [value, bounce, bounceScale]);
91
118
  const handlePress = event => {
92
119
  if (disabled) return;
93
120
  if (haptic !== false) triggerHaptic(haptic);
@@ -122,11 +149,14 @@ const Switch = /*#__PURE__*/forwardRef((props, ref) => {
122
149
  }, trackStyle],
123
150
  children: /*#__PURE__*/_jsx(Animated.View, {
124
151
  style: [styles.thumb, theme.shadows.sm, {
152
+ backgroundColor: switchThumbColor,
125
153
  width: sizeStyles.thumbSize,
126
154
  height: sizeStyles.thumbSize,
127
155
  borderRadius: sizeStyles.thumbSize / 2,
128
156
  transform: [{
129
157
  translateX
158
+ }, {
159
+ scale: bounceScale
130
160
  }]
131
161
  }, thumbStyle]
132
162
  })
@@ -155,7 +185,6 @@ const buildStyles = _theme => StyleSheet.create({
155
185
  justifyContent: 'center'
156
186
  },
157
187
  thumb: {
158
- backgroundColor: '#FFFFFF',
159
188
  position: 'absolute',
160
189
  top: 2
161
190
  },
@@ -13,7 +13,7 @@
13
13
 
14
14
  import React, { forwardRef, useCallback, useEffect, useMemo, useRef, useState } from 'react';
15
15
  import { Animated, Pressable, ScrollView, StyleSheet, Text, View } from 'react-native';
16
- import { useTheme } from "../../theme/index.js";
16
+ import { useTheme, createAnimatedValue } from "../../theme/index.js";
17
17
  import { triggerHaptic } from "../../utils/index.js";
18
18
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
19
19
  const Tabs = /*#__PURE__*/forwardRef((props, ref) => {
@@ -34,8 +34,8 @@ const Tabs = /*#__PURE__*/forwardRef((props, ref) => {
34
34
 
35
35
  // Per-tab measured layouts (key → {x, width}).
36
36
  const [layouts, setLayouts] = useState({});
37
- const indicatorTranslateX = useRef(new Animated.Value(0)).current;
38
- const indicatorWidth = useRef(new Animated.Value(0)).current;
37
+ const indicatorTranslateX = useRef(createAnimatedValue(0)).current;
38
+ const indicatorWidth = useRef(createAnimatedValue(0)).current;
39
39
  const activeLayout = layouts[activeKey];
40
40
 
41
41
  // Animate indicator whenever activeKey or its layout changes.