@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
@@ -0,0 +1,156 @@
1
+ "use strict";
2
+
3
+ import React, { forwardRef } from 'react';
4
+ import { View } from 'react-native';
5
+ import { useTheme } from "../../theme/index.js";
6
+ import { jsx as _jsx } from "react/jsx-runtime";
7
+ const space = (theme, token) => token == null ? undefined : theme.spacing[token];
8
+ export const resolveBoxStyle = (theme, p) => {
9
+ const style = {};
10
+ if (p.p != null) style.padding = space(theme, p.p);
11
+ if (p.px != null) style.paddingHorizontal = space(theme, p.px);
12
+ if (p.py != null) style.paddingVertical = space(theme, p.py);
13
+ if (p.pt != null) style.paddingTop = space(theme, p.pt);
14
+ if (p.pr != null) style.paddingRight = space(theme, p.pr);
15
+ if (p.pb != null) style.paddingBottom = space(theme, p.pb);
16
+ if (p.pl != null) style.paddingLeft = space(theme, p.pl);
17
+ if (p.m != null) style.margin = space(theme, p.m);
18
+ if (p.mx != null) style.marginHorizontal = space(theme, p.mx);
19
+ if (p.my != null) style.marginVertical = space(theme, p.my);
20
+ if (p.mt != null) style.marginTop = space(theme, p.mt);
21
+ if (p.mr != null) style.marginRight = space(theme, p.mr);
22
+ if (p.mb != null) style.marginBottom = space(theme, p.mb);
23
+ if (p.ml != null) style.marginLeft = space(theme, p.ml);
24
+ if (p.gap != null) style.gap = space(theme, p.gap);
25
+ if (p.bg != null) {
26
+ const bgTokens = theme.colors.background;
27
+ style.backgroundColor = bgTokens[p.bg] ?? p.bg;
28
+ }
29
+ if (p.radius != null) style.borderRadius = theme.radius[p.radius];
30
+ if (p.border) {
31
+ style.borderWidth = theme.colors.border.width;
32
+ style.borderColor = theme.colors.border.primary;
33
+ }
34
+ if (p.flex != null) style.flex = p.flex;
35
+ if (p.align != null) style.alignItems = p.align;
36
+ if (p.justify != null) style.justifyContent = p.justify;
37
+ if (p.direction != null) style.flexDirection = p.direction;
38
+ if (p.wrap) style.flexWrap = 'wrap';
39
+ return style;
40
+ };
41
+ const Box = /*#__PURE__*/forwardRef((props, ref) => {
42
+ const theme = useTheme();
43
+ const {
44
+ // layout props consumed by the resolver — kept out of the View spread
45
+ p,
46
+ px,
47
+ py,
48
+ pt,
49
+ pr,
50
+ pb,
51
+ pl,
52
+ m,
53
+ mx,
54
+ my,
55
+ mt,
56
+ mr,
57
+ mb,
58
+ ml,
59
+ gap,
60
+ bg,
61
+ radius,
62
+ border,
63
+ flex,
64
+ align,
65
+ justify,
66
+ direction,
67
+ wrap,
68
+ style,
69
+ children,
70
+ ...viewProps
71
+ } = props;
72
+ const boxStyle = resolveBoxStyle(theme, {
73
+ p,
74
+ px,
75
+ py,
76
+ pt,
77
+ pr,
78
+ pb,
79
+ pl,
80
+ m,
81
+ mx,
82
+ my,
83
+ mt,
84
+ mr,
85
+ mb,
86
+ ml,
87
+ gap,
88
+ bg,
89
+ radius,
90
+ border,
91
+ flex,
92
+ align,
93
+ justify,
94
+ direction,
95
+ wrap
96
+ });
97
+ return /*#__PURE__*/_jsx(View, {
98
+ ref: ref,
99
+ style: [boxStyle, style],
100
+ ...viewProps,
101
+ children: children
102
+ });
103
+ });
104
+ Box.displayName = 'Box';
105
+ /** Vertical flex container with token spacing between children (default gap `md`). */
106
+ const Stack = /*#__PURE__*/forwardRef(({
107
+ gap = 'md',
108
+ ...rest
109
+ }, ref) => /*#__PURE__*/_jsx(Box, {
110
+ ref: ref,
111
+ direction: "column",
112
+ gap: gap,
113
+ ...rest
114
+ }));
115
+ Stack.displayName = 'Stack';
116
+ /** Horizontal flex container (default `align="center"`, gap `sm`). */
117
+ const Row = /*#__PURE__*/forwardRef(({
118
+ gap = 'sm',
119
+ align = 'center',
120
+ ...rest
121
+ }, ref) => /*#__PURE__*/_jsx(Box, {
122
+ ref: ref,
123
+ direction: "row",
124
+ gap: gap,
125
+ align: align,
126
+ ...rest
127
+ }));
128
+ Row.displayName = 'Row';
129
+ /** Fixed gap (`size`) or a flexible push (`flex: 1`) between siblings. */
130
+ const Spacer = ({
131
+ size,
132
+ style,
133
+ testID
134
+ }) => {
135
+ const theme = useTheme();
136
+ if (size != null) {
137
+ const value = theme.spacing[size];
138
+ return /*#__PURE__*/_jsx(View, {
139
+ testID: testID,
140
+ style: [{
141
+ width: value,
142
+ height: value
143
+ }, style]
144
+ });
145
+ }
146
+ return /*#__PURE__*/_jsx(View, {
147
+ testID: testID,
148
+ style: [{
149
+ flex: 1
150
+ }, style]
151
+ });
152
+ };
153
+ Spacer.displayName = 'Spacer';
154
+ export { Box, Stack, Row, Spacer };
155
+ export default Box;
156
+ //# sourceMappingURL=Box.js.map
@@ -0,0 +1,4 @@
1
+ "use strict";
2
+
3
+ export { Box, Stack, Row, Spacer, resolveBoxStyle } from "./Box.js";
4
+ //# sourceMappingURL=index.js.map
@@ -67,7 +67,7 @@ const Button = /*#__PURE__*/forwardRef((props, ref) => {
67
67
  style: styles.contentRow,
68
68
  children: loading ? /*#__PURE__*/_jsx(Spinner, {
69
69
  variant: "circular",
70
- size: "small",
70
+ size: "sm",
71
71
  color: variantStyles.textColor,
72
72
  accessibilityLabel: "Loading"
73
73
  }) : /*#__PURE__*/_jsxs(_Fragment, {
@@ -184,7 +184,7 @@ const toneFor = (theme, tone) => {
184
184
  base: theme.colors.primary,
185
185
  hover: theme.colors.primaryHover,
186
186
  pressed: theme.colors.primaryPressed,
187
- on: theme.colors.text.inverse,
187
+ on: theme.colors.onPrimary,
188
188
  muted: theme.colors.primaryMuted
189
189
  };
190
190
  case 'secondary':
@@ -192,7 +192,7 @@ const toneFor = (theme, tone) => {
192
192
  base: theme.colors.secondary,
193
193
  hover: theme.colors.secondaryHover,
194
194
  pressed: theme.colors.secondaryHover,
195
- on: theme.colors.text.primary,
195
+ on: theme.colors.onSecondary,
196
196
  muted: theme.colors.secondary
197
197
  };
198
198
  case 'success':
@@ -200,7 +200,7 @@ const toneFor = (theme, tone) => {
200
200
  base: theme.colors.success,
201
201
  hover: theme.colors.success,
202
202
  pressed: theme.colors.success,
203
- on: theme.colors.text.inverse,
203
+ on: theme.colors.onSuccess,
204
204
  muted: theme.colors.background.secondary
205
205
  };
206
206
  case 'warning':
@@ -208,15 +208,15 @@ const toneFor = (theme, tone) => {
208
208
  base: theme.colors.warning,
209
209
  hover: theme.colors.warning,
210
210
  pressed: theme.colors.warning,
211
- on: theme.colors.text.inverse,
211
+ on: theme.colors.onWarning,
212
212
  muted: theme.colors.background.secondary
213
213
  };
214
- case 'danger':
214
+ case 'error':
215
215
  return {
216
216
  base: theme.colors.error,
217
217
  hover: theme.colors.error,
218
218
  pressed: theme.colors.error,
219
- on: theme.colors.text.inverse,
219
+ on: theme.colors.onError,
220
220
  muted: theme.colors.background.secondary
221
221
  };
222
222
  case 'neutral':
@@ -437,12 +437,14 @@ const ThumbnailItem = ({
437
437
  }) => {
438
438
  const scale = useRef(createAnimatedValue(isActive ? 1.1 : 1)).current;
439
439
  useEffect(() => {
440
- Animated.spring(scale, {
440
+ const anim = Animated.spring(scale, {
441
441
  toValue: isActive ? 1.1 : 1,
442
442
  useNativeDriver: true,
443
443
  friction: 6,
444
444
  tension: 80
445
- }).start();
445
+ });
446
+ anim.start();
447
+ return () => anim.stop();
446
448
  }, [isActive, scale]);
447
449
  const content = useMemo(() => {
448
450
  if (renderThumbnail) return renderThumbnail(item, index);
@@ -3,6 +3,7 @@
3
3
  import React, { forwardRef, useEffect, useMemo, useRef } from 'react';
4
4
  import { Animated, 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 = {
@@ -26,6 +27,7 @@ const toneColor = (theme, tone) => {
26
27
  const Checkbox = /*#__PURE__*/forwardRef((props, ref) => {
27
28
  const {
28
29
  checked,
30
+ defaultChecked,
29
31
  onChange,
30
32
  indeterminate = false,
31
33
  disabled = false,
@@ -43,22 +45,29 @@ const Checkbox = /*#__PURE__*/forwardRef((props, ref) => {
43
45
  testID,
44
46
  ...rest
45
47
  } = props;
48
+ const [current, setCurrent] = useControllableState({
49
+ value: checked,
50
+ defaultValue: defaultChecked ?? false,
51
+ onChange
52
+ });
46
53
  const theme = useTheme();
47
54
  const styles = useMemo(() => buildStyles(theme), [theme]);
48
55
  const boxSize = theme.components.checkbox?.[size]?.boxSize ?? sizeMap[size];
49
56
  const checkboxBorderWidth = theme.colors.border.width;
50
57
  const checkboxLabelGap = theme.components.checkbox?.labelGap ?? 10;
51
58
  const fillColor = toneColor(theme, tone);
52
- const isActive = checked || indeterminate;
59
+ const isActive = current || indeterminate;
53
60
  const progress = useRef(createAnimatedValue(isActive ? 1 : 0)).current;
54
61
  useEffect(() => {
55
- Animated.spring(progress, {
62
+ const anim = Animated.spring(progress, {
56
63
  toValue: isActive ? 1 : 0,
57
64
  damping: theme.motion.spring.snappy.damping,
58
65
  stiffness: theme.motion.spring.snappy.stiffness,
59
66
  mass: theme.motion.spring.snappy.mass,
60
67
  useNativeDriver: true
61
- }).start();
68
+ });
69
+ anim.start();
70
+ return () => anim.stop();
62
71
  }, [isActive, progress, theme.motion.spring.snappy]);
63
72
  const scale = progress.interpolate({
64
73
  inputRange: [0, 1],
@@ -67,7 +76,7 @@ const Checkbox = /*#__PURE__*/forwardRef((props, ref) => {
67
76
  const handlePress = event => {
68
77
  if (disabled) return;
69
78
  if (haptic !== false && theme.components.checkbox?.pressHaptic) triggerHaptic(haptic);
70
- onChange(!checked);
79
+ setCurrent(!current);
71
80
  rest.onPressOut?.(event);
72
81
  };
73
82
  const accessibleLabel = accessibilityLabel ?? label;
@@ -84,7 +93,7 @@ const Checkbox = /*#__PURE__*/forwardRef((props, ref) => {
84
93
  accessibilityRole: "checkbox",
85
94
  accessibilityLabel: accessibleLabel,
86
95
  accessibilityState: {
87
- checked: indeterminate ? 'mixed' : checked,
96
+ checked: indeterminate ? 'mixed' : current,
88
97
  disabled
89
98
  },
90
99
  testID: testID,
@@ -10,14 +10,14 @@ import { PickerTrigger } from "../PickerTrigger/index.js";
10
10
  /**
11
11
  * DatePicker operates in two modes:
12
12
  *
13
- * 1. **Controlled-modal mode** — pass `visible` (plus `onSelect` / `onClose`)
13
+ * 1. **Controlled-modal mode** — pass `visible` (plus `onChange` / `onClose`)
14
14
  * and own the open state externally. The component renders only the modal.
15
15
  * 2. **Trigger mode** — omit `visible`. The component renders a built-in
16
16
  * PickerTrigger field (label / value / placeholder / chevron / clear /
17
17
  * helper / error / size / variant) and manages its own open state. The
18
18
  * field opens the modal on press and closes it on confirm/cancel.
19
19
  *
20
- * `onSelect` / `onClose` are typed optional to support trigger-only usage
20
+ * `onChange` / `onClose` are typed optional to support trigger-only usage
21
21
  * where the consumer may not need either callback. In controlled-modal mode
22
22
  * they remain semantically required.
23
23
  */
@@ -99,7 +99,7 @@ const buildDecadeCells = anchorYear => {
99
99
  const DatePicker = props => {
100
100
  const {
101
101
  value,
102
- onSelect,
102
+ onChange,
103
103
  onClose,
104
104
  minDate,
105
105
  maxDate,
@@ -174,7 +174,7 @@ const DatePicker = props => {
174
174
  if (open) {
175
175
  backdrop.setValue(0);
176
176
  setNativeValue(sheet, 0);
177
- Animated.parallel([Animated.timing(backdrop, {
177
+ const anim = Animated.parallel([Animated.timing(backdrop, {
178
178
  toValue: 1,
179
179
  duration: theme.motion.duration.normal,
180
180
  easing: Easing.out(Easing.cubic),
@@ -185,7 +185,9 @@ const DatePicker = props => {
185
185
  stiffness: theme.motion.spring.gentle.stiffness,
186
186
  mass: theme.motion.spring.gentle.mass,
187
187
  useNativeDriver: true
188
- })]).start();
188
+ })]);
189
+ anim.start();
190
+ return () => anim.stop();
189
191
  }
190
192
  }, [open, mode, backdrop, sheet, theme.motion]);
191
193
  const disabledIsoSet = useMemo(() => {
@@ -385,9 +387,9 @@ const DatePicker = props => {
385
387
  const handleConfirm = useCallback(() => {
386
388
  if (!pendingDate) return;
387
389
  if (theme.components.datePicker?.haptic) triggerHaptic('notificationSuccess');
388
- onSelect?.(pendingDate);
390
+ onChange?.(pendingDate);
389
391
  handleClose();
390
- }, [handleClose, onSelect, pendingDate, theme.components.datePicker]);
392
+ }, [handleClose, onChange, pendingDate, theme.components.datePicker]);
391
393
  const sheetTranslate = sheet.interpolate({
392
394
  inputRange: [0, 1],
393
395
  outputRange: [320, 0]
@@ -147,10 +147,11 @@ const DateRangePicker = /*#__PURE__*/forwardRef((props, ref) => {
147
147
  // Modal open / close animation. Backdrop opacity uses JS driver — see
148
148
  // Modal.tsx for the Fabric reason. Sheet transform stays native.
149
149
  useEffect(() => {
150
+ let anim;
150
151
  if (open) {
151
152
  backdrop.setValue(0);
152
153
  setNativeValue(sheet, 0);
153
- Animated.parallel([Animated.timing(backdrop, {
154
+ anim = Animated.parallel([Animated.timing(backdrop, {
154
155
  toValue: 1,
155
156
  duration: theme.motion.duration.normal,
156
157
  easing: Easing.out(Easing.cubic),
@@ -161,8 +162,10 @@ const DateRangePicker = /*#__PURE__*/forwardRef((props, ref) => {
161
162
  stiffness: theme.motion.spring.gentle.stiffness,
162
163
  mass: theme.motion.spring.gentle.mass,
163
164
  useNativeDriver: true
164
- })]).start();
165
+ })]);
166
+ anim.start();
165
167
  }
168
+ return () => anim?.stop();
166
169
  }, [open, backdrop, sheet, theme.motion]);
167
170
  const disabledIsoSet = useMemo(() => {
168
171
  const set = new Set();
@@ -144,7 +144,7 @@ const tintForVariant = (theme, variant) => {
144
144
  base: theme.colors.warning,
145
145
  muted: theme.colors.background.secondary
146
146
  };
147
- case 'danger':
147
+ case 'error':
148
148
  return {
149
149
  base: theme.colors.error,
150
150
  muted: theme.colors.background.secondary
@@ -175,7 +175,7 @@ const actionStyleFor = (theme, tone, variant) => {
175
175
  textColor: theme.colors.text.inverse
176
176
  };
177
177
  }
178
- case 'danger':
178
+ case 'error':
179
179
  return {
180
180
  backgroundColor: theme.colors.error,
181
181
  borderColor: 'transparent',
@@ -286,20 +286,24 @@ export const FieldBase = props => {
286
286
  const focusAnim = useRef(createAnimatedValue(focused ? 1 : 0)).current;
287
287
  const errorAnim = useRef(createAnimatedValue(error ? 1 : 0)).current;
288
288
  useEffect(() => {
289
- Animated.timing(focusAnim, {
289
+ const anim = Animated.timing(focusAnim, {
290
290
  toValue: focused ? 1 : 0,
291
291
  duration: theme.motion.duration.fast,
292
292
  easing: Easing.bezier(...theme.motion.easing.standard),
293
293
  useNativeDriver: false
294
- }).start();
294
+ });
295
+ anim.start();
296
+ return () => anim.stop();
295
297
  }, [focused, focusAnim, theme.motion.duration.fast, theme.motion.easing.standard]);
296
298
  useEffect(() => {
297
- Animated.timing(errorAnim, {
299
+ const anim = Animated.timing(errorAnim, {
298
300
  toValue: error ? 1 : 0,
299
301
  duration: theme.motion.duration.fast,
300
302
  easing: Easing.bezier(...theme.motion.easing.standard),
301
303
  useNativeDriver: false
302
- }).start();
304
+ });
305
+ anim.start();
306
+ return () => anim.stop();
303
307
  }, [error, errorAnim, theme.motion.duration.fast, theme.motion.easing.standard]);
304
308
 
305
309
  // Resting border + fill (pre-animation). Error wins over focus when both
@@ -90,12 +90,14 @@ const FloatingActionButton = /*#__PURE__*/forwardRef((props, ref) => {
90
90
  setNativeValue(hideAnim, 0);
91
91
  return;
92
92
  }
93
- Animated.timing(hideAnim, {
93
+ const anim = Animated.timing(hideAnim, {
94
94
  toValue: isScrolling ? 1 : 0,
95
95
  duration: theme.motion.duration.normal,
96
96
  easing: Easing.bezier(...theme.motion.easing.standard),
97
97
  useNativeDriver: true
98
- }).start();
98
+ });
99
+ anim.start();
100
+ return () => anim.stop();
99
101
  }, [hideOnScroll, isScrolling, hideAnim, theme.motion.duration.normal, theme.motion.easing.standard]);
100
102
  const hideTranslateY = hideAnim.interpolate({
101
103
  inputRange: [0, 1],
@@ -271,12 +273,13 @@ const FloatingActionButtonGroup = props => {
271
273
  // eslint-disable-next-line react-hooks/exhaustive-deps
272
274
  }, [actions.length]);
273
275
  useEffect(() => {
274
- Animated.timing(progress, {
276
+ const progressAnim = Animated.timing(progress, {
275
277
  toValue: isOpen ? 1 : 0,
276
278
  duration: theme.motion.duration.normal,
277
279
  easing: Easing.bezier(...theme.motion.easing.standard),
278
280
  useNativeDriver: true
279
- }).start();
281
+ });
282
+ progressAnim.start();
280
283
  const animations = itemAnims.current.map(value => Animated.timing(value, {
281
284
  toValue: isOpen ? 1 : 0,
282
285
  duration: theme.motion.duration.normal,
@@ -285,7 +288,12 @@ const FloatingActionButtonGroup = props => {
285
288
  }));
286
289
  // Reverse stagger order on close so items closest to primary collapse last
287
290
  const ordered = isOpen ? animations : [...animations].reverse();
288
- Animated.stagger(staggerMs, ordered).start();
291
+ const staggerAnim = Animated.stagger(staggerMs, ordered);
292
+ staggerAnim.start();
293
+ return () => {
294
+ progressAnim.stop();
295
+ staggerAnim.stop();
296
+ };
289
297
  }, [isOpen, progress, theme.motion.duration.normal, theme.motion.easing.standard, actions.length, itemAnimsVersion, staggerMs]);
290
298
  const setOpen = useCallback(next => {
291
299
  if (pressHaptic) triggerHaptic('impactLight');
@@ -3,13 +3,15 @@
3
3
  import React, { forwardRef, useEffect, useMemo, useRef } from 'react';
4
4
  import { Animated, StyleSheet, Text, View } from 'react-native';
5
5
  import { fontFor, useTheme, createAnimatedValue } from "../../theme/index.js";
6
- import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
6
+ import { useOptionalFormContext } from "../../form/FormContext.js";
7
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
7
8
  const FormField = /*#__PURE__*/forwardRef((props, ref) => {
8
9
  const {
9
10
  label,
10
11
  helperText,
11
12
  error,
12
13
  required = false,
14
+ name,
13
15
  children,
14
16
  layout = 'stacked',
15
17
  labelStyle,
@@ -22,19 +24,32 @@ const FormField = /*#__PURE__*/forwardRef((props, ref) => {
22
24
  } = props;
23
25
  const theme = useTheme();
24
26
  const styles = useMemo(() => buildStyles(theme), [theme]);
25
- const errorOpacity = useRef(createAnimatedValue(error ? 1 : 0)).current;
27
+ const formCtx = useOptionalFormContext();
28
+ const isConnected = name != null && formCtx != null;
29
+ const field = isConnected ? formCtx.getFieldProps(name) : null;
30
+ const isRenderProp = typeof children === 'function';
31
+
32
+ // Error the FormField renders itself. When connected to an element child the
33
+ // child (Input/Select etc.) shows the injected error, so FormField stays
34
+ // quiet to avoid a duplicate message; the render-prop form keeps it here.
35
+ const ownError = isConnected ? isRenderProp ? field?.error : undefined : error;
36
+ // Error used purely for assistive tech — always reflects the real error.
37
+ const a11yError = isConnected ? field?.error : error;
38
+ const errorOpacity = useRef(createAnimatedValue(ownError ? 1 : 0)).current;
26
39
  useEffect(() => {
27
- Animated.timing(errorOpacity, {
28
- toValue: error ? 1 : 0,
29
- duration: 150,
40
+ const anim = Animated.timing(errorOpacity, {
41
+ toValue: ownError ? 1 : 0,
42
+ duration: theme.motion.duration.fast,
30
43
  useNativeDriver: true
31
- }).start();
32
- }, [error, errorOpacity]);
44
+ });
45
+ anim.start();
46
+ return () => anim.stop();
47
+ }, [ownError, errorOpacity, theme.motion.duration.fast]);
33
48
  const computedAccessibilityLabel = useMemo(() => {
34
49
  if (accessibilityLabel) return accessibilityLabel;
35
50
  if (!label) return undefined;
36
- return error ? `${label}, error: ${error}` : label;
37
- }, [accessibilityLabel, label, error]);
51
+ return a11yError ? `${label}, error: ${a11yError}` : label;
52
+ }, [accessibilityLabel, label, a11yError]);
38
53
  const labelNode = label ? /*#__PURE__*/_jsxs(Text, {
39
54
  style: [styles.label, layout === 'inline' ? styles.labelInline : null, labelStyle],
40
55
  children: [label, required ? /*#__PURE__*/_jsx(Text, {
@@ -43,39 +58,60 @@ const FormField = /*#__PURE__*/forwardRef((props, ref) => {
43
58
  }) : null]
44
59
  }) : null;
45
60
  const inputContainerStyle = layout === 'inline' ? styles.inputInline : styles.inputStacked;
46
- const showError = Boolean(error);
61
+ const showError = Boolean(ownError);
47
62
  const showHelper = !showError && Boolean(helperText);
63
+ const renderedChildren = (() => {
64
+ if (isRenderProp) {
65
+ return field ? children(field) : null;
66
+ }
67
+ if (isConnected && field && /*#__PURE__*/React.isValidElement(children)) {
68
+ const child = children;
69
+ const childOnChangeText = child.props.onChangeText;
70
+ const childOnBlur = child.props.onBlur;
71
+ const childOnFocus = child.props.onFocus;
72
+ return /*#__PURE__*/React.cloneElement(child, {
73
+ value: field.value,
74
+ onChangeText: text => {
75
+ field.onChangeText(text);
76
+ childOnChangeText?.(text);
77
+ },
78
+ onBlur: e => {
79
+ field.onBlur();
80
+ childOnBlur?.(e);
81
+ },
82
+ onFocus: e => {
83
+ field.onFocus();
84
+ childOnFocus?.(e);
85
+ },
86
+ error: field.error,
87
+ ref: node => formCtx.registerField(name, node ?? null)
88
+ });
89
+ }
90
+ return children;
91
+ })();
48
92
  return /*#__PURE__*/_jsxs(View, {
49
93
  ref: ref,
50
94
  style: [layout === 'inline' ? styles.rootInline : styles.rootStacked, containerStyle],
51
95
  accessibilityLabel: computedAccessibilityLabel
52
- // Surface the invalid state to assistive tech via the hint. RN's
53
- // AccessibilityState type does not expose an `invalid` field, so the
54
- // error message itself is folded into the label and hint.
96
+ // RN's AccessibilityState type has no `invalid` field, so the error is
97
+ // folded into the label and surfaced again via the hint.
55
98
  ,
56
- accessibilityHint: error ? error : undefined,
99
+ accessibilityHint: a11yError ? a11yError : undefined,
57
100
  testID: testID,
58
- children: [layout === 'inline' ? /*#__PURE__*/_jsxs(_Fragment, {
59
- children: [labelNode, /*#__PURE__*/_jsx(View, {
60
- style: [inputContainerStyle, inputContainerStyleProp],
61
- children: children
62
- })]
63
- }) : /*#__PURE__*/_jsxs(_Fragment, {
64
- children: [labelNode, /*#__PURE__*/_jsx(View, {
65
- style: [inputContainerStyle, inputContainerStyleProp],
66
- children: children
67
- })]
101
+ children: [labelNode, /*#__PURE__*/_jsx(View, {
102
+ style: [inputContainerStyle, inputContainerStyleProp],
103
+ children: renderedChildren
68
104
  }), showHelper ? /*#__PURE__*/_jsx(Text, {
69
105
  style: [styles.helper, helperStyle],
70
106
  numberOfLines: 2,
71
107
  children: helperText
72
- }) : null, error ? /*#__PURE__*/_jsx(Animated.Text, {
108
+ }) : null, ownError ? /*#__PURE__*/_jsx(Animated.Text, {
73
109
  style: [styles.error, {
74
110
  opacity: errorOpacity
75
111
  }, errorStyle],
76
112
  numberOfLines: 2,
77
113
  accessibilityLiveRegion: "polite",
78
- children: error
114
+ children: ownError
79
115
  }) : null]
80
116
  });
81
117
  });