@webority-technologies/mobile 0.0.21 → 0.0.23

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 (187) hide show
  1. package/lib/commonjs/components/Accordion/Accordion.js +4 -2
  2. package/lib/commonjs/components/Avatar/Avatar.js +4 -2
  3. package/lib/commonjs/components/Badge/Badge.js +5 -5
  4. package/lib/commonjs/components/Banner/Banner.js +8 -4
  5. package/lib/commonjs/components/BottomNavigation/BottomNavigation.js +6 -4
  6. package/lib/commonjs/components/BottomSheet/BottomSheet.js +69 -13
  7. package/lib/commonjs/components/BottomSheet/index.js +6 -0
  8. package/lib/commonjs/components/Box/Box.js +162 -0
  9. package/lib/commonjs/components/Box/index.js +37 -0
  10. package/lib/commonjs/components/Button/Button.js +7 -7
  11. package/lib/commonjs/components/Carousel/Carousel.js +4 -2
  12. package/lib/commonjs/components/Checkbox/Checkbox.js +14 -5
  13. package/lib/commonjs/components/DatePicker/DatePicker.js +9 -7
  14. package/lib/commonjs/components/DateRangePicker/DateRangePicker.js +5 -2
  15. package/lib/commonjs/components/Dialog/Dialog.js +2 -2
  16. package/lib/commonjs/components/FieldBase/FieldBase.js +8 -4
  17. package/lib/commonjs/components/FloatingActionButton/FloatingActionButton.js +13 -5
  18. package/lib/commonjs/components/FormField/FormField.js +61 -25
  19. package/lib/commonjs/components/Input/Input.js +41 -29
  20. package/lib/commonjs/components/KeyboardAwareScrollView/KeyboardAwareScrollView.js +102 -0
  21. package/lib/commonjs/components/KeyboardAwareScrollView/index.js +13 -0
  22. package/lib/commonjs/components/KeyboardToolbar/KeyboardToolbar.js +130 -0
  23. package/lib/commonjs/components/KeyboardToolbar/index.js +13 -0
  24. package/lib/commonjs/components/Modal/Modal.js +17 -6
  25. package/lib/commonjs/components/NumberInput/NumberInput.js +35 -28
  26. package/lib/commonjs/components/OTPInput/OTPInput.js +33 -18
  27. package/lib/commonjs/components/Radio/Radio.js +7 -5
  28. package/lib/commonjs/components/Radio/RadioGroup.js +10 -3
  29. package/lib/commonjs/components/SearchBar/SearchBar.js +4 -2
  30. package/lib/commonjs/components/SegmentedControl/SegmentedControl.js +20 -10
  31. package/lib/commonjs/components/Select/Select.js +33 -32
  32. package/lib/commonjs/components/Skeleton/SkeletonContent.js +5 -2
  33. package/lib/commonjs/components/Slider/Slider.js +42 -26
  34. package/lib/commonjs/components/Spinner/Spinner.js +5 -5
  35. package/lib/commonjs/components/Switch/Switch.js +29 -16
  36. package/lib/commonjs/components/Tabs/Tabs.js +4 -2
  37. package/lib/commonjs/components/Text/Text.js +142 -0
  38. package/lib/commonjs/components/Text/index.js +13 -0
  39. package/lib/commonjs/components/TimePicker/TimePicker.js +10 -7
  40. package/lib/commonjs/components/Toast/Toast.js +22 -10
  41. package/lib/commonjs/components/Tooltip/Tooltip.js +6 -2
  42. package/lib/commonjs/components/index.js +141 -89
  43. package/lib/commonjs/form/FormContext.js +40 -0
  44. package/lib/commonjs/form/index.js +68 -0
  45. package/lib/commonjs/form/path.js +79 -0
  46. package/lib/commonjs/form/rules.js +67 -0
  47. package/lib/commonjs/form/types.js +2 -0
  48. package/lib/commonjs/form/useField.js +54 -0
  49. package/lib/commonjs/form/useForm.js +316 -0
  50. package/lib/commonjs/hooks/index.js +14 -0
  51. package/lib/commonjs/hooks/useControllableState.js +30 -0
  52. package/lib/commonjs/hooks/useReducedMotion.js +31 -0
  53. package/lib/commonjs/index.js +96 -11
  54. package/lib/commonjs/theme/ThemeContext.js +30 -2
  55. package/lib/commonjs/theme/tokens.js +12 -0
  56. package/lib/module/components/Accordion/Accordion.js +4 -2
  57. package/lib/module/components/Avatar/Avatar.js +4 -2
  58. package/lib/module/components/Badge/Badge.js +5 -5
  59. package/lib/module/components/Banner/Banner.js +8 -4
  60. package/lib/module/components/BottomNavigation/BottomNavigation.js +6 -4
  61. package/lib/module/components/BottomSheet/BottomSheet.js +68 -13
  62. package/lib/module/components/BottomSheet/index.js +1 -1
  63. package/lib/module/components/Box/Box.js +156 -0
  64. package/lib/module/components/Box/index.js +4 -0
  65. package/lib/module/components/Button/Button.js +7 -7
  66. package/lib/module/components/Carousel/Carousel.js +4 -2
  67. package/lib/module/components/Checkbox/Checkbox.js +14 -5
  68. package/lib/module/components/DatePicker/DatePicker.js +9 -7
  69. package/lib/module/components/DateRangePicker/DateRangePicker.js +5 -2
  70. package/lib/module/components/Dialog/Dialog.js +2 -2
  71. package/lib/module/components/FieldBase/FieldBase.js +8 -4
  72. package/lib/module/components/FloatingActionButton/FloatingActionButton.js +13 -5
  73. package/lib/module/components/FormField/FormField.js +62 -26
  74. package/lib/module/components/Input/Input.js +41 -29
  75. package/lib/module/components/KeyboardAwareScrollView/KeyboardAwareScrollView.js +98 -0
  76. package/lib/module/components/KeyboardAwareScrollView/index.js +4 -0
  77. package/lib/module/components/KeyboardToolbar/KeyboardToolbar.js +125 -0
  78. package/lib/module/components/KeyboardToolbar/index.js +4 -0
  79. package/lib/module/components/Modal/Modal.js +17 -6
  80. package/lib/module/components/NumberInput/NumberInput.js +30 -23
  81. package/lib/module/components/OTPInput/OTPInput.js +30 -15
  82. package/lib/module/components/Radio/Radio.js +7 -5
  83. package/lib/module/components/Radio/RadioGroup.js +10 -3
  84. package/lib/module/components/SearchBar/SearchBar.js +4 -2
  85. package/lib/module/components/SegmentedControl/SegmentedControl.js +20 -10
  86. package/lib/module/components/Select/Select.js +33 -32
  87. package/lib/module/components/Skeleton/SkeletonContent.js +5 -2
  88. package/lib/module/components/Slider/Slider.js +42 -26
  89. package/lib/module/components/Spinner/Spinner.js +5 -5
  90. package/lib/module/components/Switch/Switch.js +29 -16
  91. package/lib/module/components/Tabs/Tabs.js +4 -2
  92. package/lib/module/components/Text/Text.js +138 -0
  93. package/lib/module/components/Text/index.js +4 -0
  94. package/lib/module/components/TimePicker/TimePicker.js +10 -7
  95. package/lib/module/components/Toast/Toast.js +22 -10
  96. package/lib/module/components/Tooltip/Tooltip.js +6 -2
  97. package/lib/module/components/index.js +5 -1
  98. package/lib/module/form/FormContext.js +32 -0
  99. package/lib/module/form/index.js +12 -0
  100. package/lib/module/form/path.js +72 -0
  101. package/lib/module/form/rules.js +52 -0
  102. package/lib/module/form/types.js +2 -0
  103. package/lib/module/form/useField.js +49 -0
  104. package/lib/module/form/useForm.js +312 -0
  105. package/lib/module/hooks/index.js +2 -0
  106. package/lib/module/hooks/useControllableState.js +26 -0
  107. package/lib/module/hooks/useReducedMotion.js +27 -0
  108. package/lib/module/index.js +3 -1
  109. package/lib/module/theme/ThemeContext.js +30 -2
  110. package/lib/module/theme/tokens.js +12 -0
  111. package/lib/typescript/commonjs/components/BottomNavigation/BottomNavigation.d.ts +1 -1
  112. package/lib/typescript/commonjs/components/BottomSheet/BottomSheet.d.ts +41 -0
  113. package/lib/typescript/commonjs/components/BottomSheet/index.d.ts +2 -2
  114. package/lib/typescript/commonjs/components/Box/Box.d.ts +60 -0
  115. package/lib/typescript/commonjs/components/Box/index.d.ts +3 -0
  116. package/lib/typescript/commonjs/components/Button/Button.d.ts +1 -1
  117. package/lib/typescript/commonjs/components/Checkbox/Checkbox.d.ts +3 -2
  118. package/lib/typescript/commonjs/components/DatePicker/DatePicker.d.ts +3 -3
  119. package/lib/typescript/commonjs/components/Dialog/Dialog.d.ts +2 -2
  120. package/lib/typescript/commonjs/components/FormField/FormField.d.ts +13 -2
  121. package/lib/typescript/commonjs/components/KeyboardAwareScrollView/KeyboardAwareScrollView.d.ts +20 -0
  122. package/lib/typescript/commonjs/components/KeyboardAwareScrollView/index.d.ts +3 -0
  123. package/lib/typescript/commonjs/components/KeyboardToolbar/KeyboardToolbar.d.ts +29 -0
  124. package/lib/typescript/commonjs/components/KeyboardToolbar/index.d.ts +3 -0
  125. package/lib/typescript/commonjs/components/NumberInput/NumberInput.d.ts +3 -2
  126. package/lib/typescript/commonjs/components/OTPInput/OTPInput.d.ts +3 -2
  127. package/lib/typescript/commonjs/components/Radio/Radio.d.ts +2 -2
  128. package/lib/typescript/commonjs/components/Radio/RadioGroup.d.ts +3 -2
  129. package/lib/typescript/commonjs/components/SegmentedControl/SegmentedControl.d.ts +3 -2
  130. package/lib/typescript/commonjs/components/Slider/Slider.d.ts +6 -4
  131. package/lib/typescript/commonjs/components/Spinner/Spinner.d.ts +1 -1
  132. package/lib/typescript/commonjs/components/Switch/Switch.d.ts +3 -2
  133. package/lib/typescript/commonjs/components/Text/Text.d.ts +25 -0
  134. package/lib/typescript/commonjs/components/Text/index.d.ts +3 -0
  135. package/lib/typescript/commonjs/components/TimePicker/TimePicker.d.ts +3 -3
  136. package/lib/typescript/commonjs/components/index.d.ts +10 -2
  137. package/lib/typescript/commonjs/form/FormContext.d.ts +17 -0
  138. package/lib/typescript/commonjs/form/index.d.ts +9 -0
  139. package/lib/typescript/commonjs/form/path.d.ts +10 -0
  140. package/lib/typescript/commonjs/form/rules.d.ts +31 -0
  141. package/lib/typescript/commonjs/form/types.d.ts +94 -0
  142. package/lib/typescript/commonjs/form/useField.d.ts +27 -0
  143. package/lib/typescript/commonjs/form/useForm.d.ts +10 -0
  144. package/lib/typescript/commonjs/hooks/index.d.ts +3 -0
  145. package/lib/typescript/commonjs/hooks/useControllableState.d.ts +17 -0
  146. package/lib/typescript/commonjs/hooks/useReducedMotion.d.ts +8 -0
  147. package/lib/typescript/commonjs/index.d.ts +4 -2
  148. package/lib/typescript/commonjs/theme/types.d.ts +15 -0
  149. package/lib/typescript/module/components/BottomNavigation/BottomNavigation.d.ts +1 -1
  150. package/lib/typescript/module/components/BottomSheet/BottomSheet.d.ts +41 -0
  151. package/lib/typescript/module/components/BottomSheet/index.d.ts +2 -2
  152. package/lib/typescript/module/components/Box/Box.d.ts +60 -0
  153. package/lib/typescript/module/components/Box/index.d.ts +3 -0
  154. package/lib/typescript/module/components/Button/Button.d.ts +1 -1
  155. package/lib/typescript/module/components/Checkbox/Checkbox.d.ts +3 -2
  156. package/lib/typescript/module/components/DatePicker/DatePicker.d.ts +3 -3
  157. package/lib/typescript/module/components/Dialog/Dialog.d.ts +2 -2
  158. package/lib/typescript/module/components/FormField/FormField.d.ts +13 -2
  159. package/lib/typescript/module/components/KeyboardAwareScrollView/KeyboardAwareScrollView.d.ts +20 -0
  160. package/lib/typescript/module/components/KeyboardAwareScrollView/index.d.ts +3 -0
  161. package/lib/typescript/module/components/KeyboardToolbar/KeyboardToolbar.d.ts +29 -0
  162. package/lib/typescript/module/components/KeyboardToolbar/index.d.ts +3 -0
  163. package/lib/typescript/module/components/NumberInput/NumberInput.d.ts +3 -2
  164. package/lib/typescript/module/components/OTPInput/OTPInput.d.ts +3 -2
  165. package/lib/typescript/module/components/Radio/Radio.d.ts +2 -2
  166. package/lib/typescript/module/components/Radio/RadioGroup.d.ts +3 -2
  167. package/lib/typescript/module/components/SegmentedControl/SegmentedControl.d.ts +3 -2
  168. package/lib/typescript/module/components/Slider/Slider.d.ts +6 -4
  169. package/lib/typescript/module/components/Spinner/Spinner.d.ts +1 -1
  170. package/lib/typescript/module/components/Switch/Switch.d.ts +3 -2
  171. package/lib/typescript/module/components/Text/Text.d.ts +25 -0
  172. package/lib/typescript/module/components/Text/index.d.ts +3 -0
  173. package/lib/typescript/module/components/TimePicker/TimePicker.d.ts +3 -3
  174. package/lib/typescript/module/components/index.d.ts +10 -2
  175. package/lib/typescript/module/form/FormContext.d.ts +17 -0
  176. package/lib/typescript/module/form/index.d.ts +9 -0
  177. package/lib/typescript/module/form/path.d.ts +10 -0
  178. package/lib/typescript/module/form/rules.d.ts +31 -0
  179. package/lib/typescript/module/form/types.d.ts +94 -0
  180. package/lib/typescript/module/form/useField.d.ts +27 -0
  181. package/lib/typescript/module/form/useForm.d.ts +10 -0
  182. package/lib/typescript/module/hooks/index.d.ts +3 -0
  183. package/lib/typescript/module/hooks/useControllableState.d.ts +17 -0
  184. package/lib/typescript/module/hooks/useReducedMotion.d.ts +8 -0
  185. package/lib/typescript/module/index.d.ts +4 -2
  186. package/lib/typescript/module/theme/types.d.ts +15 -0
  187. package/package.json +1 -1
@@ -3,6 +3,7 @@
3
3
  import React, { forwardRef, useEffect, useMemo, useRef } from 'react';
4
4
  import { Animated, Easing, Pressable, StyleSheet, Text, View } from 'react-native';
5
5
  import { useTheme, createAnimatedValue } from "../../theme/index.js";
6
+ import { useControllableState } from "../../hooks/index.js";
6
7
  import { triggerHaptic } from "../../utils/hapticUtils.js";
7
8
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
8
9
  const sizeMap = {
@@ -41,7 +42,8 @@ const toneColor = (theme, tone) => {
41
42
  const Switch = /*#__PURE__*/forwardRef((props, ref) => {
42
43
  const {
43
44
  value,
44
- onValueChange,
45
+ defaultValue,
46
+ onChange,
45
47
  disabled = false,
46
48
  size = 'md',
47
49
  tone = 'primary',
@@ -56,6 +58,11 @@ const Switch = /*#__PURE__*/forwardRef((props, ref) => {
56
58
  testID,
57
59
  ...rest
58
60
  } = props;
61
+ const [current, setCurrent] = useControllableState({
62
+ value,
63
+ defaultValue: defaultValue ?? false,
64
+ onChange
65
+ });
59
66
  const theme = useTheme();
60
67
  const sizeStyles = {
61
68
  ...sizeMap[size],
@@ -65,25 +72,29 @@ const Switch = /*#__PURE__*/forwardRef((props, ref) => {
65
72
  const styles = useMemo(() => buildStyles(theme), [theme]);
66
73
  const offTrackColor = theme.mode === 'dark' ? theme.colors.secondary : theme.colors.surface.disabled;
67
74
  const onTrackColor = toneColor(theme, tone);
68
- const progress = useRef(createAnimatedValue(value ? 1 : 0)).current;
75
+ const progress = useRef(createAnimatedValue(current ? 1 : 0)).current;
69
76
  useEffect(() => {
70
- Animated.spring(progress, {
71
- toValue: value ? 1 : 0,
77
+ const anim = Animated.spring(progress, {
78
+ toValue: current ? 1 : 0,
72
79
  damping: theme.motion.spring.snappy.damping,
73
80
  stiffness: theme.motion.spring.snappy.stiffness,
74
81
  mass: theme.motion.spring.snappy.mass,
75
82
  useNativeDriver: true
76
- }).start();
77
- }, [value, progress, theme.motion.spring.snappy]);
78
- const trackBgAnim = useRef(createAnimatedValue(value ? 1 : 0)).current;
83
+ });
84
+ anim.start();
85
+ return () => anim.stop();
86
+ }, [current, progress, theme.motion.spring.snappy]);
87
+ const trackBgAnim = useRef(createAnimatedValue(current ? 1 : 0)).current;
79
88
  useEffect(() => {
80
- Animated.timing(trackBgAnim, {
81
- toValue: value ? 1 : 0,
89
+ const anim = Animated.timing(trackBgAnim, {
90
+ toValue: current ? 1 : 0,
82
91
  duration: theme.motion.duration.fast,
83
92
  easing: Easing.out(Easing.ease),
84
93
  useNativeDriver: false
85
- }).start();
86
- }, [value, trackBgAnim, theme.motion.duration.fast]);
94
+ });
95
+ anim.start();
96
+ return () => anim.stop();
97
+ }, [current, trackBgAnim, theme.motion.duration.fast]);
87
98
  const offX = sizeStyles.padding;
88
99
  const onX = sizeStyles.trackWidth - sizeStyles.thumbSize - sizeStyles.padding;
89
100
  const translateX = progress.interpolate({
@@ -102,7 +113,7 @@ const Switch = /*#__PURE__*/forwardRef((props, ref) => {
102
113
  isFirstRender.current = false;
103
114
  return;
104
115
  }
105
- Animated.sequence([Animated.spring(bounceScale, {
116
+ const anim = Animated.sequence([Animated.spring(bounceScale, {
106
117
  toValue: 1.15,
107
118
  damping: 10,
108
119
  stiffness: 220,
@@ -114,12 +125,14 @@ const Switch = /*#__PURE__*/forwardRef((props, ref) => {
114
125
  stiffness: 240,
115
126
  mass: 1,
116
127
  useNativeDriver: true
117
- })]).start();
118
- }, [value, bounce, bounceScale]);
128
+ })]);
129
+ anim.start();
130
+ return () => anim.stop();
131
+ }, [current, bounce, bounceScale]);
119
132
  const handlePress = event => {
120
133
  if (disabled) return;
121
134
  if (haptic !== false) triggerHaptic(haptic);
122
- onValueChange(!value);
135
+ setCurrent(!current);
123
136
  rest.onPressOut?.(event);
124
137
  };
125
138
  const accessibleLabel = accessibilityLabel ?? label;
@@ -130,7 +143,7 @@ const Switch = /*#__PURE__*/forwardRef((props, ref) => {
130
143
  accessibilityRole: "switch",
131
144
  accessibilityLabel: accessibleLabel,
132
145
  accessibilityState: {
133
- checked: value,
146
+ checked: current,
134
147
  disabled
135
148
  },
136
149
  testID: testID,
@@ -82,7 +82,7 @@ const Tabs = /*#__PURE__*/forwardRef((props, ref) => {
82
82
  if (!activeLayout) return;
83
83
  if (useProgress) return;
84
84
  const spring = theme.motion.spring.snappy;
85
- Animated.parallel([
85
+ const anim = Animated.parallel([
86
86
  // Both must use the JS driver: width can't run on native, and mixing
87
87
  // drivers on the same view (transform native + width JS) trips RN's
88
88
  // "node already moved to native" guard under the new architecture.
@@ -98,7 +98,9 @@ const Tabs = /*#__PURE__*/forwardRef((props, ref) => {
98
98
  stiffness: spring.stiffness,
99
99
  mass: spring.mass,
100
100
  useNativeDriver: false
101
- })]).start();
101
+ })]);
102
+ anim.start();
103
+ return () => anim.stop();
102
104
  }, [activeLayout, activeKey, indicatorTranslateX, indicatorWidth, theme.motion.spring.snappy, useProgress]);
103
105
  const handleLayout = useCallback(key => e => {
104
106
  const {
@@ -0,0 +1,138 @@
1
+ "use strict";
2
+
3
+ import React, { forwardRef, useMemo } from 'react';
4
+ import { Text as RNText } from 'react-native';
5
+ import { fontFor, useTheme } from "../../theme/index.js";
6
+ import { jsx as _jsx } from "react/jsx-runtime";
7
+ const VARIANTS = {
8
+ display: {
9
+ size: '4xl',
10
+ weight: 'bold',
11
+ line: 'tight',
12
+ color: 'primary',
13
+ heading: true
14
+ },
15
+ h1: {
16
+ size: '3xl',
17
+ weight: 'bold',
18
+ line: 'tight',
19
+ color: 'primary',
20
+ heading: true
21
+ },
22
+ h2: {
23
+ size: '2xl',
24
+ weight: 'semibold',
25
+ line: 'tight',
26
+ color: 'primary',
27
+ heading: true
28
+ },
29
+ h3: {
30
+ size: 'xl',
31
+ weight: 'semibold',
32
+ line: 'tight',
33
+ color: 'primary',
34
+ heading: true
35
+ },
36
+ title: {
37
+ size: 'lg',
38
+ weight: 'semibold',
39
+ line: 'normal',
40
+ color: 'primary'
41
+ },
42
+ body: {
43
+ size: 'base',
44
+ weight: 'normal',
45
+ line: 'normal',
46
+ color: 'primary'
47
+ },
48
+ bodySmall: {
49
+ size: 'sm',
50
+ weight: 'normal',
51
+ line: 'normal',
52
+ color: 'secondary'
53
+ },
54
+ caption: {
55
+ size: 'xs',
56
+ weight: 'normal',
57
+ line: 'normal',
58
+ color: 'tertiary'
59
+ },
60
+ label: {
61
+ size: 'sm',
62
+ weight: 'medium',
63
+ line: 'normal',
64
+ color: 'secondary'
65
+ },
66
+ overline: {
67
+ size: 'xs',
68
+ weight: 'semibold',
69
+ line: 'normal',
70
+ color: 'secondary',
71
+ uppercase: true,
72
+ letterSpacing: 'wide'
73
+ }
74
+ };
75
+ const TEXT_ROLES = {
76
+ primary: true,
77
+ secondary: true,
78
+ tertiary: true,
79
+ inverse: true,
80
+ disabled: true,
81
+ link: true
82
+ };
83
+ const SEMANTIC = {
84
+ success: true,
85
+ warning: true,
86
+ error: true,
87
+ info: true
88
+ };
89
+ const resolveColor = (theme, color) => {
90
+ // Text roles win over the same-named brand colour ('primary' -> text.primary),
91
+ // which is the intent the vast majority of the time for text.
92
+ if (TEXT_ROLES[color]) return theme.colors.text[color];
93
+ if (SEMANTIC[color]) return theme.colors[color];
94
+ return color; // raw colour string
95
+ };
96
+ const Text = /*#__PURE__*/forwardRef((props, ref) => {
97
+ const {
98
+ variant = 'body',
99
+ color,
100
+ weight,
101
+ size,
102
+ align,
103
+ italic,
104
+ underline,
105
+ style,
106
+ children,
107
+ ...rest
108
+ } = props;
109
+ const theme = useTheme();
110
+ const textStyle = useMemo(() => {
111
+ const spec = VARIANTS[variant];
112
+ const fontSize = typeof size === 'number' ? size : theme.typography.fontSize[size ?? spec.size];
113
+ const lineHeight = Math.round(fontSize * theme.typography.lineHeight[spec.line]);
114
+ return {
115
+ fontSize,
116
+ lineHeight,
117
+ color: resolveColor(theme, color ?? spec.color),
118
+ textAlign: align,
119
+ textTransform: spec.uppercase ? 'uppercase' : undefined,
120
+ letterSpacing: spec.letterSpacing ? theme.typography.letterSpacing[spec.letterSpacing] : undefined,
121
+ fontStyle: italic ? 'italic' : undefined,
122
+ textDecorationLine: underline ? 'underline' : undefined,
123
+ ...fontFor(theme, weight ?? spec.weight)
124
+ };
125
+ }, [theme, variant, color, weight, size, align, italic, underline]);
126
+ const heading = VARIANTS[variant].heading;
127
+ return /*#__PURE__*/_jsx(RNText, {
128
+ ref: ref,
129
+ style: [textStyle, style],
130
+ accessibilityRole: heading ? 'header' : rest.accessibilityRole,
131
+ ...rest,
132
+ children: children
133
+ });
134
+ });
135
+ Text.displayName = 'Text';
136
+ export { Text };
137
+ export default Text;
138
+ //# sourceMappingURL=Text.js.map
@@ -0,0 +1,4 @@
1
+ "use strict";
2
+
3
+ export { Text } from "./Text.js";
4
+ //# sourceMappingURL=index.js.map
@@ -11,12 +11,12 @@ import { PickerTrigger } from "../PickerTrigger/PickerTrigger.js";
11
11
  /**
12
12
  * TimePicker supports two modes:
13
13
  *
14
- * 1. Controlled-modal mode — pass `visible`, `onSelect`, `onClose`. The
14
+ * 1. Controlled-modal mode — pass `visible`, `onChange`, `onClose`. The
15
15
  * component renders only the modal sheet and the caller owns open/close
16
16
  * state plus its own trigger UI.
17
17
  * 2. Trigger mode — omit `visible`. The component renders a PickerTrigger
18
18
  * field (label / value / placeholder / chevron / clear / helper / error)
19
- * and manages its own modal open state. `onSelect` is still called on
19
+ * and manages its own modal open state. `onChange` is still called on
20
20
  * confirm.
21
21
  */
22
22
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
@@ -217,7 +217,7 @@ const TimePicker = props => {
217
217
  const {
218
218
  visible,
219
219
  value,
220
- onSelect,
220
+ onChange,
221
221
  onClose,
222
222
  format = '12h',
223
223
  minuteStep = 1,
@@ -304,8 +304,9 @@ const TimePicker = props => {
304
304
  const opacity = useRef(createAnimatedValue(0)).current;
305
305
  const translateY = useRef(createAnimatedValue(40)).current;
306
306
  useEffect(() => {
307
+ let anim;
307
308
  if (open) {
308
- Animated.parallel([
309
+ anim = Animated.parallel([
309
310
  // Backdrop opacity uses JS driver — see Modal.tsx for the Fabric reason.
310
311
  Animated.timing(opacity, {
311
312
  toValue: 1,
@@ -318,11 +319,13 @@ const TimePicker = props => {
318
319
  stiffness: theme.motion.spring.snappy.stiffness,
319
320
  mass: theme.motion.spring.snappy.mass,
320
321
  useNativeDriver: true
321
- })]).start();
322
+ })]);
323
+ anim.start();
322
324
  } else {
323
325
  opacity.setValue(0);
324
326
  setNativeValue(translateY, 40);
325
327
  }
328
+ return () => anim?.stop();
326
329
  }, [open, opacity, translateY, theme.motion]);
327
330
  const announce = useCallback(msg => {
328
331
  if (Platform.OS === 'ios' || Platform.OS === 'android') {
@@ -351,12 +354,12 @@ const TimePicker = props => {
351
354
  const hour24 = to24h(displayHour, period, format);
352
355
  const minute = minutes[minuteIndex] ?? 0;
353
356
  if (theme.components.timePicker?.haptic) triggerHaptic('notificationSuccess');
354
- onSelect?.({
357
+ onChange?.({
355
358
  hour: hour24,
356
359
  minute
357
360
  });
358
361
  handleCloseModal();
359
- }, [hours, hourIndex, periods, periodIndex, minutes, minuteIndex, format, onSelect, handleCloseModal, theme.components.timePicker]);
362
+ }, [hours, hourIndex, periods, periodIndex, minutes, minuteIndex, format, onChange, handleCloseModal, theme.components.timePicker]);
360
363
  const summary = useMemo(() => {
361
364
  const displayHour = hours[hourIndex] ?? 0;
362
365
  const minute = minutes[minuteIndex] ?? 0;
@@ -39,6 +39,18 @@ const Toast = ({
39
39
  const translateX = useRef(createAnimatedValue(0)).current;
40
40
  const opacity = useRef(createAnimatedValue(0)).current;
41
41
  const dismissedRef = useRef(false);
42
+ const stackTranslate = position === 'top' ? index * stackOffset : -index * stackOffset;
43
+ const stackScale = Math.max(1 - index * stackScaleStep, stackMinScale);
44
+
45
+ // The stack offset rides on its own value so the enter spring (translateY)
46
+ // and the layout offset compose once instead of rebuilding a fresh
47
+ // `new Animated.Value` + `Animated.add` node on every render. setNativeValue
48
+ // keeps it in sync after the node has moved to the native driver.
49
+ const stackTranslateY = useRef(createAnimatedValue(stackTranslate)).current;
50
+ useEffect(() => {
51
+ setNativeValue(stackTranslateY, stackTranslate);
52
+ }, [stackTranslate, stackTranslateY]);
53
+ const composedTranslateY = useMemo(() => Animated.add(translateY, stackTranslateY), [translateY, stackTranslateY]);
42
54
  const dismiss = (animateOut = true) => {
43
55
  if (dismissedRef.current) return;
44
56
  dismissedRef.current = true;
@@ -57,7 +69,7 @@ const Toast = ({
57
69
  }
58
70
  };
59
71
  useEffect(() => {
60
- Animated.parallel([Animated.spring(translateY, {
72
+ const enter = Animated.parallel([Animated.spring(translateY, {
61
73
  toValue: 0,
62
74
  damping: enterSpringDamping,
63
75
  stiffness: enterSpringStiffness,
@@ -67,13 +79,17 @@ const Toast = ({
67
79
  toValue: 1,
68
80
  duration: theme.motion.duration.fast,
69
81
  useNativeDriver: true
70
- })]).start();
82
+ })]);
83
+ enter.start();
71
84
  const duration = toast.duration ?? defaultDurationMs;
72
85
  if (duration > 0) {
73
86
  const timer = setTimeout(() => dismiss(true), duration);
74
- return () => clearTimeout(timer);
87
+ return () => {
88
+ enter.stop();
89
+ clearTimeout(timer);
90
+ };
75
91
  }
76
- return undefined;
92
+ return () => enter.stop();
77
93
  // eslint-disable-next-line react-hooks/exhaustive-deps
78
94
  }, []);
79
95
  const panResponder = useMemo(() => PanResponder.create({
@@ -108,11 +124,7 @@ const Toast = ({
108
124
  })]).start();
109
125
  }
110
126
  }
111
- }),
112
- // eslint-disable-next-line react-hooks/exhaustive-deps
113
- []);
114
- const stackTranslate = position === 'top' ? index * stackOffset : -index * stackOffset;
115
- const stackScale = Math.max(1 - index * stackScaleStep, stackMinScale);
127
+ }), [translateX, opacity, swipeDismissThreshold, swipeVelocityThreshold, theme.motion.duration.fast, onDismiss, toast.id]);
116
128
  const handleActionPress = () => {
117
129
  toast.action?.onPress();
118
130
  dismiss(true);
@@ -152,7 +164,7 @@ const Toast = ({
152
164
  shadowColor: theme.shadows.md.shadowColor,
153
165
  opacity,
154
166
  transform: [{
155
- translateY: Animated.add(translateY, new Animated.Value(stackTranslate))
167
+ translateY: composedTranslateY
156
168
  }, {
157
169
  translateX
158
170
  }, {
@@ -102,6 +102,7 @@ const Tooltip = props => {
102
102
  }
103
103
  };
104
104
  }
105
+ let anim;
105
106
  if (visible) {
106
107
  measureAnchor();
107
108
  const enterAnims = [Animated.timing(opacity, {
@@ -118,7 +119,8 @@ const Tooltip = props => {
118
119
  useNativeDriver: true
119
120
  }));
120
121
  }
121
- Animated.parallel(enterAnims).start();
122
+ anim = Animated.parallel(enterAnims);
123
+ anim.start();
122
124
  if (trigger === 'press') {
123
125
  if (autoHideTimer.current) clearTimeout(autoHideTimer.current);
124
126
  autoHideTimer.current = setTimeout(() => {
@@ -138,13 +140,15 @@ const Tooltip = props => {
138
140
  useNativeDriver: true
139
141
  }));
140
142
  }
141
- Animated.parallel(exitAnims).start();
143
+ anim = Animated.parallel(exitAnims);
144
+ anim.start();
142
145
  if (autoHideTimer.current) {
143
146
  clearTimeout(autoHideTimer.current);
144
147
  autoHideTimer.current = null;
145
148
  }
146
149
  }
147
150
  return () => {
151
+ anim?.stop();
148
152
  if (autoHideTimer.current) {
149
153
  clearTimeout(autoHideTimer.current);
150
154
  autoHideTimer.current = null;
@@ -5,8 +5,12 @@ export { Avatar, AvatarGroup } from "./Avatar/index.js";
5
5
  export { Badge } from "./Badge/index.js";
6
6
  export { Banner } from "./Banner/index.js";
7
7
  export { BottomNavigation } from "./BottomNavigation/index.js";
8
- export { BottomSheet } from "./BottomSheet/index.js";
8
+ export { BottomSheet, useBottomSheet } from "./BottomSheet/index.js";
9
9
  export { Button } from "./Button/index.js";
10
+ export { Box, Stack, Row, Spacer } from "./Box/index.js";
11
+ export { Text } from "./Text/index.js";
12
+ export { KeyboardAwareScrollView } from "./KeyboardAwareScrollView/index.js";
13
+ export { KeyboardToolbar } from "./KeyboardToolbar/index.js";
10
14
  export { Card } from "./Card/index.js";
11
15
  export { Carousel } from "./Carousel/index.js";
12
16
  export { Checkbox } from "./Checkbox/index.js";
@@ -0,0 +1,32 @@
1
+ "use strict";
2
+
3
+ import React, { createContext, useContext } from 'react';
4
+ import { jsx as _jsx } from "react/jsx-runtime";
5
+ const FormContext = /*#__PURE__*/createContext(null);
6
+ /**
7
+ * Provides a {@link useForm} instance to descendants so `<FormField name>`,
8
+ * {@link useField} and {@link useFieldArray} can bind by name.
9
+ */
10
+ export const Form = ({
11
+ form,
12
+ children
13
+ }) => /*#__PURE__*/_jsx(FormContext.Provider, {
14
+ value: form,
15
+ children: children
16
+ });
17
+ Form.displayName = 'Form';
18
+
19
+ /** Read the surrounding form. Throws if there is no `<Form>` ancestor. */
20
+ export function useFormContext() {
21
+ const ctx = useContext(FormContext);
22
+ if (!ctx) {
23
+ throw new Error('useFormContext / useField / <FormField name> must be rendered inside a <Form> from @webority-technologies/mobile.');
24
+ }
25
+ return ctx;
26
+ }
27
+
28
+ /** Read the surrounding form, or null when there is no `<Form>` ancestor. */
29
+ export function useOptionalFormContext() {
30
+ return useContext(FormContext);
31
+ }
32
+ //# sourceMappingURL=FormContext.js.map
@@ -0,0 +1,12 @@
1
+ "use strict";
2
+
3
+ export { useForm } from "./useForm.js";
4
+ export { useField, useFieldArray } from "./useField.js";
5
+ export { Form, useFormContext, useOptionalFormContext } from "./FormContext.js";
6
+ export { getPath, setPath, deletePath } from "./path.js";
7
+
8
+ // Validation rule presets (the dependency-free Yup replacement):
9
+ // import { rules } from '@webority-technologies/mobile';
10
+ // validate: { email: [rules.required(), rules.email()] }
11
+ export * as rules from "./rules.js";
12
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,72 @@
1
+ "use strict";
2
+
3
+ /**
4
+ * Immutable get/set/delete for dot- and bracket-notation field paths
5
+ * ("address.city", "phones[0]", "items[2].qty"). Lets a single flat `name`
6
+ * string address nested values and array items, so the form engine can treat
7
+ * every field uniformly regardless of how deep it lives in the value tree.
8
+ */
9
+
10
+ const tokenize = path => {
11
+ const tokens = [];
12
+ const re = /[^.[\]]+/g;
13
+ let m;
14
+ while ((m = re.exec(path)) !== null) {
15
+ const raw = m[0];
16
+ tokens.push(/^\d+$/.test(raw) ? Number(raw) : raw);
17
+ }
18
+ return tokens;
19
+ };
20
+ export const getPath = (obj, path) => {
21
+ const tokens = tokenize(path);
22
+ let cur = obj;
23
+ for (const t of tokens) {
24
+ if (cur == null || typeof cur !== 'object') return undefined;
25
+ cur = cur[t];
26
+ }
27
+ return cur;
28
+ };
29
+ export const setPath = (obj, path, value) => {
30
+ const tokens = tokenize(path);
31
+ if (tokens.length === 0) return obj;
32
+ const root = Array.isArray(obj) ? [...obj] : {
33
+ ...obj
34
+ };
35
+ let cur = root;
36
+ for (let i = 0; i < tokens.length - 1; i++) {
37
+ const t = tokens[i];
38
+ const next = tokens[i + 1];
39
+ const child = cur[t];
40
+ // Clone the existing branch so we never mutate the previous value tree;
41
+ // create the right container shape when the branch is missing.
42
+ const cloned = child != null && typeof child === 'object' ? Array.isArray(child) ? [...child] : {
43
+ ...child
44
+ } : typeof next === 'number' ? [] : {};
45
+ cur[t] = cloned;
46
+ cur = cloned;
47
+ }
48
+ cur[tokens[tokens.length - 1]] = value;
49
+ return root;
50
+ };
51
+ export const deletePath = (obj, path) => {
52
+ const tokens = tokenize(path);
53
+ if (tokens.length === 0) return obj;
54
+ const root = Array.isArray(obj) ? [...obj] : {
55
+ ...obj
56
+ };
57
+ let cur = root;
58
+ for (let i = 0; i < tokens.length - 1; i++) {
59
+ const t = tokens[i];
60
+ const child = cur[t];
61
+ if (child == null || typeof child !== 'object') return root;
62
+ const cloned = Array.isArray(child) ? [...child] : {
63
+ ...child
64
+ };
65
+ cur[t] = cloned;
66
+ cur = cloned;
67
+ }
68
+ const last = tokens[tokens.length - 1];
69
+ if (Array.isArray(cur) && typeof last === 'number') cur.splice(last, 1);else delete cur[last];
70
+ return root;
71
+ };
72
+ //# sourceMappingURL=path.js.map
@@ -0,0 +1,52 @@
1
+ "use strict";
2
+
3
+ /**
4
+ * Validation rule presets — the dependency-free replacement for Yup chains.
5
+ * Each factory returns a {@link ValidationRule}. Rules built on the project's
6
+ * `validators` module skip empty values (so `required()` owns emptiness and you
7
+ * don't get duplicate errors), and accept an optional custom message.
8
+ */
9
+ import { isEmail, isIndianMobile, isPhone, isUrl, isNumeric, isInteger, isAlphanumeric, isStrongPassword, isIndianPincode, isPan, isGstin, isAadhaar, isIfsc } from "../validators/index.js";
10
+ import { getPath } from "./path.js";
11
+ const isEmptyValue = v => v == null || v === '' || Array.isArray(v) && v.length === 0;
12
+ const fromPredicate = (predicate, defaultMsg) => message => value => isEmptyValue(value) || predicate(value) ? undefined : message ?? defaultMsg;
13
+ export const required = (message = 'This field is required') => value => {
14
+ // A required boolean (e.g. "accept terms" checkbox) must be true.
15
+ if (typeof value === 'boolean') return value ? undefined : message;
16
+ return isEmptyValue(value) ? message : undefined;
17
+ };
18
+ export const email = fromPredicate(isEmail, 'Enter a valid email');
19
+ export const mobile = fromPredicate(isIndianMobile, 'Enter a valid mobile number');
20
+ export const phone = fromPredicate(isPhone, 'Enter a valid phone number');
21
+ export const url = fromPredicate(isUrl, 'Enter a valid URL');
22
+ export const numeric = fromPredicate(isNumeric, 'Enter a valid number');
23
+ export const integer = fromPredicate(isInteger, 'Enter a whole number');
24
+ export const alphanumeric = fromPredicate(isAlphanumeric, 'Use letters and numbers only');
25
+ export const pincode = fromPredicate(isIndianPincode, 'Enter a valid 6-digit PIN code');
26
+ export const pan = fromPredicate(isPan, 'Enter a valid PAN');
27
+ export const gstin = fromPredicate(isGstin, 'Enter a valid GSTIN');
28
+ export const aadhaar = fromPredicate(isAadhaar, 'Enter a valid Aadhaar number');
29
+ export const ifsc = fromPredicate(isIfsc, 'Enter a valid IFSC code');
30
+ export const minLength = (length, message) => value => isEmptyValue(value) || String(value).length >= length ? undefined : message ?? `Must be at least ${length} characters`;
31
+ export const maxLength = (length, message) => value => value == null || String(value).length <= length ? undefined : message ?? `Must be at most ${length} characters`;
32
+ export const min = (n, message) => value => isEmptyValue(value) || Number(value) >= n ? undefined : message ?? `Must be at least ${n}`;
33
+ export const max = (n, message) => value => isEmptyValue(value) || Number(value) <= n ? undefined : message ?? `Must be at most ${n}`;
34
+ export const pattern = (regex, message = 'Invalid format') => value => isEmptyValue(value) || regex.test(String(value)) ? undefined : message;
35
+ export const oneOf = (allowed, message = 'Invalid selection') => value => isEmptyValue(value) || allowed.includes(value) ? undefined : message;
36
+
37
+ /** Cross-field equality (e.g. confirm-password). `otherField` is a field path. */
38
+ export const matches = (otherField, message = 'Values do not match') => (value, allValues) => value === getPath(allValues, otherField) ? undefined : message;
39
+ export const strongPassword = (rules, message = 'Password is too weak') => value => isEmptyValue(value) || isStrongPassword(value, rules) ? undefined : message;
40
+
41
+ /**
42
+ * Wrap any custom check. Return `true` (valid), `false` (invalid → default
43
+ * message), or a string (invalid → that message). Async is supported — return
44
+ * a Promise of the same.
45
+ */
46
+ export const custom = (fn, message = 'Invalid value') => async (value, allValues) => {
47
+ const result = await fn(value, allValues);
48
+ if (result === true) return undefined;
49
+ if (result === false) return message;
50
+ return result;
51
+ };
52
+ //# sourceMappingURL=rules.js.map
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1,49 @@
1
+ "use strict";
2
+
3
+ import { getPath } from "./path.js";
4
+ import { useFormContext } from "./FormContext.js";
5
+ /**
6
+ * Bind a single field by name. Returns everything an input needs; pick the
7
+ * handler your control uses:
8
+ * const email = useField('email');
9
+ * <Input value={email.value} onChangeText={email.onChangeText} onBlur={email.onBlur} error={email.error} />
10
+ * <Select value={country.value} onChange={country.onChange} error={country.error} />
11
+ * <Switch value={!!agree.value} onChange={agree.onChange} />
12
+ */
13
+ export function useField(name) {
14
+ const form = useFormContext();
15
+ return form.getFieldProps(name);
16
+ }
17
+ /**
18
+ * Manage a repeating list field (phone numbers, line items, etc.) by name.
19
+ * Each helper writes the whole array back through the form so validation and
20
+ * dirty-tracking stay correct.
21
+ */
22
+ export function useFieldArray(name) {
23
+ const form = useFormContext();
24
+ const fields = getPath(form.values, name) ?? [];
25
+ const set = next => form.setFieldValue(name, next);
26
+ return {
27
+ fields,
28
+ length: fields.length,
29
+ push: item => set([...fields, item]),
30
+ remove: index => set(fields.filter((_, i) => i !== index)),
31
+ insert: (index, item) => {
32
+ const copy = [...fields];
33
+ copy.splice(index, 0, item);
34
+ set(copy);
35
+ },
36
+ move: (from, to) => {
37
+ const copy = [...fields];
38
+ const [moved] = copy.splice(from, 1);
39
+ copy.splice(to, 0, moved);
40
+ set(copy);
41
+ },
42
+ replace: (index, item) => {
43
+ const copy = [...fields];
44
+ copy[index] = item;
45
+ set(copy);
46
+ }
47
+ };
48
+ }
49
+ //# sourceMappingURL=useField.js.map