@webority-technologies/mobile 0.0.22 → 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 (181) 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 +8 -9
  7. package/lib/commonjs/components/Box/Box.js +162 -0
  8. package/lib/commonjs/components/Box/index.js +37 -0
  9. package/lib/commonjs/components/Button/Button.js +7 -7
  10. package/lib/commonjs/components/Carousel/Carousel.js +4 -2
  11. package/lib/commonjs/components/Checkbox/Checkbox.js +14 -5
  12. package/lib/commonjs/components/DatePicker/DatePicker.js +9 -7
  13. package/lib/commonjs/components/DateRangePicker/DateRangePicker.js +5 -2
  14. package/lib/commonjs/components/Dialog/Dialog.js +2 -2
  15. package/lib/commonjs/components/FieldBase/FieldBase.js +8 -4
  16. package/lib/commonjs/components/FloatingActionButton/FloatingActionButton.js +13 -5
  17. package/lib/commonjs/components/FormField/FormField.js +61 -25
  18. package/lib/commonjs/components/Input/Input.js +41 -29
  19. package/lib/commonjs/components/KeyboardAwareScrollView/KeyboardAwareScrollView.js +102 -0
  20. package/lib/commonjs/components/KeyboardAwareScrollView/index.js +13 -0
  21. package/lib/commonjs/components/KeyboardToolbar/KeyboardToolbar.js +130 -0
  22. package/lib/commonjs/components/KeyboardToolbar/index.js +13 -0
  23. package/lib/commonjs/components/Modal/Modal.js +17 -6
  24. package/lib/commonjs/components/NumberInput/NumberInput.js +35 -28
  25. package/lib/commonjs/components/OTPInput/OTPInput.js +33 -18
  26. package/lib/commonjs/components/Radio/Radio.js +7 -5
  27. package/lib/commonjs/components/Radio/RadioGroup.js +10 -3
  28. package/lib/commonjs/components/SearchBar/SearchBar.js +4 -2
  29. package/lib/commonjs/components/SegmentedControl/SegmentedControl.js +20 -10
  30. package/lib/commonjs/components/Select/Select.js +33 -32
  31. package/lib/commonjs/components/Skeleton/SkeletonContent.js +5 -2
  32. package/lib/commonjs/components/Slider/Slider.js +42 -26
  33. package/lib/commonjs/components/Spinner/Spinner.js +5 -5
  34. package/lib/commonjs/components/Switch/Switch.js +29 -16
  35. package/lib/commonjs/components/Tabs/Tabs.js +4 -2
  36. package/lib/commonjs/components/Text/Text.js +142 -0
  37. package/lib/commonjs/components/Text/index.js +13 -0
  38. package/lib/commonjs/components/TimePicker/TimePicker.js +10 -7
  39. package/lib/commonjs/components/Toast/Toast.js +22 -10
  40. package/lib/commonjs/components/Tooltip/Tooltip.js +6 -2
  41. package/lib/commonjs/components/index.js +135 -89
  42. package/lib/commonjs/form/FormContext.js +40 -0
  43. package/lib/commonjs/form/index.js +68 -0
  44. package/lib/commonjs/form/path.js +79 -0
  45. package/lib/commonjs/form/rules.js +67 -0
  46. package/lib/commonjs/form/types.js +2 -0
  47. package/lib/commonjs/form/useField.js +54 -0
  48. package/lib/commonjs/form/useForm.js +316 -0
  49. package/lib/commonjs/hooks/index.js +14 -0
  50. package/lib/commonjs/hooks/useControllableState.js +30 -0
  51. package/lib/commonjs/hooks/useReducedMotion.js +31 -0
  52. package/lib/commonjs/index.js +96 -11
  53. package/lib/commonjs/theme/ThemeContext.js +30 -2
  54. package/lib/commonjs/theme/tokens.js +12 -0
  55. package/lib/module/components/Accordion/Accordion.js +4 -2
  56. package/lib/module/components/Avatar/Avatar.js +4 -2
  57. package/lib/module/components/Badge/Badge.js +5 -5
  58. package/lib/module/components/Banner/Banner.js +8 -4
  59. package/lib/module/components/BottomNavigation/BottomNavigation.js +6 -4
  60. package/lib/module/components/BottomSheet/BottomSheet.js +8 -9
  61. package/lib/module/components/Box/Box.js +156 -0
  62. package/lib/module/components/Box/index.js +4 -0
  63. package/lib/module/components/Button/Button.js +7 -7
  64. package/lib/module/components/Carousel/Carousel.js +4 -2
  65. package/lib/module/components/Checkbox/Checkbox.js +14 -5
  66. package/lib/module/components/DatePicker/DatePicker.js +9 -7
  67. package/lib/module/components/DateRangePicker/DateRangePicker.js +5 -2
  68. package/lib/module/components/Dialog/Dialog.js +2 -2
  69. package/lib/module/components/FieldBase/FieldBase.js +8 -4
  70. package/lib/module/components/FloatingActionButton/FloatingActionButton.js +13 -5
  71. package/lib/module/components/FormField/FormField.js +62 -26
  72. package/lib/module/components/Input/Input.js +41 -29
  73. package/lib/module/components/KeyboardAwareScrollView/KeyboardAwareScrollView.js +98 -0
  74. package/lib/module/components/KeyboardAwareScrollView/index.js +4 -0
  75. package/lib/module/components/KeyboardToolbar/KeyboardToolbar.js +125 -0
  76. package/lib/module/components/KeyboardToolbar/index.js +4 -0
  77. package/lib/module/components/Modal/Modal.js +17 -6
  78. package/lib/module/components/NumberInput/NumberInput.js +30 -23
  79. package/lib/module/components/OTPInput/OTPInput.js +30 -15
  80. package/lib/module/components/Radio/Radio.js +7 -5
  81. package/lib/module/components/Radio/RadioGroup.js +10 -3
  82. package/lib/module/components/SearchBar/SearchBar.js +4 -2
  83. package/lib/module/components/SegmentedControl/SegmentedControl.js +20 -10
  84. package/lib/module/components/Select/Select.js +33 -32
  85. package/lib/module/components/Skeleton/SkeletonContent.js +5 -2
  86. package/lib/module/components/Slider/Slider.js +42 -26
  87. package/lib/module/components/Spinner/Spinner.js +5 -5
  88. package/lib/module/components/Switch/Switch.js +29 -16
  89. package/lib/module/components/Tabs/Tabs.js +4 -2
  90. package/lib/module/components/Text/Text.js +138 -0
  91. package/lib/module/components/Text/index.js +4 -0
  92. package/lib/module/components/TimePicker/TimePicker.js +10 -7
  93. package/lib/module/components/Toast/Toast.js +22 -10
  94. package/lib/module/components/Tooltip/Tooltip.js +6 -2
  95. package/lib/module/components/index.js +4 -0
  96. package/lib/module/form/FormContext.js +32 -0
  97. package/lib/module/form/index.js +12 -0
  98. package/lib/module/form/path.js +72 -0
  99. package/lib/module/form/rules.js +52 -0
  100. package/lib/module/form/types.js +2 -0
  101. package/lib/module/form/useField.js +49 -0
  102. package/lib/module/form/useForm.js +312 -0
  103. package/lib/module/hooks/index.js +2 -0
  104. package/lib/module/hooks/useControllableState.js +26 -0
  105. package/lib/module/hooks/useReducedMotion.js +27 -0
  106. package/lib/module/index.js +3 -1
  107. package/lib/module/theme/ThemeContext.js +30 -2
  108. package/lib/module/theme/tokens.js +12 -0
  109. package/lib/typescript/commonjs/components/BottomNavigation/BottomNavigation.d.ts +1 -1
  110. package/lib/typescript/commonjs/components/Box/Box.d.ts +60 -0
  111. package/lib/typescript/commonjs/components/Box/index.d.ts +3 -0
  112. package/lib/typescript/commonjs/components/Button/Button.d.ts +1 -1
  113. package/lib/typescript/commonjs/components/Checkbox/Checkbox.d.ts +3 -2
  114. package/lib/typescript/commonjs/components/DatePicker/DatePicker.d.ts +3 -3
  115. package/lib/typescript/commonjs/components/Dialog/Dialog.d.ts +2 -2
  116. package/lib/typescript/commonjs/components/FormField/FormField.d.ts +13 -2
  117. package/lib/typescript/commonjs/components/KeyboardAwareScrollView/KeyboardAwareScrollView.d.ts +20 -0
  118. package/lib/typescript/commonjs/components/KeyboardAwareScrollView/index.d.ts +3 -0
  119. package/lib/typescript/commonjs/components/KeyboardToolbar/KeyboardToolbar.d.ts +29 -0
  120. package/lib/typescript/commonjs/components/KeyboardToolbar/index.d.ts +3 -0
  121. package/lib/typescript/commonjs/components/NumberInput/NumberInput.d.ts +3 -2
  122. package/lib/typescript/commonjs/components/OTPInput/OTPInput.d.ts +3 -2
  123. package/lib/typescript/commonjs/components/Radio/Radio.d.ts +2 -2
  124. package/lib/typescript/commonjs/components/Radio/RadioGroup.d.ts +3 -2
  125. package/lib/typescript/commonjs/components/SegmentedControl/SegmentedControl.d.ts +3 -2
  126. package/lib/typescript/commonjs/components/Slider/Slider.d.ts +6 -4
  127. package/lib/typescript/commonjs/components/Spinner/Spinner.d.ts +1 -1
  128. package/lib/typescript/commonjs/components/Switch/Switch.d.ts +3 -2
  129. package/lib/typescript/commonjs/components/Text/Text.d.ts +25 -0
  130. package/lib/typescript/commonjs/components/Text/index.d.ts +3 -0
  131. package/lib/typescript/commonjs/components/TimePicker/TimePicker.d.ts +3 -3
  132. package/lib/typescript/commonjs/components/index.d.ts +8 -0
  133. package/lib/typescript/commonjs/form/FormContext.d.ts +17 -0
  134. package/lib/typescript/commonjs/form/index.d.ts +9 -0
  135. package/lib/typescript/commonjs/form/path.d.ts +10 -0
  136. package/lib/typescript/commonjs/form/rules.d.ts +31 -0
  137. package/lib/typescript/commonjs/form/types.d.ts +94 -0
  138. package/lib/typescript/commonjs/form/useField.d.ts +27 -0
  139. package/lib/typescript/commonjs/form/useForm.d.ts +10 -0
  140. package/lib/typescript/commonjs/hooks/index.d.ts +3 -0
  141. package/lib/typescript/commonjs/hooks/useControllableState.d.ts +17 -0
  142. package/lib/typescript/commonjs/hooks/useReducedMotion.d.ts +8 -0
  143. package/lib/typescript/commonjs/index.d.ts +4 -2
  144. package/lib/typescript/commonjs/theme/types.d.ts +15 -0
  145. package/lib/typescript/module/components/BottomNavigation/BottomNavigation.d.ts +1 -1
  146. package/lib/typescript/module/components/Box/Box.d.ts +60 -0
  147. package/lib/typescript/module/components/Box/index.d.ts +3 -0
  148. package/lib/typescript/module/components/Button/Button.d.ts +1 -1
  149. package/lib/typescript/module/components/Checkbox/Checkbox.d.ts +3 -2
  150. package/lib/typescript/module/components/DatePicker/DatePicker.d.ts +3 -3
  151. package/lib/typescript/module/components/Dialog/Dialog.d.ts +2 -2
  152. package/lib/typescript/module/components/FormField/FormField.d.ts +13 -2
  153. package/lib/typescript/module/components/KeyboardAwareScrollView/KeyboardAwareScrollView.d.ts +20 -0
  154. package/lib/typescript/module/components/KeyboardAwareScrollView/index.d.ts +3 -0
  155. package/lib/typescript/module/components/KeyboardToolbar/KeyboardToolbar.d.ts +29 -0
  156. package/lib/typescript/module/components/KeyboardToolbar/index.d.ts +3 -0
  157. package/lib/typescript/module/components/NumberInput/NumberInput.d.ts +3 -2
  158. package/lib/typescript/module/components/OTPInput/OTPInput.d.ts +3 -2
  159. package/lib/typescript/module/components/Radio/Radio.d.ts +2 -2
  160. package/lib/typescript/module/components/Radio/RadioGroup.d.ts +3 -2
  161. package/lib/typescript/module/components/SegmentedControl/SegmentedControl.d.ts +3 -2
  162. package/lib/typescript/module/components/Slider/Slider.d.ts +6 -4
  163. package/lib/typescript/module/components/Spinner/Spinner.d.ts +1 -1
  164. package/lib/typescript/module/components/Switch/Switch.d.ts +3 -2
  165. package/lib/typescript/module/components/Text/Text.d.ts +25 -0
  166. package/lib/typescript/module/components/Text/index.d.ts +3 -0
  167. package/lib/typescript/module/components/TimePicker/TimePicker.d.ts +3 -3
  168. package/lib/typescript/module/components/index.d.ts +8 -0
  169. package/lib/typescript/module/form/FormContext.d.ts +17 -0
  170. package/lib/typescript/module/form/index.d.ts +9 -0
  171. package/lib/typescript/module/form/path.d.ts +10 -0
  172. package/lib/typescript/module/form/rules.d.ts +31 -0
  173. package/lib/typescript/module/form/types.d.ts +94 -0
  174. package/lib/typescript/module/form/useField.d.ts +27 -0
  175. package/lib/typescript/module/form/useForm.d.ts +10 -0
  176. package/lib/typescript/module/hooks/index.d.ts +3 -0
  177. package/lib/typescript/module/hooks/useControllableState.d.ts +17 -0
  178. package/lib/typescript/module/hooks/useReducedMotion.d.ts +8 -0
  179. package/lib/typescript/module/index.d.ts +4 -2
  180. package/lib/typescript/module/theme/types.d.ts +15 -0
  181. package/package.json +1 -1
@@ -95,12 +95,14 @@ const FloatingActionButton = exports.FloatingActionButton = /*#__PURE__*/(0, _re
95
95
  (0, _index.setNativeValue)(hideAnim, 0);
96
96
  return;
97
97
  }
98
- _reactNative.Animated.timing(hideAnim, {
98
+ const anim = _reactNative.Animated.timing(hideAnim, {
99
99
  toValue: isScrolling ? 1 : 0,
100
100
  duration: theme.motion.duration.normal,
101
101
  easing: _reactNative.Easing.bezier(...theme.motion.easing.standard),
102
102
  useNativeDriver: true
103
- }).start();
103
+ });
104
+ anim.start();
105
+ return () => anim.stop();
104
106
  }, [hideOnScroll, isScrolling, hideAnim, theme.motion.duration.normal, theme.motion.easing.standard]);
105
107
  const hideTranslateY = hideAnim.interpolate({
106
108
  inputRange: [0, 1],
@@ -276,12 +278,13 @@ const FloatingActionButtonGroup = props => {
276
278
  // eslint-disable-next-line react-hooks/exhaustive-deps
277
279
  }, [actions.length]);
278
280
  (0, _react.useEffect)(() => {
279
- _reactNative.Animated.timing(progress, {
281
+ const progressAnim = _reactNative.Animated.timing(progress, {
280
282
  toValue: isOpen ? 1 : 0,
281
283
  duration: theme.motion.duration.normal,
282
284
  easing: _reactNative.Easing.bezier(...theme.motion.easing.standard),
283
285
  useNativeDriver: true
284
- }).start();
286
+ });
287
+ progressAnim.start();
285
288
  const animations = itemAnims.current.map(value => _reactNative.Animated.timing(value, {
286
289
  toValue: isOpen ? 1 : 0,
287
290
  duration: theme.motion.duration.normal,
@@ -290,7 +293,12 @@ const FloatingActionButtonGroup = props => {
290
293
  }));
291
294
  // Reverse stagger order on close so items closest to primary collapse last
292
295
  const ordered = isOpen ? animations : [...animations].reverse();
293
- _reactNative.Animated.stagger(staggerMs, ordered).start();
296
+ const staggerAnim = _reactNative.Animated.stagger(staggerMs, ordered);
297
+ staggerAnim.start();
298
+ return () => {
299
+ progressAnim.stop();
300
+ staggerAnim.stop();
301
+ };
294
302
  }, [isOpen, progress, theme.motion.duration.normal, theme.motion.easing.standard, actions.length, itemAnimsVersion, staggerMs]);
295
303
  const setOpen = (0, _react.useCallback)(next => {
296
304
  if (pressHaptic) (0, _hapticUtils.triggerHaptic)('impactLight');
@@ -7,6 +7,7 @@ exports.default = exports.FormField = void 0;
7
7
  var _react = _interopRequireWildcard(require("react"));
8
8
  var _reactNative = require("react-native");
9
9
  var _index = require("../../theme/index.js");
10
+ var _FormContext = require("../../form/FormContext.js");
10
11
  var _jsxRuntime = require("react/jsx-runtime");
11
12
  function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
12
13
  const FormField = exports.FormField = /*#__PURE__*/(0, _react.forwardRef)((props, ref) => {
@@ -15,6 +16,7 @@ const FormField = exports.FormField = /*#__PURE__*/(0, _react.forwardRef)((props
15
16
  helperText,
16
17
  error,
17
18
  required = false,
19
+ name,
18
20
  children,
19
21
  layout = 'stacked',
20
22
  labelStyle,
@@ -27,19 +29,32 @@ const FormField = exports.FormField = /*#__PURE__*/(0, _react.forwardRef)((props
27
29
  } = props;
28
30
  const theme = (0, _index.useTheme)();
29
31
  const styles = (0, _react.useMemo)(() => buildStyles(theme), [theme]);
30
- const errorOpacity = (0, _react.useRef)((0, _index.createAnimatedValue)(error ? 1 : 0)).current;
32
+ const formCtx = (0, _FormContext.useOptionalFormContext)();
33
+ const isConnected = name != null && formCtx != null;
34
+ const field = isConnected ? formCtx.getFieldProps(name) : null;
35
+ const isRenderProp = typeof children === 'function';
36
+
37
+ // Error the FormField renders itself. When connected to an element child the
38
+ // child (Input/Select etc.) shows the injected error, so FormField stays
39
+ // quiet to avoid a duplicate message; the render-prop form keeps it here.
40
+ const ownError = isConnected ? isRenderProp ? field?.error : undefined : error;
41
+ // Error used purely for assistive tech — always reflects the real error.
42
+ const a11yError = isConnected ? field?.error : error;
43
+ const errorOpacity = (0, _react.useRef)((0, _index.createAnimatedValue)(ownError ? 1 : 0)).current;
31
44
  (0, _react.useEffect)(() => {
32
- _reactNative.Animated.timing(errorOpacity, {
33
- toValue: error ? 1 : 0,
34
- duration: 150,
45
+ const anim = _reactNative.Animated.timing(errorOpacity, {
46
+ toValue: ownError ? 1 : 0,
47
+ duration: theme.motion.duration.fast,
35
48
  useNativeDriver: true
36
- }).start();
37
- }, [error, errorOpacity]);
49
+ });
50
+ anim.start();
51
+ return () => anim.stop();
52
+ }, [ownError, errorOpacity, theme.motion.duration.fast]);
38
53
  const computedAccessibilityLabel = (0, _react.useMemo)(() => {
39
54
  if (accessibilityLabel) return accessibilityLabel;
40
55
  if (!label) return undefined;
41
- return error ? `${label}, error: ${error}` : label;
42
- }, [accessibilityLabel, label, error]);
56
+ return a11yError ? `${label}, error: ${a11yError}` : label;
57
+ }, [accessibilityLabel, label, a11yError]);
43
58
  const labelNode = label ? /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.Text, {
44
59
  style: [styles.label, layout === 'inline' ? styles.labelInline : null, labelStyle],
45
60
  children: [label, required ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
@@ -48,39 +63,60 @@ const FormField = exports.FormField = /*#__PURE__*/(0, _react.forwardRef)((props
48
63
  }) : null]
49
64
  }) : null;
50
65
  const inputContainerStyle = layout === 'inline' ? styles.inputInline : styles.inputStacked;
51
- const showError = Boolean(error);
66
+ const showError = Boolean(ownError);
52
67
  const showHelper = !showError && Boolean(helperText);
68
+ const renderedChildren = (() => {
69
+ if (isRenderProp) {
70
+ return field ? children(field) : null;
71
+ }
72
+ if (isConnected && field && /*#__PURE__*/_react.default.isValidElement(children)) {
73
+ const child = children;
74
+ const childOnChangeText = child.props.onChangeText;
75
+ const childOnBlur = child.props.onBlur;
76
+ const childOnFocus = child.props.onFocus;
77
+ return /*#__PURE__*/_react.default.cloneElement(child, {
78
+ value: field.value,
79
+ onChangeText: text => {
80
+ field.onChangeText(text);
81
+ childOnChangeText?.(text);
82
+ },
83
+ onBlur: e => {
84
+ field.onBlur();
85
+ childOnBlur?.(e);
86
+ },
87
+ onFocus: e => {
88
+ field.onFocus();
89
+ childOnFocus?.(e);
90
+ },
91
+ error: field.error,
92
+ ref: node => formCtx.registerField(name, node ?? null)
93
+ });
94
+ }
95
+ return children;
96
+ })();
53
97
  return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
54
98
  ref: ref,
55
99
  style: [layout === 'inline' ? styles.rootInline : styles.rootStacked, containerStyle],
56
100
  accessibilityLabel: computedAccessibilityLabel
57
- // Surface the invalid state to assistive tech via the hint. RN's
58
- // AccessibilityState type does not expose an `invalid` field, so the
59
- // error message itself is folded into the label and hint.
101
+ // RN's AccessibilityState type has no `invalid` field, so the error is
102
+ // folded into the label and surfaced again via the hint.
60
103
  ,
61
- accessibilityHint: error ? error : undefined,
104
+ accessibilityHint: a11yError ? a11yError : undefined,
62
105
  testID: testID,
63
- children: [layout === 'inline' ? /*#__PURE__*/(0, _jsxRuntime.jsxs)(_jsxRuntime.Fragment, {
64
- children: [labelNode, /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
65
- style: [inputContainerStyle, inputContainerStyleProp],
66
- children: children
67
- })]
68
- }) : /*#__PURE__*/(0, _jsxRuntime.jsxs)(_jsxRuntime.Fragment, {
69
- children: [labelNode, /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
70
- style: [inputContainerStyle, inputContainerStyleProp],
71
- children: children
72
- })]
106
+ children: [labelNode, /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
107
+ style: [inputContainerStyle, inputContainerStyleProp],
108
+ children: renderedChildren
73
109
  }), showHelper ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
74
110
  style: [styles.helper, helperStyle],
75
111
  numberOfLines: 2,
76
112
  children: helperText
77
- }) : null, error ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Animated.Text, {
113
+ }) : null, ownError ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Animated.Text, {
78
114
  style: [styles.error, {
79
115
  opacity: errorOpacity
80
116
  }, errorStyle],
81
117
  numberOfLines: 2,
82
118
  accessibilityLiveRegion: "polite",
83
- children: error
119
+ children: ownError
84
120
  }) : null]
85
121
  });
86
122
  });
@@ -8,6 +8,7 @@ var _react = _interopRequireWildcard(require("react"));
8
8
  var _reactNative = require("react-native");
9
9
  var _index = require("../../theme/index.js");
10
10
  var _index2 = require("../../utils/index.js");
11
+ var _index3 = require("../../hooks/index.js");
11
12
  var _FieldBase = require("../FieldBase/FieldBase.js");
12
13
  var _jsxRuntime = require("react/jsx-runtime");
13
14
  function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
@@ -84,26 +85,31 @@ const Input = exports.Input = /*#__PURE__*/(0, _react.forwardRef)((props, ref) =
84
85
 
85
86
  // Floating label animation
86
87
  (0, _react.useEffect)(() => {
87
- _reactNative.Animated.timing(labelAnim, {
88
+ const anim = _reactNative.Animated.timing(labelAnim, {
88
89
  toValue: shouldFloat ? 1 : 0,
89
90
  duration: theme.motion.duration.fast,
90
91
  easing: _reactNative.Easing.bezier(...theme.motion.easing.standard),
91
92
  useNativeDriver: false
92
- }).start();
93
+ });
94
+ anim.start();
95
+ return () => anim.stop();
93
96
  }, [shouldFloat, labelAnim, theme.motion.duration.fast, theme.motion.easing.standard]);
94
97
 
95
98
  // Helper / error fade
96
99
  (0, _react.useEffect)(() => {
97
- _reactNative.Animated.timing(messageAnim, {
100
+ const anim = _reactNative.Animated.timing(messageAnim, {
98
101
  toValue: hasError || Boolean(helperText) ? 1 : 0,
99
- duration: 150,
102
+ duration: theme.motion.duration.fast,
100
103
  easing: _reactNative.Easing.bezier(...theme.motion.easing.standard),
101
104
  useNativeDriver: true
102
- }).start();
103
- }, [hasError, helperText, messageAnim, theme.motion.easing.standard]);
105
+ });
106
+ anim.start();
107
+ return () => anim.stop();
108
+ }, [hasError, helperText, messageAnim, theme.motion.duration.fast, theme.motion.easing.standard]);
104
109
 
105
110
  // Error shake — off by default; consumers opt in via
106
111
  // theme.components.input.shakeOnError. The haptic ships with the shake.
112
+ const reduceMotion = (0, _index3.useReducedMotion)();
107
113
  const shakeOnError = theme.components.input?.shakeOnError ?? false;
108
114
  const prevErrorRef = (0, _react.useRef)(hasError);
109
115
  (0, _react.useEffect)(() => {
@@ -111,33 +117,39 @@ const Input = exports.Input = /*#__PURE__*/(0, _react.forwardRef)((props, ref) =
111
117
  prevErrorRef.current = hasError;
112
118
  return;
113
119
  }
120
+ let anim;
114
121
  if (hasError && !prevErrorRef.current) {
115
- (0, _index.setNativeValue)(shakeAnim, 0);
116
- _reactNative.Animated.sequence([_reactNative.Animated.timing(shakeAnim, {
117
- toValue: 1,
118
- duration: 50,
119
- useNativeDriver: true
120
- }), _reactNative.Animated.timing(shakeAnim, {
121
- toValue: -1,
122
- duration: 50,
123
- useNativeDriver: true
124
- }), _reactNative.Animated.timing(shakeAnim, {
125
- toValue: 1,
126
- duration: 50,
127
- useNativeDriver: true
128
- }), _reactNative.Animated.timing(shakeAnim, {
129
- toValue: -1,
130
- duration: 50,
131
- useNativeDriver: true
132
- }), _reactNative.Animated.timing(shakeAnim, {
133
- toValue: 0,
134
- duration: 100,
135
- useNativeDriver: true
136
- })]).start();
122
+ // Reduce Motion: keep the error haptic, skip the shake.
123
+ if (!reduceMotion) {
124
+ (0, _index.setNativeValue)(shakeAnim, 0);
125
+ anim = _reactNative.Animated.sequence([_reactNative.Animated.timing(shakeAnim, {
126
+ toValue: 1,
127
+ duration: 50,
128
+ useNativeDriver: true
129
+ }), _reactNative.Animated.timing(shakeAnim, {
130
+ toValue: -1,
131
+ duration: 50,
132
+ useNativeDriver: true
133
+ }), _reactNative.Animated.timing(shakeAnim, {
134
+ toValue: 1,
135
+ duration: 50,
136
+ useNativeDriver: true
137
+ }), _reactNative.Animated.timing(shakeAnim, {
138
+ toValue: -1,
139
+ duration: 50,
140
+ useNativeDriver: true
141
+ }), _reactNative.Animated.timing(shakeAnim, {
142
+ toValue: 0,
143
+ duration: 100,
144
+ useNativeDriver: true
145
+ })]);
146
+ anim.start();
147
+ }
137
148
  (0, _index2.triggerHaptic)('notificationError');
138
149
  }
139
150
  prevErrorRef.current = hasError;
140
- }, [hasError, shakeAnim, shakeOnError]);
151
+ return () => anim?.stop();
152
+ }, [hasError, shakeAnim, shakeOnError, reduceMotion]);
141
153
  const handleFocus = (0, _react.useCallback)(e => {
142
154
  setIsFocused(true);
143
155
  onFocus?.(e);
@@ -0,0 +1,102 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.default = exports.KeyboardAwareScrollView = void 0;
7
+ var _react = _interopRequireWildcard(require("react"));
8
+ var _reactNative = require("react-native");
9
+ var _jsxRuntime = require("react/jsx-runtime");
10
+ function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
11
+ /**
12
+ * A ScrollView that keeps the focused input visible above the keyboard — no
13
+ * native dependency. On keyboard show it pads the content by the keyboard
14
+ * height and scrolls the focused TextInput so its bottom sits `extraScrollHeight`
15
+ * above the keyboard, but only when it would otherwise be covered (so already-
16
+ * visible fields don't jump). The classic measure-and-scroll approach, in pure RN.
17
+ */
18
+ const KeyboardAwareScrollView = exports.KeyboardAwareScrollView = /*#__PURE__*/(0, _react.forwardRef)((props, ref) => {
19
+ const {
20
+ children,
21
+ extraScrollHeight = 24,
22
+ disabled = false,
23
+ contentContainerStyle,
24
+ onScroll,
25
+ onLayout,
26
+ ...rest
27
+ } = props;
28
+ const scrollRef = (0, _react.useRef)(null);
29
+ const scrollYRef = (0, _react.useRef)(0);
30
+ const viewportHeightRef = (0, _react.useRef)(0);
31
+ const [keyboardHeight, setKeyboardHeight] = (0, _react.useState)(0);
32
+ const setRefs = (0, _react.useCallback)(node => {
33
+ scrollRef.current = node;
34
+ if (typeof ref === 'function') ref(node);else if (ref) ref.current = node;
35
+ }, [ref]);
36
+ const scrollFocusedIntoView = (0, _react.useCallback)(kbHeight => {
37
+ const scroll = scrollRef.current;
38
+ const scrollNode = scroll ? (0, _reactNative.findNodeHandle)(scroll) : null;
39
+ const stateApi = _reactNative.TextInput?.State;
40
+ const focused = stateApi?.currentlyFocusedInput?.();
41
+ if (!scroll || scrollNode == null || !focused?.measureLayout) return;
42
+ focused.measureLayout(scrollNode, (_left, top, _width, height) => {
43
+ const scrollY = scrollYRef.current;
44
+ const viewportH = viewportHeightRef.current;
45
+ if (viewportH <= 0) return;
46
+ const keyboardTop = viewportH - kbHeight - extraScrollHeight;
47
+ const fieldBottomInViewport = top - scrollY + height;
48
+ if (fieldBottomInViewport > keyboardTop) {
49
+ const delta = fieldBottomInViewport - keyboardTop;
50
+ scroll.scrollTo({
51
+ y: scrollY + delta,
52
+ animated: true
53
+ });
54
+ }
55
+ }, () => undefined);
56
+ }, [extraScrollHeight]);
57
+ (0, _react.useEffect)(() => {
58
+ if (disabled) return undefined;
59
+ // iOS exposes the will* events (smoother); Android only fires did*.
60
+ const showEvent = _reactNative.Platform.OS === 'ios' ? 'keyboardWillShow' : 'keyboardDidShow';
61
+ const hideEvent = _reactNative.Platform.OS === 'ios' ? 'keyboardWillHide' : 'keyboardDidHide';
62
+ let rafId;
63
+ const showSub = _reactNative.Keyboard.addListener(showEvent, e => {
64
+ const height = e.endCoordinates?.height ?? 0;
65
+ setKeyboardHeight(height);
66
+ // Wait a frame so the padding is applied before we scroll. Tracked so
67
+ // it can be cancelled on unmount (never runs against a torn-down tree).
68
+ if (rafId != null) cancelAnimationFrame(rafId);
69
+ rafId = requestAnimationFrame(() => scrollFocusedIntoView(height));
70
+ });
71
+ const hideSub = _reactNative.Keyboard.addListener(hideEvent, () => setKeyboardHeight(0));
72
+ return () => {
73
+ if (rafId != null) cancelAnimationFrame(rafId);
74
+ showSub.remove();
75
+ hideSub.remove();
76
+ };
77
+ }, [disabled, scrollFocusedIntoView]);
78
+ const handleScroll = (0, _react.useCallback)(e => {
79
+ scrollYRef.current = e.nativeEvent.contentOffset.y;
80
+ onScroll?.(e);
81
+ }, [onScroll]);
82
+ const handleLayout = (0, _react.useCallback)(e => {
83
+ viewportHeightRef.current = e.nativeEvent.layout.height;
84
+ onLayout?.(e);
85
+ }, [onLayout]);
86
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.ScrollView, {
87
+ ref: setRefs,
88
+ onScroll: handleScroll,
89
+ onLayout: handleLayout,
90
+ scrollEventThrottle: 16,
91
+ keyboardShouldPersistTaps: "handled",
92
+ keyboardDismissMode: _reactNative.Platform.OS === 'ios' ? 'interactive' : 'on-drag',
93
+ contentContainerStyle: [contentContainerStyle, {
94
+ paddingBottom: keyboardHeight
95
+ }],
96
+ ...rest,
97
+ children: children
98
+ });
99
+ });
100
+ KeyboardAwareScrollView.displayName = 'KeyboardAwareScrollView';
101
+ var _default = exports.default = KeyboardAwareScrollView;
102
+ //# sourceMappingURL=KeyboardAwareScrollView.js.map
@@ -0,0 +1,13 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ Object.defineProperty(exports, "KeyboardAwareScrollView", {
7
+ enumerable: true,
8
+ get: function () {
9
+ return _KeyboardAwareScrollView.KeyboardAwareScrollView;
10
+ }
11
+ });
12
+ var _KeyboardAwareScrollView = require("./KeyboardAwareScrollView.js");
13
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,130 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.default = exports.KeyboardToolbar = void 0;
7
+ var _react = _interopRequireWildcard(require("react"));
8
+ var _reactNative = require("react-native");
9
+ var _index = require("../../theme/index.js");
10
+ var _FormContext = require("../../form/FormContext.js");
11
+ var _index2 = require("../Text/index.js");
12
+ var _jsxRuntime = require("react/jsx-runtime");
13
+ function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
14
+ const NavButton = ({
15
+ label,
16
+ accessibilityLabel,
17
+ onPress,
18
+ theme
19
+ }) => /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Pressable, {
20
+ onPress: onPress,
21
+ disabled: !onPress,
22
+ accessibilityRole: "button",
23
+ accessibilityLabel: accessibilityLabel,
24
+ hitSlop: 8,
25
+ style: {
26
+ paddingHorizontal: theme.spacing.sm,
27
+ opacity: onPress ? 1 : 0.4
28
+ },
29
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_index2.Text, {
30
+ variant: "h2",
31
+ color: onPress ? 'link' : 'disabled',
32
+ children: label
33
+ })
34
+ });
35
+
36
+ /**
37
+ * An accessory bar pinned just above the keyboard — pure RN, no native
38
+ * dependency. Shows a Done (dismiss) button and optional prev/next chevrons
39
+ * that, inside a `<Form>`, walk the registered field order. Render it at the
40
+ * screen root (a `flex: 1` ancestor) so its `bottom: keyboardHeight` offset
41
+ * lands it on top of the keyboard. Renders nothing while the keyboard is hidden.
42
+ */
43
+ const KeyboardToolbar = props => {
44
+ const {
45
+ doneLabel = 'Done',
46
+ showNavigation,
47
+ onDone,
48
+ onNext,
49
+ onPrev,
50
+ leading,
51
+ style,
52
+ testID
53
+ } = props;
54
+ const theme = (0, _index.useTheme)();
55
+ const form = (0, _FormContext.useOptionalFormContext)();
56
+ const [keyboardHeight, setKeyboardHeight] = (0, _react.useState)(0);
57
+ (0, _react.useEffect)(() => {
58
+ const showEvent = _reactNative.Platform.OS === 'ios' ? 'keyboardWillShow' : 'keyboardDidShow';
59
+ const hideEvent = _reactNative.Platform.OS === 'ios' ? 'keyboardWillHide' : 'keyboardDidHide';
60
+ const showSub = _reactNative.Keyboard.addListener(showEvent, e => setKeyboardHeight(e.endCoordinates?.height ?? 0));
61
+ const hideSub = _reactNative.Keyboard.addListener(hideEvent, () => setKeyboardHeight(0));
62
+ return () => {
63
+ showSub.remove();
64
+ hideSub.remove();
65
+ };
66
+ }, []);
67
+ if (keyboardHeight <= 0) return null;
68
+ const handleDone = onDone ?? (() => _reactNative.Keyboard.dismiss());
69
+ const handlePrev = onPrev ?? form?.focusPrev;
70
+ const handleNext = onNext ?? form?.focusNext;
71
+ const navEnabled = showNavigation ?? Boolean(handlePrev || handleNext);
72
+ return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
73
+ testID: testID,
74
+ accessibilityRole: "toolbar",
75
+ style: [styles.bar, {
76
+ bottom: keyboardHeight,
77
+ backgroundColor: theme.colors.background.elevated,
78
+ borderTopColor: theme.colors.border.primary,
79
+ paddingHorizontal: theme.spacing.md
80
+ }, style],
81
+ children: [navEnabled ? /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
82
+ style: styles.nav,
83
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(NavButton, {
84
+ label: "\u2039",
85
+ accessibilityLabel: "Previous field",
86
+ onPress: handlePrev,
87
+ theme: theme
88
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(NavButton, {
89
+ label: "\u203A",
90
+ accessibilityLabel: "Next field",
91
+ onPress: handleNext,
92
+ theme: theme
93
+ })]
94
+ }) : /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {}), leading, /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
95
+ style: styles.spacer
96
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Pressable, {
97
+ onPress: handleDone,
98
+ accessibilityRole: "button",
99
+ accessibilityLabel: doneLabel,
100
+ hitSlop: 8,
101
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_index2.Text, {
102
+ variant: "body",
103
+ weight: "semibold",
104
+ color: "link",
105
+ children: doneLabel
106
+ })
107
+ })]
108
+ });
109
+ };
110
+ exports.KeyboardToolbar = KeyboardToolbar;
111
+ const styles = _reactNative.StyleSheet.create({
112
+ bar: {
113
+ position: 'absolute',
114
+ left: 0,
115
+ right: 0,
116
+ height: 44,
117
+ flexDirection: 'row',
118
+ alignItems: 'center',
119
+ borderTopWidth: _reactNative.StyleSheet.hairlineWidth
120
+ },
121
+ nav: {
122
+ flexDirection: 'row',
123
+ alignItems: 'center'
124
+ },
125
+ spacer: {
126
+ flex: 1
127
+ }
128
+ });
129
+ var _default = exports.default = KeyboardToolbar;
130
+ //# sourceMappingURL=KeyboardToolbar.js.map
@@ -0,0 +1,13 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ Object.defineProperty(exports, "KeyboardToolbar", {
7
+ enumerable: true,
8
+ get: function () {
9
+ return _KeyboardToolbar.KeyboardToolbar;
10
+ }
11
+ });
12
+ var _KeyboardToolbar = require("./KeyboardToolbar.js");
13
+ //# sourceMappingURL=index.js.map
@@ -44,6 +44,7 @@ const Modal = exports.Modal = /*#__PURE__*/(0, _react.forwardRef)((props, ref) =
44
44
  const wasVisibleRef = (0, _react.useRef)(false);
45
45
  const styles = (0, _react.useMemo)(() => buildStyles(theme), [theme]);
46
46
  (0, _react.useEffect)(() => {
47
+ const running = [];
47
48
  if (visible) {
48
49
  // Two Fabric quirks force this combination: backdrop View needs
49
50
  // `collapsable={false}` (see render) so flattening doesn't drop it,
@@ -51,21 +52,25 @@ const Modal = exports.Modal = /*#__PURE__*/(0, _react.forwardRef)((props, ref) =
51
52
  // Animated.View that also sets backgroundColor inline renders as 0 on
52
53
  // RN 0.85 / Fabric / iOS, leaving the dim layer invisible. Single
53
54
  // 240ms tween — JS thread cost is negligible.
54
- _reactNative.Animated.timing(backdropAnim, {
55
+ const backdrop = _reactNative.Animated.timing(backdropAnim, {
55
56
  toValue: 1,
56
57
  duration,
57
58
  useNativeDriver: false
58
- }).start();
59
+ });
60
+ backdrop.start();
61
+ running.push(backdrop);
59
62
  if (presentation === 'bottom') {
60
- _reactNative.Animated.spring(translateYAnim, {
63
+ const slide = _reactNative.Animated.spring(translateYAnim, {
61
64
  toValue: 0,
62
65
  damping: theme.motion.spring.gentle.damping,
63
66
  stiffness: theme.motion.spring.gentle.stiffness,
64
67
  mass: theme.motion.spring.gentle.mass,
65
68
  useNativeDriver: true
66
- }).start();
69
+ });
70
+ slide.start();
71
+ running.push(slide);
67
72
  } else {
68
- _reactNative.Animated.parallel([_reactNative.Animated.spring(scaleAnim, {
73
+ const enter = _reactNative.Animated.parallel([_reactNative.Animated.spring(scaleAnim, {
69
74
  toValue: 1,
70
75
  damping: theme.motion.spring.gentle.damping,
71
76
  stiffness: theme.motion.spring.gentle.stiffness,
@@ -75,7 +80,9 @@ const Modal = exports.Modal = /*#__PURE__*/(0, _react.forwardRef)((props, ref) =
75
80
  toValue: 1,
76
81
  duration,
77
82
  useNativeDriver: true
78
- })]).start();
83
+ })]);
84
+ enter.start();
85
+ running.push(enter);
79
86
  }
80
87
  } else {
81
88
  // backdropAnim is JS-driven (see note above) — reset directly so a
@@ -85,6 +92,10 @@ const Modal = exports.Modal = /*#__PURE__*/(0, _react.forwardRef)((props, ref) =
85
92
  (0, _index.setNativeValue)(opacityAnim, 0);
86
93
  (0, _index.setNativeValue)(translateYAnim, screenHeight);
87
94
  }
95
+ // Stop in-flight tweens on unmount / visibility flip so an enter animation
96
+ // never resolves against a torn-down tree (fixes the jest async leak and
97
+ // the equivalent post-unmount work in the real app).
98
+ return () => running.forEach(animation => animation.stop());
88
99
  }, [visible, presentation, duration, backdropAnim, scaleAnim, opacityAnim, translateYAnim, screenHeight, theme.motion.spring.gentle.damping, theme.motion.spring.gentle.stiffness, theme.motion.spring.gentle.mass, scaleStartValue]);
89
100
 
90
101
  // Accessibility focus trap: when the modal opens, push screen-reader focus