@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
@@ -20,7 +20,7 @@
20
20
  */
21
21
 
22
22
  import React, { forwardRef, useCallback, useEffect, useImperativeHandle, useMemo, useRef, useState } from 'react';
23
- import { Dimensions, Pressable, StyleSheet, View } from 'react-native';
23
+ import { Dimensions, Keyboard, Platform, Pressable, StyleSheet, View } from 'react-native';
24
24
  import { Gesture, GestureDetector } from 'react-native-gesture-handler';
25
25
  import Animated, { Extrapolation, interpolate, runOnJS, useAnimatedStyle, useSharedValue, withSpring, withTiming } from 'react-native-reanimated';
26
26
  import { useSafeAreaInsets } from 'react-native-safe-area-context';
@@ -43,6 +43,7 @@ const BottomSheet = /*#__PURE__*/forwardRef((props, ref) => {
43
43
  enablePanDownToClose = true,
44
44
  enableBackdropPress = true,
45
45
  backdropOpacity = 0.5,
46
+ keyboardBehavior = 'none',
46
47
  handleIndicatorStyle,
47
48
  containerStyle,
48
49
  children,
@@ -235,12 +236,45 @@ const BottomSheet = /*#__PURE__*/forwardRef((props, ref) => {
235
236
  });
236
237
  }, [closedY, dragStartY, enablePanDownToClose, handleSnapEnd, minTopY, snapTargets, translateY]);
237
238
 
239
+ // ───────── Keyboard tracking ─────────
240
+ // keyboardOffset is added to translateY in sheetStyle so we don't disturb
241
+ // snap-point math. iOS gets keyboardWillShow/Hide (smoother), Android only
242
+ // emits keyboardDidShow/Hide.
243
+ const keyboardOffset = useSharedValue(0);
244
+ useEffect(() => {
245
+ if (keyboardBehavior === 'none') return;
246
+ const showEvt = Platform.OS === 'ios' ? 'keyboardWillShow' : 'keyboardDidShow';
247
+ const hideEvt = Platform.OS === 'ios' ? 'keyboardWillHide' : 'keyboardDidHide';
248
+ const onShow = e => {
249
+ const h = e.endCoordinates?.height ?? 0;
250
+ keyboardOffset.value = withTiming(-h, {
251
+ duration: 220
252
+ });
253
+ };
254
+ const onHide = () => {
255
+ keyboardOffset.value = withTiming(0, {
256
+ duration: 220
257
+ });
258
+ };
259
+ const showSub = Keyboard.addListener(showEvt, onShow);
260
+ const hideSub = Keyboard.addListener(hideEvt, onHide);
261
+ return () => {
262
+ showSub.remove();
263
+ hideSub.remove();
264
+ };
265
+ }, [keyboardBehavior, keyboardOffset]);
266
+
238
267
  // ───────── Animated styles ─────────
239
- const sheetStyle = useAnimatedStyle(() => ({
240
- transform: [{
241
- translateY: translateY.value
242
- }]
243
- }));
268
+ const sheetStyle = useAnimatedStyle(() => {
269
+ // Don't push past the screen top — keyboard offset is clamped to minTopY.
270
+ const yWithKb = translateY.value + keyboardOffset.value;
271
+ const clamped = yWithKb < minTopY ? minTopY : yWithKb;
272
+ return {
273
+ transform: [{
274
+ translateY: clamped
275
+ }]
276
+ };
277
+ });
244
278
  const backdropStyle = useAnimatedStyle(() => {
245
279
  // 0 opacity when sheet is closed, full backdropOpacity at minSnap height (and above).
246
280
  const closedAt = screenHeight;
@@ -2,7 +2,7 @@
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, Gradient, useTheme } from "../../theme/index.js";
6
6
  import { usePressAnimation } from "../../hooks/usePressAnimation.js";
7
7
  import { triggerHaptic } from "../../utils/hapticUtils.js";
8
8
  import { Spinner } from "../Spinner/index.js";
@@ -21,6 +21,7 @@ const Button = /*#__PURE__*/forwardRef((props, ref) => {
21
21
  rightIcon,
22
22
  haptic = 'selection',
23
23
  rounded = false,
24
+ gradient,
24
25
  style,
25
26
  textStyle,
26
27
  pressAnimation = true,
@@ -40,9 +41,22 @@ const Button = /*#__PURE__*/forwardRef((props, ref) => {
40
41
  enabled: pressAnimation && isInteractive
41
42
  });
42
43
  const styles = useMemo(() => buildStyles(theme), [theme]);
43
- const sizeStyles = sizeMap[size];
44
+ const sizeStyles = {
45
+ ...sizeMap[size],
46
+ ...(theme.components.button?.[size] ?? {})
47
+ };
44
48
  const toneColors = useMemo(() => toneFor(theme, tone), [theme, tone]);
45
49
  const variantStyles = useMemo(() => variantFor(theme, variant, toneColors, disabled), [theme, variant, toneColors, disabled]);
50
+
51
+ // Resolve gradient: string token → theme.gradients[token]; literal passes through.
52
+ // Skipped when disabled (parity with disabled flat-color treatment).
53
+ const resolvedGradient = useMemo(() => {
54
+ if (!gradient || disabled || variant !== 'solid') return null;
55
+ if (typeof gradient === 'string') {
56
+ return theme.gradients[gradient] ?? null;
57
+ }
58
+ return gradient;
59
+ }, [gradient, disabled, variant, theme.gradients]);
46
60
  const handlePress = event => {
47
61
  if (!isInteractive) return;
48
62
  if (haptic !== false) triggerHaptic(haptic);
@@ -64,7 +78,7 @@ const Button = /*#__PURE__*/forwardRef((props, ref) => {
64
78
  style: [styles.label, {
65
79
  color: variantStyles.textColor,
66
80
  fontSize: sizeStyles.fontSize,
67
- fontWeight: theme.typography.fontWeight.semibold
81
+ ...fontFor(theme, 'semibold')
68
82
  }, textStyle],
69
83
  numberOfLines: 1,
70
84
  children: title
@@ -80,7 +94,7 @@ const Button = /*#__PURE__*/forwardRef((props, ref) => {
80
94
  scale
81
95
  }]
82
96
  }, fullWidth ? styles.fullWidth : null],
83
- children: /*#__PURE__*/_jsx(Pressable, {
97
+ children: /*#__PURE__*/_jsxs(Pressable, {
84
98
  ref: ref,
85
99
  onPress: handlePress,
86
100
  onPressIn: pressIn,
@@ -108,15 +122,20 @@ const Button = /*#__PURE__*/forwardRef((props, ref) => {
108
122
  paddingVertical: sizeStyles.paddingVertical,
109
123
  minHeight: sizeStyles.minHeight,
110
124
  borderRadius: rounded ? theme.radius.full : sizeStyles.borderRadius,
111
- backgroundColor: variantStyles.backgroundColor,
125
+ // Hide solid bg when a gradient layer covers it; preserve outline borders.
126
+ backgroundColor: resolvedGradient ? 'transparent' : variantStyles.backgroundColor,
112
127
  borderWidth: variantStyles.borderWidth,
113
128
  borderColor: variantStyles.borderColor,
114
- opacity: !isInteractive ? 0.55 : 1
129
+ opacity: !isInteractive ? 0.55 : 1,
130
+ overflow: resolvedGradient ? 'hidden' : undefined
115
131
  }, pressed && variant !== 'solid' ? {
116
132
  backgroundColor: theme.colors.surface.pressed
117
133
  } : null, fullWidth ? styles.fullWidth : null, style],
118
134
  ...rest,
119
- children: content
135
+ children: [resolvedGradient ? /*#__PURE__*/_jsx(Gradient, {
136
+ gradient: resolvedGradient,
137
+ style: StyleSheet.absoluteFill
138
+ }) : null, content]
120
139
  })
121
140
  });
122
141
  });
@@ -2,7 +2,7 @@
2
2
 
3
3
  import React, { forwardRef, useMemo } from 'react';
4
4
  import { Animated, Image, Pressable, StyleSheet, View } from 'react-native';
5
- import { useTheme } from "../../theme/index.js";
5
+ import { Gradient, useTheme } from "../../theme/index.js";
6
6
  import { usePressAnimation } from "../../hooks/usePressAnimation.js";
7
7
  import { triggerHaptic } from "../../utils/hapticUtils.js";
8
8
  import { SkeletonContent } from "../Skeleton/index.js";
@@ -29,6 +29,7 @@ const Card = /*#__PURE__*/forwardRef((props, ref) => {
29
29
  imageAspectRatio,
30
30
  imageOverlay,
31
31
  loading = false,
32
+ gradient,
32
33
  onPress,
33
34
  accessibilityLabel,
34
35
  accessibilityHint,
@@ -49,6 +50,11 @@ const Card = /*#__PURE__*/forwardRef((props, ref) => {
49
50
  const styles = useMemo(() => buildStyles(theme), [theme]);
50
51
  const hasImage = Boolean(imageSource);
51
52
  const contentPadding = theme.spacing[paddingMap[padding]];
53
+ const resolvedGradient = useMemo(() => {
54
+ if (!gradient) return null;
55
+ if (typeof gradient === 'string') return theme.gradients[gradient] ?? null;
56
+ return gradient;
57
+ }, [gradient, theme.gradients]);
52
58
  const containerStyle = useMemo(() => {
53
59
  const base = {
54
60
  borderRadius: theme.radius[radius],
@@ -108,7 +114,7 @@ const Card = /*#__PURE__*/forwardRef((props, ref) => {
108
114
  children: footer
109
115
  }) : null]
110
116
  });
111
- const content = hasImage ? /*#__PURE__*/_jsxs(_Fragment, {
117
+ const baseContent = hasImage ? /*#__PURE__*/_jsxs(_Fragment, {
112
118
  children: [/*#__PURE__*/_jsxs(View, {
113
119
  style: styles.imageWrapper,
114
120
  children: [/*#__PURE__*/_jsx(Image, {
@@ -129,6 +135,12 @@ const Card = /*#__PURE__*/forwardRef((props, ref) => {
129
135
  children: innerContent
130
136
  })]
131
137
  }) : innerContent;
138
+ const content = resolvedGradient ? /*#__PURE__*/_jsxs(_Fragment, {
139
+ children: [/*#__PURE__*/_jsx(Gradient, {
140
+ gradient: resolvedGradient,
141
+ style: StyleSheet.absoluteFillObject
142
+ }), baseContent]
143
+ }) : baseContent;
132
144
  let rendered;
133
145
  if (isInteractive) {
134
146
  const handlePress = event => {
@@ -24,7 +24,7 @@
24
24
 
25
25
  import React, { forwardRef, useCallback, useEffect, useImperativeHandle, useMemo, useRef, useState } from 'react';
26
26
  import { Animated, Dimensions, FlatList, Image, Pressable, ScrollView, StyleSheet, Text, View } from 'react-native';
27
- import { useTheme } from "../../theme/index.js";
27
+ import { useTheme, createAnimatedValue } from "../../theme/index.js";
28
28
  import { triggerHaptic } from "../../utils/index.js";
29
29
  import { SkeletonContent } from "../Skeleton/index.js";
30
30
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
@@ -60,7 +60,7 @@ const CarouselInner = /*#__PURE__*/forwardRef((props, ref) => {
60
60
  const resolvedItemWidth = itemWidth === 'screen' ? containerWidth : itemWidth;
61
61
  const slideStride = resolvedItemWidth + spacing;
62
62
  const flatListRef = useRef(null);
63
- const scrollX = useRef(new Animated.Value(0)).current;
63
+ const scrollX = useRef(createAnimatedValue(0)).current;
64
64
  const initialIndex = clamp(isControlled ? controlledIndex : defaultIndex, 0, Math.max(0, data.length - 1));
65
65
  const [currentIndex, setCurrentIndex] = useState(initialIndex);
66
66
 
@@ -381,7 +381,7 @@ const ThumbnailItem = ({
381
381
  onPress,
382
382
  theme
383
383
  }) => {
384
- const scale = useRef(new Animated.Value(isActive ? 1.1 : 1)).current;
384
+ const scale = useRef(createAnimatedValue(isActive ? 1.1 : 1)).current;
385
385
  useEffect(() => {
386
386
  Animated.spring(scale, {
387
387
  toValue: isActive ? 1.1 : 1,
@@ -2,7 +2,7 @@
2
2
 
3
3
  import React, { forwardRef, 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
  const sizeMap = {
@@ -41,10 +41,12 @@ const Checkbox = /*#__PURE__*/forwardRef((props, ref) => {
41
41
  } = props;
42
42
  const theme = useTheme();
43
43
  const styles = useMemo(() => buildStyles(theme), [theme]);
44
- const boxSize = sizeMap[size];
44
+ const boxSize = theme.components.checkbox?.[size]?.boxSize ?? sizeMap[size];
45
+ const checkboxBorderWidth = theme.components.checkbox?.borderWidth ?? 1.5;
46
+ const checkboxLabelGap = theme.components.checkbox?.labelGap ?? 10;
45
47
  const fillColor = toneColor(theme, tone);
46
48
  const isActive = checked || indeterminate;
47
- const progress = useRef(new Animated.Value(isActive ? 1 : 0)).current;
49
+ const progress = useRef(createAnimatedValue(isActive ? 1 : 0)).current;
48
50
  useEffect(() => {
49
51
  Animated.spring(progress, {
50
52
  toValue: isActive ? 1 : 0,
@@ -93,6 +95,7 @@ const Checkbox = /*#__PURE__*/forwardRef((props, ref) => {
93
95
  style: [styles.box, {
94
96
  width: boxSize,
95
97
  height: boxSize,
98
+ borderWidth: checkboxBorderWidth,
96
99
  borderRadius: theme.radius.xs,
97
100
  borderColor,
98
101
  backgroundColor
@@ -123,6 +126,7 @@ const Checkbox = /*#__PURE__*/forwardRef((props, ref) => {
123
126
  })
124
127
  }), label ? /*#__PURE__*/_jsx(Text, {
125
128
  style: [styles.label, {
129
+ marginLeft: checkboxLabelGap,
126
130
  color: disabled ? theme.colors.text.disabled : theme.colors.text.primary,
127
131
  fontSize: theme.typography.fontSize.base
128
132
  }],
@@ -138,7 +142,6 @@ const buildStyles = _theme => StyleSheet.create({
138
142
  alignItems: 'center'
139
143
  },
140
144
  box: {
141
- borderWidth: 1.5,
142
145
  alignItems: 'center',
143
146
  justifyContent: 'center'
144
147
  },
@@ -152,7 +155,6 @@ const buildStyles = _theme => StyleSheet.create({
152
155
  includeFontPadding: false
153
156
  },
154
157
  label: {
155
- marginLeft: 10,
156
158
  flexShrink: 1
157
159
  }
158
160
  });
@@ -2,7 +2,7 @@
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 { SkeletonContent } from "../Skeleton/index.js";
@@ -113,7 +113,16 @@ const Chip = /*#__PURE__*/forwardRef((props, ref) => {
113
113
  enabled: isPressable
114
114
  });
115
115
  const tones = useMemo(() => toneFor(theme, tone), [theme, tone]);
116
- const sz = sizeMap[size];
116
+ const overrides = theme.components.chip?.[size];
117
+ const sz = {
118
+ paddingH: overrides?.paddingHorizontal ?? sizeMap[size].paddingH,
119
+ paddingV: overrides?.paddingVertical ?? sizeMap[size].paddingV,
120
+ fontSize: overrides?.fontSize ?? sizeMap[size].fontSize,
121
+ minHeight: overrides?.minHeight ?? sizeMap[size].minHeight,
122
+ closeSize: overrides?.closeSize ?? sizeMap[size].closeSize,
123
+ closeFont: overrides?.closeFontSize ?? sizeMap[size].closeFont,
124
+ gap: overrides?.gap ?? sizeMap[size].gap
125
+ };
117
126
  const isFilled = variant === 'filled';
118
127
  const backgroundColor = (() => {
119
128
  if (selected) return isFilled ? tones.selectedBg : 'transparent';
@@ -153,7 +162,7 @@ const Chip = /*#__PURE__*/forwardRef((props, ref) => {
153
162
  style: [styles.label, {
154
163
  color: textColor,
155
164
  fontSize: sz.fontSize,
156
- fontWeight: theme.typography.fontWeight.medium
165
+ ...fontFor(theme, 'medium')
157
166
  }, textStyle],
158
167
  numberOfLines: 1,
159
168
  children: label ?? ' '
@@ -179,7 +188,7 @@ const Chip = /*#__PURE__*/forwardRef((props, ref) => {
179
188
  style: {
180
189
  color: textColor,
181
190
  fontSize: sz.closeFont,
182
- fontWeight: theme.typography.fontWeight.bold,
191
+ ...fontFor(theme, 'bold'),
183
192
  lineHeight: sz.closeFont + 2
184
193
  },
185
194
  allowFontScaling: false,
@@ -2,7 +2,7 @@
2
2
 
3
3
  import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
4
4
  import { AccessibilityInfo, Animated, Easing, Modal, 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, Fragment as _Fragment } from "react/jsx-runtime";
8
8
  const DAY_MS = 24 * 60 * 60 * 1000;
@@ -106,14 +106,14 @@ const DatePicker = props => {
106
106
  const [viewMode, setViewMode] = useState('days');
107
107
 
108
108
  // Animations
109
- const backdrop = useRef(new Animated.Value(0)).current;
110
- const sheet = useRef(new Animated.Value(0)).current;
111
- const monthSlide = useRef(new Animated.Value(0)).current;
112
- const monthFade = useRef(new Animated.Value(1)).current;
113
- const selectScale = useRef(new Animated.Value(1)).current;
114
- const viewFade = useRef(new Animated.Value(1)).current;
115
- const viewScale = useRef(new Animated.Value(1)).current;
116
- const headerScale = useRef(new Animated.Value(1)).current;
109
+ const backdrop = useRef(createAnimatedValue(0)).current;
110
+ const sheet = useRef(createAnimatedValue(0)).current;
111
+ const monthSlide = useRef(createAnimatedValue(0)).current;
112
+ const monthFade = useRef(createAnimatedValue(1)).current;
113
+ const selectScale = useRef(createAnimatedValue(1)).current;
114
+ const viewFade = useRef(createAnimatedValue(1)).current;
115
+ const viewScale = useRef(createAnimatedValue(1)).current;
116
+ const headerScale = useRef(createAnimatedValue(1)).current;
117
117
 
118
118
  // Sync anchor / pending when value prop changes.
119
119
  useEffect(() => {
@@ -2,7 +2,7 @@
2
2
 
3
3
  import React, { forwardRef, useCallback, useEffect, useMemo, useRef, useState } from 'react';
4
4
  import { AccessibilityInfo, Animated, Easing, Modal, 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 DAY_MS = 24 * 60 * 60 * 1000;
@@ -91,10 +91,10 @@ const DateRangePicker = /*#__PURE__*/forwardRef((props, ref) => {
91
91
  const [pendingEnd, setPendingEnd] = useState(value.end ? startOfDay(value.end) : null);
92
92
 
93
93
  // Animations
94
- const backdrop = useRef(new Animated.Value(0)).current;
95
- const sheet = useRef(new Animated.Value(0)).current;
96
- const monthSlide = useRef(new Animated.Value(0)).current;
97
- const monthFade = useRef(new Animated.Value(1)).current;
94
+ const backdrop = useRef(createAnimatedValue(0)).current;
95
+ const sheet = useRef(createAnimatedValue(0)).current;
96
+ const monthSlide = useRef(createAnimatedValue(0)).current;
97
+ const monthFade = useRef(createAnimatedValue(1)).current;
98
98
 
99
99
  // Sync external value -> pending state when it changes.
100
100
  useEffect(() => {
@@ -2,7 +2,7 @@
2
2
 
3
3
  import React, { useCallback, useMemo } from 'react';
4
4
  import { ActivityIndicator, 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 { triggerHaptic } from "../../utils/hapticUtils.js";
7
7
  import { Modal } from "../Modal/Modal.js";
8
8
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
@@ -17,11 +17,17 @@ const Dialog = props => {
17
17
  actions,
18
18
  dismissOnAction = true,
19
19
  accessibilityLabel,
20
+ contentStyle,
21
+ containerStyle,
20
22
  testID
21
23
  } = props;
22
24
  const theme = useTheme();
23
25
  const styles = useMemo(() => buildStyles(theme), [theme]);
24
26
  const variantTint = useMemo(() => tintForVariant(theme, variant), [theme, variant]);
27
+ const dialogTokens = theme.components.dialog;
28
+ const iconWrapperSize = dialogTokens?.iconWrapperSize ?? 48;
29
+ const iconWrapperBorderRadius = dialogTokens?.iconWrapperBorderRadius ?? 24;
30
+ const actionButtonMinHeight = dialogTokens?.actionButtonMinHeight ?? 44;
25
31
  const handleAction = useCallback(action => {
26
32
  if (action.loading) return;
27
33
  triggerHaptic('selection');
@@ -35,13 +41,17 @@ const Dialog = props => {
35
41
  onRequestClose: onClose,
36
42
  presentation: "centered",
37
43
  accessibilityLabel: accessibilityLabel ?? title,
44
+ contentStyle: contentStyle,
38
45
  testID: testID,
39
46
  children: /*#__PURE__*/_jsxs(View, {
40
47
  accessibilityRole: 'alertdialog',
41
48
  accessibilityLabel: accessibilityLabel ?? title,
42
- style: styles.container,
49
+ style: [styles.container, containerStyle],
43
50
  children: [icon ? /*#__PURE__*/_jsx(View, {
44
51
  style: [styles.iconWrapper, {
52
+ width: iconWrapperSize,
53
+ height: iconWrapperSize,
54
+ borderRadius: iconWrapperBorderRadius,
45
55
  backgroundColor: variantTint.muted,
46
56
  marginBottom: theme.spacing.md
47
57
  }],
@@ -50,7 +60,7 @@ const Dialog = props => {
50
60
  style: [styles.title, {
51
61
  color: theme.colors.text.primary,
52
62
  fontSize: theme.typography.fontSize.xl,
53
- fontWeight: theme.typography.fontWeight.semibold,
63
+ ...fontFor(theme, 'semibold'),
54
64
  marginBottom: message ? theme.spacing.sm : theme.spacing.md
55
65
  }],
56
66
  accessibilityRole: "header",
@@ -86,6 +96,7 @@ const Dialog = props => {
86
96
  style: ({
87
97
  pressed
88
98
  }) => [styles.actionButton, {
99
+ minHeight: actionButtonMinHeight,
89
100
  backgroundColor: buttonStyle.backgroundColor,
90
101
  borderColor: buttonStyle.borderColor,
91
102
  borderWidth: buttonStyle.borderWidth,
@@ -102,7 +113,7 @@ const Dialog = props => {
102
113
  style: {
103
114
  color: buttonStyle.textColor,
104
115
  fontSize: theme.typography.fontSize.base,
105
- fontWeight: theme.typography.fontWeight.semibold,
116
+ ...fontFor(theme, 'semibold'),
106
117
  textAlign: 'center'
107
118
  },
108
119
  numberOfLines: 1,
@@ -180,9 +191,6 @@ const buildStyles = _theme => StyleSheet.create({
180
191
  alignItems: 'stretch'
181
192
  },
182
193
  iconWrapper: {
183
- width: 48,
184
- height: 48,
185
- borderRadius: 24,
186
194
  alignItems: 'center',
187
195
  justifyContent: 'center',
188
196
  alignSelf: 'center'
@@ -201,8 +209,7 @@ const buildStyles = _theme => StyleSheet.create({
201
209
  actionButton: {
202
210
  flex: 1,
203
211
  alignItems: 'center',
204
- justifyContent: 'center',
205
- minHeight: 44
212
+ justifyContent: 'center'
206
213
  }
207
214
  });
208
215
  export { Dialog };
@@ -2,36 +2,42 @@
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 { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
9
- const sizeFor = (theme, size) => {
10
- switch (size) {
11
- case 'sm':
12
- return {
13
- iconSize: 48,
14
- titleSize: theme.typography.fontSize.lg,
15
- descriptionSize: theme.typography.fontSize.sm,
16
- paddingVertical: theme.spacing.lg
17
- };
18
- case 'lg':
19
- return {
20
- iconSize: 80,
21
- titleSize: theme.typography.fontSize['2xl'],
22
- descriptionSize: theme.typography.fontSize.base,
23
- paddingVertical: theme.spacing['2xl']
24
- };
25
- case 'md':
26
- default:
27
- return {
28
- iconSize: 64,
29
- titleSize: theme.typography.fontSize.xl,
30
- descriptionSize: theme.typography.fontSize.base,
31
- paddingVertical: theme.spacing.xl
32
- };
9
+ const SIZE_FALLBACK = {
10
+ sm: {
11
+ iconSize: 48,
12
+ titleFontSize: 'lg',
13
+ descriptionFontSize: 'sm',
14
+ paddingVertical: 'lg'
15
+ },
16
+ md: {
17
+ iconSize: 64,
18
+ titleFontSize: 'xl',
19
+ descriptionFontSize: 'base',
20
+ paddingVertical: 'xl'
21
+ },
22
+ lg: {
23
+ iconSize: 80,
24
+ titleFontSize: '2xl',
25
+ descriptionFontSize: 'base',
26
+ paddingVertical: '2xl'
33
27
  }
34
28
  };
29
+ const sizeFor = (theme, size) => {
30
+ const tokens = {
31
+ ...SIZE_FALLBACK[size],
32
+ ...(theme.components.emptyState?.[size] ?? {})
33
+ };
34
+ return {
35
+ iconSize: tokens.iconSize,
36
+ titleSize: theme.typography.fontSize[tokens.titleFontSize],
37
+ descriptionSize: theme.typography.fontSize[tokens.descriptionFontSize],
38
+ paddingVertical: theme.spacing[tokens.paddingVertical]
39
+ };
40
+ };
35
41
  const ActionButton = ({
36
42
  action,
37
43
  variant
@@ -110,7 +116,7 @@ const EmptyState = /*#__PURE__*/forwardRef((props, ref) => {
110
116
  }) : null, /*#__PURE__*/_jsx(Text, {
111
117
  style: [styles.title, {
112
118
  fontSize: sz.titleSize,
113
- fontWeight: theme.typography.fontWeight.semibold
119
+ ...fontFor(theme, 'semibold')
114
120
  }],
115
121
  children: title
116
122
  }), description ? /*#__PURE__*/_jsx(Text, {
@@ -183,7 +189,7 @@ const buildActionStyles = theme => StyleSheet.create({
183
189
  },
184
190
  buttonText: {
185
191
  fontSize: theme.typography.fontSize.base,
186
- fontWeight: theme.typography.fontWeight.semibold
192
+ ...fontFor(theme, 'semibold')
187
193
  },
188
194
  buttonTextPrimary: {
189
195
  color: theme.colors.text.inverse
@@ -3,7 +3,7 @@
3
3
  import React, { forwardRef, useCallback, useEffect, useMemo, useRef, useState } from 'react';
4
4
  import { Animated, Easing, Pressable, StyleSheet, Text, View } from 'react-native';
5
5
  import { useSafeAreaInsets } from 'react-native-safe-area-context';
6
- import { useTheme } from "../../theme/index.js";
6
+ import { useTheme, createAnimatedValue } from "../../theme/index.js";
7
7
  import { usePressAnimation } from "../../hooks/usePressAnimation.js";
8
8
  import { triggerHaptic } from "../../utils/hapticUtils.js";
9
9
  import { AppIcon } from "../AppIcon/index.js";
@@ -78,7 +78,7 @@ const FloatingActionButton = /*#__PURE__*/forwardRef((props, ref) => {
78
78
  } = usePressAnimation({
79
79
  enabled: !disabled
80
80
  });
81
- const hideAnim = useRef(new Animated.Value(0)).current;
81
+ const hideAnim = useRef(createAnimatedValue(0)).current;
82
82
  useEffect(() => {
83
83
  if (!hideOnScroll) {
84
84
  hideAnim.setValue(0);
@@ -234,7 +234,7 @@ const FloatingActionButtonGroup = props => {
234
234
  const isOpen = isControlled ? controlledOpen : internalOpen;
235
235
 
236
236
  // Animation drivers
237
- const progress = useRef(new Animated.Value(isOpen ? 1 : 0)).current;
237
+ const progress = useRef(createAnimatedValue(isOpen ? 1 : 0)).current;
238
238
  const itemAnims = useRef([]);
239
239
 
240
240
  // Resize per-item anim array if action count changes
@@ -2,7 +2,7 @@
2
2
 
3
3
  import React, { forwardRef, useEffect, useMemo, useRef } from 'react';
4
4
  import { Animated, StyleSheet, Text, View } from 'react-native';
5
- import { useTheme } from "../../theme/index.js";
5
+ import { fontFor, useTheme, createAnimatedValue } from "../../theme/index.js";
6
6
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
7
7
  const FormField = /*#__PURE__*/forwardRef((props, ref) => {
8
8
  const {
@@ -21,7 +21,7 @@ const FormField = /*#__PURE__*/forwardRef((props, ref) => {
21
21
  } = props;
22
22
  const theme = useTheme();
23
23
  const styles = useMemo(() => buildStyles(theme), [theme]);
24
- const errorOpacity = useRef(new Animated.Value(error ? 1 : 0)).current;
24
+ const errorOpacity = useRef(createAnimatedValue(error ? 1 : 0)).current;
25
25
  useEffect(() => {
26
26
  Animated.timing(errorOpacity, {
27
27
  toValue: error ? 1 : 0,
@@ -92,15 +92,15 @@ const buildStyles = theme => StyleSheet.create({
92
92
  },
93
93
  label: {
94
94
  fontSize: theme.typography.fontSize.sm,
95
- fontWeight: theme.typography.fontWeight.medium,
95
+ ...fontFor(theme, 'medium'),
96
96
  color: theme.colors.text.secondary
97
97
  },
98
98
  labelInline: {
99
- width: '35%'
99
+ width: theme.components.formField?.inlineLabelWidth ?? '35%'
100
100
  },
101
101
  requiredMark: {
102
102
  color: theme.colors.error,
103
- fontWeight: theme.typography.fontWeight.medium
103
+ ...fontFor(theme, 'medium')
104
104
  },
105
105
  inputStacked: {
106
106
  width: '100%'