@webority-technologies/mobile 0.0.14 → 0.0.20

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 (202) hide show
  1. package/lib/commonjs/components/Accordion/Accordion.js +60 -19
  2. package/lib/commonjs/components/AppBar/AppBar.js +29 -20
  3. package/lib/commonjs/components/Avatar/Avatar.js +38 -8
  4. package/lib/commonjs/components/Badge/Badge.js +66 -4
  5. package/lib/commonjs/components/Banner/Banner.js +146 -66
  6. package/lib/commonjs/components/BottomNavigation/BottomNavigation.js +37 -15
  7. package/lib/commonjs/components/BottomSheet/BottomSheet.js +85 -50
  8. package/lib/commonjs/components/Button/Button.js +12 -5
  9. package/lib/commonjs/components/Card/Card.js +106 -16
  10. package/lib/commonjs/components/Carousel/Carousel.js +66 -12
  11. package/lib/commonjs/components/Checkbox/Checkbox.js +11 -7
  12. package/lib/commonjs/components/Chip/Chip.js +44 -12
  13. package/lib/commonjs/components/DatePicker/DatePicker.js +185 -76
  14. package/lib/commonjs/components/DateRangePicker/DateRangePicker.js +133 -59
  15. package/lib/commonjs/components/Dialog/Dialog.js +16 -10
  16. package/lib/commonjs/components/Drawer/Drawer.js +13 -10
  17. package/lib/commonjs/components/FieldBase/FieldBase.js +306 -0
  18. package/lib/commonjs/components/FieldBase/index.js +32 -0
  19. package/lib/commonjs/components/FloatingActionButton/FloatingActionButton.js +69 -44
  20. package/lib/commonjs/components/ForceUpdateDialog/ForceUpdateDialog.js +8 -2
  21. package/lib/commonjs/components/FormField/FormField.js +3 -2
  22. package/lib/commonjs/components/ImageGallery/ImageGallery.js +132 -44
  23. package/lib/commonjs/components/Input/Input.js +144 -181
  24. package/lib/commonjs/components/ListItem/ListItem.js +90 -11
  25. package/lib/commonjs/components/Modal/Modal.js +55 -27
  26. package/lib/commonjs/components/NumberInput/NumberInput.js +60 -106
  27. package/lib/commonjs/components/OTPInput/OTPInput.js +65 -58
  28. package/lib/commonjs/components/PickerTrigger/PickerTrigger.js +185 -0
  29. package/lib/commonjs/components/{AppIcon → PickerTrigger}/index.js +4 -4
  30. package/lib/commonjs/components/ProgressBar/ProgressBar.js +19 -11
  31. package/lib/commonjs/components/Radio/Radio.js +11 -6
  32. package/lib/commonjs/components/Rating/Rating.js +85 -19
  33. package/lib/commonjs/components/SearchBar/SearchBar.js +84 -107
  34. package/lib/commonjs/components/SegmentedControl/SegmentedControl.js +22 -11
  35. package/lib/commonjs/components/Select/Select.js +62 -91
  36. package/lib/commonjs/components/Skeleton/Skeleton.js +131 -174
  37. package/lib/commonjs/components/Skeleton/SkeletonClock.js +117 -0
  38. package/lib/commonjs/components/Skeleton/SkeletonContent.js +164 -81
  39. package/lib/commonjs/components/Skeleton/SkeletonProvider.js +72 -10
  40. package/lib/commonjs/components/Skeleton/index.js +17 -16
  41. package/lib/commonjs/components/Slider/Slider.js +44 -25
  42. package/lib/commonjs/components/Stepper/Stepper.js +199 -29
  43. package/lib/commonjs/components/Swipeable/Swipeable.js +36 -19
  44. package/lib/commonjs/components/Switch/Switch.js +9 -2
  45. package/lib/commonjs/components/Tabs/Tabs.js +84 -21
  46. package/lib/commonjs/components/TimePicker/TimePicker.js +123 -45
  47. package/lib/commonjs/components/Toast/Toast.js +27 -16
  48. package/lib/commonjs/components/Tooltip/Tooltip.js +56 -32
  49. package/lib/commonjs/components/index.js +37 -37
  50. package/lib/commonjs/theme/tokens.js +55 -7
  51. package/lib/module/components/Accordion/Accordion.js +61 -20
  52. package/lib/module/components/AppBar/AppBar.js +29 -20
  53. package/lib/module/components/Avatar/Avatar.js +39 -9
  54. package/lib/module/components/Badge/Badge.js +67 -5
  55. package/lib/module/components/Banner/Banner.js +147 -67
  56. package/lib/module/components/BottomNavigation/BottomNavigation.js +37 -15
  57. package/lib/module/components/BottomSheet/BottomSheet.js +87 -52
  58. package/lib/module/components/Button/Button.js +12 -5
  59. package/lib/module/components/Card/Card.js +107 -17
  60. package/lib/module/components/Carousel/Carousel.js +67 -13
  61. package/lib/module/components/Checkbox/Checkbox.js +11 -7
  62. package/lib/module/components/Chip/Chip.js +45 -13
  63. package/lib/module/components/DatePicker/DatePicker.js +185 -76
  64. package/lib/module/components/DateRangePicker/DateRangePicker.js +134 -60
  65. package/lib/module/components/Dialog/Dialog.js +16 -10
  66. package/lib/module/components/Drawer/Drawer.js +13 -10
  67. package/lib/module/components/FieldBase/FieldBase.js +297 -0
  68. package/lib/module/components/FieldBase/index.js +4 -0
  69. package/lib/module/components/FloatingActionButton/FloatingActionButton.js +69 -44
  70. package/lib/module/components/ForceUpdateDialog/ForceUpdateDialog.js +8 -2
  71. package/lib/module/components/FormField/FormField.js +3 -2
  72. package/lib/module/components/ImageGallery/ImageGallery.js +128 -40
  73. package/lib/module/components/Input/Input.js +144 -179
  74. package/lib/module/components/ListItem/ListItem.js +91 -12
  75. package/lib/module/components/Modal/Modal.js +55 -27
  76. package/lib/module/components/NumberInput/NumberInput.js +60 -106
  77. package/lib/module/components/OTPInput/OTPInput.js +65 -58
  78. package/lib/module/components/PickerTrigger/PickerTrigger.js +181 -0
  79. package/lib/module/components/PickerTrigger/index.js +4 -0
  80. package/lib/module/components/ProgressBar/ProgressBar.js +19 -11
  81. package/lib/module/components/Radio/Radio.js +11 -6
  82. package/lib/module/components/Rating/Rating.js +86 -20
  83. package/lib/module/components/SearchBar/SearchBar.js +84 -107
  84. package/lib/module/components/SegmentedControl/SegmentedControl.js +22 -11
  85. package/lib/module/components/Select/Select.js +62 -91
  86. package/lib/module/components/Skeleton/Skeleton.js +135 -175
  87. package/lib/module/components/Skeleton/SkeletonClock.js +110 -0
  88. package/lib/module/components/Skeleton/SkeletonContent.js +167 -84
  89. package/lib/module/components/Skeleton/SkeletonProvider.js +71 -10
  90. package/lib/module/components/Skeleton/index.js +3 -2
  91. package/lib/module/components/Slider/Slider.js +44 -25
  92. package/lib/module/components/Stepper/Stepper.js +201 -31
  93. package/lib/module/components/Swipeable/Swipeable.js +36 -19
  94. package/lib/module/components/Switch/Switch.js +9 -2
  95. package/lib/module/components/Tabs/Tabs.js +84 -21
  96. package/lib/module/components/TimePicker/TimePicker.js +123 -45
  97. package/lib/module/components/Toast/Toast.js +27 -16
  98. package/lib/module/components/Tooltip/Tooltip.js +56 -32
  99. package/lib/module/components/index.js +2 -2
  100. package/lib/module/theme/tokens.js +55 -7
  101. package/lib/typescript/commonjs/components/Accordion/Accordion.d.ts +10 -5
  102. package/lib/typescript/commonjs/components/AppBar/AppBar.d.ts +8 -0
  103. package/lib/typescript/commonjs/components/Avatar/Avatar.d.ts +12 -6
  104. package/lib/typescript/commonjs/components/Badge/Badge.d.ts +7 -6
  105. package/lib/typescript/commonjs/components/Banner/Banner.d.ts +17 -6
  106. package/lib/typescript/commonjs/components/BottomSheet/BottomSheet.d.ts +7 -0
  107. package/lib/typescript/commonjs/components/Card/Card.d.ts +17 -6
  108. package/lib/typescript/commonjs/components/Carousel/Carousel.d.ts +7 -6
  109. package/lib/typescript/commonjs/components/Checkbox/Checkbox.d.ts +9 -1
  110. package/lib/typescript/commonjs/components/Chip/Chip.d.ts +13 -6
  111. package/lib/typescript/commonjs/components/DatePicker/DatePicker.d.ts +38 -3
  112. package/lib/typescript/commonjs/components/DateRangePicker/DateRangePicker.d.ts +36 -3
  113. package/lib/typescript/commonjs/components/Dialog/Dialog.d.ts +13 -1
  114. package/lib/typescript/commonjs/components/FieldBase/FieldBase.d.ts +141 -0
  115. package/lib/typescript/commonjs/components/FieldBase/index.d.ts +3 -0
  116. package/lib/typescript/commonjs/components/FloatingActionButton/FloatingActionButton.d.ts +8 -6
  117. package/lib/typescript/commonjs/components/FloatingActionButton/index.d.ts +1 -1
  118. package/lib/typescript/commonjs/components/ForceUpdateDialog/ForceUpdateDialog.d.ts +7 -0
  119. package/lib/typescript/commonjs/components/FormField/FormField.d.ts +7 -0
  120. package/lib/typescript/commonjs/components/ImageGallery/ImageGallery.d.ts +6 -4
  121. package/lib/typescript/commonjs/components/Input/Input.d.ts +6 -0
  122. package/lib/typescript/commonjs/components/ListItem/ListItem.d.ts +13 -6
  123. package/lib/typescript/commonjs/components/NumberInput/NumberInput.d.ts +3 -0
  124. package/lib/typescript/commonjs/components/PickerTrigger/PickerTrigger.d.ts +57 -0
  125. package/lib/typescript/commonjs/components/PickerTrigger/index.d.ts +3 -0
  126. package/lib/typescript/commonjs/components/ProgressBar/ProgressBar.d.ts +2 -0
  127. package/lib/typescript/commonjs/components/Radio/Radio.d.ts +3 -0
  128. package/lib/typescript/commonjs/components/Rating/Rating.d.ts +9 -6
  129. package/lib/typescript/commonjs/components/SegmentedControl/SegmentedControl.d.ts +3 -0
  130. package/lib/typescript/commonjs/components/Skeleton/Skeleton.d.ts +49 -20
  131. package/lib/typescript/commonjs/components/Skeleton/SkeletonClock.d.ts +60 -0
  132. package/lib/typescript/commonjs/components/Skeleton/SkeletonContent.d.ts +80 -19
  133. package/lib/typescript/commonjs/components/Skeleton/SkeletonProvider.d.ts +39 -5
  134. package/lib/typescript/commonjs/components/Skeleton/index.d.ts +6 -4
  135. package/lib/typescript/commonjs/components/Slider/Slider.d.ts +12 -1
  136. package/lib/typescript/commonjs/components/Stepper/Stepper.d.ts +18 -6
  137. package/lib/typescript/commonjs/components/Swipeable/Swipeable.d.ts +2 -0
  138. package/lib/typescript/commonjs/components/Switch/Switch.d.ts +1 -0
  139. package/lib/typescript/commonjs/components/Tabs/Tabs.d.ts +26 -2
  140. package/lib/typescript/commonjs/components/TimePicker/TimePicker.d.ts +36 -3
  141. package/lib/typescript/commonjs/components/Toast/Toast.d.ts +8 -0
  142. package/lib/typescript/commonjs/components/Tooltip/Tooltip.d.ts +7 -1
  143. package/lib/typescript/commonjs/components/index.d.ts +5 -5
  144. package/lib/typescript/commonjs/index.d.ts +1 -1
  145. package/lib/typescript/commonjs/theme/index.d.ts +1 -1
  146. package/lib/typescript/commonjs/theme/types.d.ts +553 -11
  147. package/lib/typescript/module/components/Accordion/Accordion.d.ts +10 -5
  148. package/lib/typescript/module/components/AppBar/AppBar.d.ts +8 -0
  149. package/lib/typescript/module/components/Avatar/Avatar.d.ts +12 -6
  150. package/lib/typescript/module/components/Badge/Badge.d.ts +7 -6
  151. package/lib/typescript/module/components/Banner/Banner.d.ts +17 -6
  152. package/lib/typescript/module/components/BottomSheet/BottomSheet.d.ts +7 -0
  153. package/lib/typescript/module/components/Card/Card.d.ts +17 -6
  154. package/lib/typescript/module/components/Carousel/Carousel.d.ts +7 -6
  155. package/lib/typescript/module/components/Checkbox/Checkbox.d.ts +9 -1
  156. package/lib/typescript/module/components/Chip/Chip.d.ts +13 -6
  157. package/lib/typescript/module/components/DatePicker/DatePicker.d.ts +38 -3
  158. package/lib/typescript/module/components/DateRangePicker/DateRangePicker.d.ts +36 -3
  159. package/lib/typescript/module/components/Dialog/Dialog.d.ts +13 -1
  160. package/lib/typescript/module/components/FieldBase/FieldBase.d.ts +141 -0
  161. package/lib/typescript/module/components/FieldBase/index.d.ts +3 -0
  162. package/lib/typescript/module/components/FloatingActionButton/FloatingActionButton.d.ts +8 -6
  163. package/lib/typescript/module/components/FloatingActionButton/index.d.ts +1 -1
  164. package/lib/typescript/module/components/ForceUpdateDialog/ForceUpdateDialog.d.ts +7 -0
  165. package/lib/typescript/module/components/FormField/FormField.d.ts +7 -0
  166. package/lib/typescript/module/components/ImageGallery/ImageGallery.d.ts +6 -4
  167. package/lib/typescript/module/components/Input/Input.d.ts +6 -0
  168. package/lib/typescript/module/components/ListItem/ListItem.d.ts +13 -6
  169. package/lib/typescript/module/components/NumberInput/NumberInput.d.ts +3 -0
  170. package/lib/typescript/module/components/PickerTrigger/PickerTrigger.d.ts +57 -0
  171. package/lib/typescript/module/components/PickerTrigger/index.d.ts +3 -0
  172. package/lib/typescript/module/components/ProgressBar/ProgressBar.d.ts +2 -0
  173. package/lib/typescript/module/components/Radio/Radio.d.ts +3 -0
  174. package/lib/typescript/module/components/Rating/Rating.d.ts +9 -6
  175. package/lib/typescript/module/components/SegmentedControl/SegmentedControl.d.ts +3 -0
  176. package/lib/typescript/module/components/Skeleton/Skeleton.d.ts +49 -20
  177. package/lib/typescript/module/components/Skeleton/SkeletonClock.d.ts +60 -0
  178. package/lib/typescript/module/components/Skeleton/SkeletonContent.d.ts +80 -19
  179. package/lib/typescript/module/components/Skeleton/SkeletonProvider.d.ts +39 -5
  180. package/lib/typescript/module/components/Skeleton/index.d.ts +6 -4
  181. package/lib/typescript/module/components/Slider/Slider.d.ts +12 -1
  182. package/lib/typescript/module/components/Stepper/Stepper.d.ts +18 -6
  183. package/lib/typescript/module/components/Swipeable/Swipeable.d.ts +2 -0
  184. package/lib/typescript/module/components/Switch/Switch.d.ts +1 -0
  185. package/lib/typescript/module/components/Tabs/Tabs.d.ts +26 -2
  186. package/lib/typescript/module/components/TimePicker/TimePicker.d.ts +36 -3
  187. package/lib/typescript/module/components/Toast/Toast.d.ts +8 -0
  188. package/lib/typescript/module/components/Tooltip/Tooltip.d.ts +7 -1
  189. package/lib/typescript/module/components/index.d.ts +5 -5
  190. package/lib/typescript/module/index.d.ts +1 -1
  191. package/lib/typescript/module/theme/index.d.ts +1 -1
  192. package/lib/typescript/module/theme/types.d.ts +553 -11
  193. package/package.json +2 -6
  194. package/lib/commonjs/components/AppIcon/AppIcon.js +0 -120
  195. package/lib/commonjs/types/vector-icons.d.js +0 -2
  196. package/lib/module/components/AppIcon/AppIcon.js +0 -111
  197. package/lib/module/components/AppIcon/index.js +0 -4
  198. package/lib/module/types/vector-icons.d.js +0 -2
  199. package/lib/typescript/commonjs/components/AppIcon/AppIcon.d.ts +0 -20
  200. package/lib/typescript/commonjs/components/AppIcon/index.d.ts +0 -3
  201. package/lib/typescript/module/components/AppIcon/AppIcon.d.ts +0 -20
  202. package/lib/typescript/module/components/AppIcon/index.d.ts +0 -3
@@ -36,6 +36,7 @@ const SPRING_CONFIG = {
36
36
  };
37
37
  const DRAG_ACTIVATION_OFFSET = 10;
38
38
  const RUBBER_BAND_FACTOR = 0.35;
39
+ const FAIL_OFFSET_Y = 15;
39
40
  const toneToBg = (theme, tone) => {
40
41
  switch (tone) {
41
42
  case 'primary':
@@ -56,16 +57,32 @@ const Swipeable = props => {
56
57
  children,
57
58
  leftActions,
58
59
  rightActions,
59
- threshold = 80,
60
- fullSwipeThreshold = 200,
60
+ threshold: thresholdProp,
61
+ fullSwipeThreshold: fullSwipeThresholdProp,
61
62
  onSwipeOpen,
62
63
  onSwipeClose,
63
64
  disabled = false,
64
65
  containerStyle,
66
+ contentStyle: contentSlotStyle,
67
+ actionStyle,
65
68
  accessibilityLabel,
66
69
  testID
67
70
  } = props;
68
71
  const theme = (0, _index.useTheme)();
72
+ const swipeTheme = theme.components.swipeable;
73
+ const threshold = thresholdProp ?? swipeTheme?.threshold ?? 80;
74
+ const fullSwipeThreshold = fullSwipeThresholdProp ?? swipeTheme?.fullSwipeThreshold ?? 200;
75
+ const dragActivationOffset = swipeTheme?.dragActivationOffset ?? DRAG_ACTIVATION_OFFSET;
76
+ const rubberBandFactor = swipeTheme?.rubberBandFactor ?? RUBBER_BAND_FACTOR;
77
+ const failOffsetY = swipeTheme?.failOffsetY ?? FAIL_OFFSET_Y;
78
+ const springConfig = {
79
+ damping: swipeTheme?.springDamping ?? SPRING_CONFIG.damping,
80
+ stiffness: swipeTheme?.springStiffness ?? SPRING_CONFIG.stiffness,
81
+ mass: swipeTheme?.springMass ?? SPRING_CONFIG.mass
82
+ };
83
+ const fullSwipeHapticEnabled = swipeTheme?.fullSwipeHaptic ?? true;
84
+ const actionPressHapticEnabled = swipeTheme?.actionPressHaptic ?? true;
85
+ const a11yActionHapticEnabled = swipeTheme?.a11yActionHaptic ?? true;
69
86
  const styles = (0, _react.useMemo)(() => buildStyles(theme), [theme]);
70
87
  const hasLeft = !!leftActions && leftActions.length > 0;
71
88
  const hasRight = !!rightActions && rightActions.length > 0;
@@ -105,22 +122,22 @@ const Swipeable = props => {
105
122
  const list = side === 'left' ? leftActions : rightActions;
106
123
  const first = list?.[0];
107
124
  if (!first) return;
108
- (0, _index2.triggerHaptic)('notificationSuccess');
125
+ if (fullSwipeHapticEnabled) (0, _index2.triggerHaptic)('notificationSuccess');
109
126
  first.onPress();
110
127
  // After the off-screen slide, snap back to 0 silently.
111
- translateX.value = (0, _reactNativeReanimated.withSpring)(0, SPRING_CONFIG);
128
+ translateX.value = (0, _reactNativeReanimated.withSpring)(0, springConfig);
112
129
  openSideRef.current = null;
113
130
  onSwipeClose?.();
114
- }, [leftActions, rightActions, translateX, onSwipeClose]);
131
+ }, [leftActions, rightActions, translateX, onSwipeClose, springConfig, fullSwipeHapticEnabled]);
115
132
  const close = (0, _react.useCallback)(() => {
116
- translateX.value = (0, _reactNativeReanimated.withSpring)(0, SPRING_CONFIG);
133
+ translateX.value = (0, _reactNativeReanimated.withSpring)(0, springConfig);
117
134
  notifyClose();
118
- }, [translateX, notifyClose]);
135
+ }, [translateX, notifyClose, springConfig]);
119
136
  const handleActionPress = (0, _react.useCallback)(action => {
120
- (0, _index2.triggerHaptic)('selection');
137
+ if (actionPressHapticEnabled) (0, _index2.triggerHaptic)('selection');
121
138
  action.onPress();
122
139
  close();
123
- }, [close]);
140
+ }, [close, actionPressHapticEnabled]);
124
141
 
125
142
  // ───────── Pan gesture (UI thread) ─────────
126
143
  const panGesture = (0, _react.useMemo)(() => {
@@ -133,7 +150,7 @@ const Swipeable = props => {
133
150
  const openThreshold = threshold;
134
151
  const allowLeft = hasLeft;
135
152
  const allowRight = hasRight;
136
- return _reactNativeGestureHandler.Gesture.Pan().enabled(!disabled).activeOffsetX([-DRAG_ACTIVATION_OFFSET, DRAG_ACTIVATION_OFFSET]).failOffsetY([-15, 15]).onStart(() => {
153
+ return _reactNativeGestureHandler.Gesture.Pan().enabled(!disabled).activeOffsetX([-dragActivationOffset, dragActivationOffset]).failOffsetY([-failOffsetY, failOffsetY]).onStart(() => {
137
154
  'worklet';
138
155
 
139
156
  dragStartX.value = translateX.value;
@@ -152,9 +169,9 @@ const Swipeable = props => {
152
169
  }
153
170
  // Rubber-band past the open position so it still feels physical past the cap.
154
171
  if (next > leftCap && allowLeft) {
155
- translateX.value = leftCap + (next - leftCap) * RUBBER_BAND_FACTOR;
172
+ translateX.value = leftCap + (next - leftCap) * rubberBandFactor;
156
173
  } else if (next < -rightCap && allowRight) {
157
- translateX.value = -rightCap + (next + rightCap) * RUBBER_BAND_FACTOR;
174
+ translateX.value = -rightCap + (next + rightCap) * rubberBandFactor;
158
175
  } else {
159
176
  translateX.value = next;
160
177
  }
@@ -188,10 +205,10 @@ const Swipeable = props => {
188
205
  }
189
206
 
190
207
  // Otherwise → spring back closed.
191
- translateX.value = (0, _reactNativeReanimated.withSpring)(0, SPRING_CONFIG);
208
+ translateX.value = (0, _reactNativeReanimated.withSpring)(0, springConfig);
192
209
  (0, _reactNativeReanimated.runOnJS)(notifyClose)();
193
210
  });
194
- }, [disabled, dragStartX, fireFirstAction, fullSwipeThreshold, hasLeft, hasRight, leftRevealWidth, notifyClose, notifyOpen, rightRevealWidth, screenWidth, threshold, translateX]);
211
+ }, [disabled, dragStartX, fireFirstAction, fullSwipeThreshold, hasLeft, hasRight, leftRevealWidth, notifyClose, notifyOpen, rightRevealWidth, screenWidth, threshold, translateX, dragActivationOffset, failOffsetY, rubberBandFactor, springConfig]);
195
212
 
196
213
  // ───────── Animated styles ─────────
197
214
  const contentStyle = (0, _reactNativeReanimated.useAnimatedStyle)(() => ({
@@ -226,10 +243,10 @@ const Swipeable = props => {
226
243
  const all = [...(leftActions ?? []), ...(rightActions ?? [])];
227
244
  const match = all.find(a => a.key === name);
228
245
  if (match) {
229
- (0, _index2.triggerHaptic)('selection');
246
+ if (a11yActionHapticEnabled) (0, _index2.triggerHaptic)('selection');
230
247
  match.onPress();
231
248
  }
232
- }, [leftActions, rightActions]);
249
+ }, [leftActions, rightActions, a11yActionHapticEnabled]);
233
250
 
234
251
  // ───────── Render ─────────
235
252
  // No actions configured → render children directly; zero gesture overhead.
@@ -248,7 +265,7 @@ const Swipeable = props => {
248
265
  children: [hasLeft ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNativeReanimated.default.View, {
249
266
  style: [styles.actionsRow, styles.actionsLeft, {
250
267
  width: leftRevealWidth
251
- }, leftBgStyle],
268
+ }, actionStyle, leftBgStyle],
252
269
  pointerEvents: "box-none",
253
270
  children: leftActions?.map(action => /*#__PURE__*/(0, _jsxRuntime.jsx)(ActionButton, {
254
271
  action: action,
@@ -259,7 +276,7 @@ const Swipeable = props => {
259
276
  }) : null, hasRight ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNativeReanimated.default.View, {
260
277
  style: [styles.actionsRow, styles.actionsRight, {
261
278
  width: rightRevealWidth
262
- }, rightBgStyle],
279
+ }, actionStyle, rightBgStyle],
263
280
  pointerEvents: "box-none",
264
281
  children: rightActions?.map(action => /*#__PURE__*/(0, _jsxRuntime.jsx)(ActionButton, {
265
282
  action: action,
@@ -270,7 +287,7 @@ const Swipeable = props => {
270
287
  }) : null, /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNativeGestureHandler.GestureDetector, {
271
288
  gesture: panGesture,
272
289
  children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNativeReanimated.default.View, {
273
- style: [styles.content, contentStyle],
290
+ style: [styles.content, contentSlotStyle, contentStyle],
274
291
  children: children
275
292
  })
276
293
  })]
@@ -55,6 +55,7 @@ const Switch = exports.Switch = /*#__PURE__*/(0, _react.forwardRef)((props, ref)
55
55
  haptic = 'selection',
56
56
  bounce = false,
57
57
  style,
58
+ containerStyle,
58
59
  trackStyle,
59
60
  thumbStyle,
60
61
  testID,
@@ -167,9 +168,15 @@ const Switch = exports.Switch = /*#__PURE__*/(0, _react.forwardRef)((props, ref)
167
168
  })
168
169
  })
169
170
  });
170
- if (!label) return switchEl;
171
+ if (!label) {
172
+ if (!containerStyle) return switchEl;
173
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
174
+ style: containerStyle,
175
+ children: switchEl
176
+ });
177
+ }
171
178
  return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
172
- style: [styles.row, style],
179
+ style: [styles.row, containerStyle, style],
173
180
  children: [switchEl, /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
174
181
  style: [styles.label, {
175
182
  color: disabled ? theme.colors.text.disabled : theme.colors.text.primary,
@@ -30,12 +30,28 @@ const Tabs = exports.Tabs = /*#__PURE__*/(0, _react.forwardRef)((props, ref) =>
30
30
  scrollable = false,
31
31
  align = 'left',
32
32
  style,
33
+ containerStyle,
33
34
  tabStyle,
35
+ tabLabelStyle,
36
+ tabIconStyle,
37
+ tabBadgeStyle,
38
+ dividerStyle,
39
+ indicatorStyle,
40
+ progress,
34
41
  accessibilityLabel,
35
42
  testID
36
43
  } = props;
37
44
  const theme = (0, _index.useTheme)();
38
45
  const styles = (0, _react.useMemo)(() => buildStyles(theme), [theme]);
46
+ const tabsTokens = theme.components.tabs;
47
+ const tabPaddingHorizontal = tabsTokens?.tabPaddingHorizontal ?? theme.spacing.lg;
48
+ const tabPaddingVertical = tabsTokens?.tabPaddingVertical ?? theme.spacing.md;
49
+ const tabIconSpacing = tabsTokens?.tabIconSpacing ?? 6;
50
+ const underlineHeight = tabsTokens?.underlineHeight ?? 2;
51
+ const pillInset = tabsTokens?.pillInset ?? 4;
52
+ const disabledOpacity = tabsTokens?.disabledOpacity ?? 0.45;
53
+ const badgeGap = tabsTokens?.badgeGap ?? 6;
54
+ const hapticOnPress = tabsTokens?.hapticOnPress ?? false;
39
55
 
40
56
  // Per-tab measured layouts (key → {x, width}).
41
57
  const [layouts, setLayouts] = (0, _react.useState)({});
@@ -43,9 +59,33 @@ const Tabs = exports.Tabs = /*#__PURE__*/(0, _react.forwardRef)((props, ref) =>
43
59
  const indicatorWidth = (0, _react.useRef)((0, _index.createAnimatedValue)(0)).current;
44
60
  const activeLayout = layouts[activeKey];
45
61
 
62
+ // Progress-driven mode: when the caller supplies a fractional-index signal
63
+ // and every tab has reported its layout, the indicator's translateX/width
64
+ // are interpolated from that signal — the press-spring is suppressed so the
65
+ // two drivers don't fight for the same view.
66
+ const allMeasured = tabs.every(t => layouts[t.key] !== undefined);
67
+ const useProgress = progress !== undefined && allMeasured && tabs.length > 1;
68
+ const progressTranslateX = (0, _react.useMemo)(() => {
69
+ if (!useProgress || !progress) return null;
70
+ return progress.interpolate({
71
+ inputRange: tabs.map((_, i) => i),
72
+ outputRange: tabs.map(t => layouts[t.key].x),
73
+ extrapolate: 'clamp'
74
+ });
75
+ }, [useProgress, progress, tabs, layouts]);
76
+ const progressWidth = (0, _react.useMemo)(() => {
77
+ if (!useProgress || !progress) return null;
78
+ return progress.interpolate({
79
+ inputRange: tabs.map((_, i) => i),
80
+ outputRange: tabs.map(t => layouts[t.key].width),
81
+ extrapolate: 'clamp'
82
+ });
83
+ }, [useProgress, progress, tabs, layouts]);
84
+
46
85
  // Animate indicator whenever activeKey or its layout changes.
47
86
  (0, _react.useEffect)(() => {
48
87
  if (!activeLayout) return;
88
+ if (useProgress) return;
49
89
  const spring = theme.motion.spring.snappy;
50
90
  _reactNative.Animated.parallel([
51
91
  // Both must use the JS driver: width can't run on native, and mixing
@@ -64,7 +104,7 @@ const Tabs = exports.Tabs = /*#__PURE__*/(0, _react.forwardRef)((props, ref) =>
64
104
  mass: spring.mass,
65
105
  useNativeDriver: false
66
106
  })]).start();
67
- }, [activeLayout, activeKey, indicatorTranslateX, indicatorWidth, theme.motion.spring.snappy]);
107
+ }, [activeLayout, activeKey, indicatorTranslateX, indicatorWidth, theme.motion.spring.snappy, useProgress]);
68
108
  const handleLayout = (0, _react.useCallback)(key => e => {
69
109
  const {
70
110
  x,
@@ -85,22 +125,27 @@ const Tabs = exports.Tabs = /*#__PURE__*/(0, _react.forwardRef)((props, ref) =>
85
125
  const handlePress = (0, _react.useCallback)(tab => {
86
126
  if (tab.disabled) return;
87
127
  if (tab.key === activeKey) return;
88
- (0, _index2.triggerHaptic)('selection');
128
+ if (hapticOnPress) (0, _index2.triggerHaptic)('selection');
89
129
  onChange(tab.key);
90
- }, [activeKey, onChange]);
130
+ }, [activeKey, onChange, hapticOnPress]);
91
131
  const indicatorIsPill = variant === 'pills';
92
132
 
93
133
  // Indicator visual.
94
134
  const indicator = /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Animated.View, {
95
135
  pointerEvents: "none",
96
- style: [indicatorIsPill ? styles.indicatorPill : styles.indicatorUnderline, {
97
- width: indicatorWidth,
136
+ style: [indicatorIsPill ? styles.indicatorPill : styles.indicatorUnderline, indicatorIsPill ? {
137
+ top: pillInset,
138
+ bottom: pillInset
139
+ } : {
140
+ height: underlineHeight
141
+ }, {
142
+ width: progressWidth ?? indicatorWidth,
98
143
  transform: [{
99
- translateX: indicatorTranslateX
144
+ translateX: progressTranslateX ?? indicatorTranslateX
100
145
  }],
101
146
  backgroundColor: indicatorIsPill ? theme.colors.primaryMuted : theme.colors.primary,
102
147
  borderRadius: indicatorIsPill ? theme.radius.full : 0
103
- }]
148
+ }, indicatorStyle]
104
149
  });
105
150
  const renderTabs = () => tabs.map(tab => {
106
151
  const isActive = tab.key === activeKey;
@@ -122,23 +167,41 @@ const Tabs = exports.Tabs = /*#__PURE__*/(0, _react.forwardRef)((props, ref) =>
122
167
  style: ({
123
168
  pressed
124
169
  }) => [styles.tab, scrollable ? null : styles.tabFlex, {
125
- paddingHorizontal: theme.spacing.lg,
126
- paddingVertical: theme.spacing.md,
127
- opacity: isDisabled ? 0.45 : 1,
170
+ paddingHorizontal: tabPaddingHorizontal,
171
+ paddingVertical: tabPaddingVertical,
172
+ opacity: isDisabled ? disabledOpacity : 1,
128
173
  backgroundColor: pressed ? theme.colors.surface.pressed : 'transparent'
129
174
  }, tabStyle],
130
175
  children: [tab.icon ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
131
- style: styles.tabIcon,
176
+ style: [styles.tabIcon, {
177
+ marginRight: tabIconSpacing
178
+ }, tabIconStyle],
132
179
  children: tab.icon
133
180
  }) : null, /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
134
181
  style: [styles.tabLabel, {
135
182
  color: isActive ? theme.colors.primary : theme.colors.text.tertiary,
136
183
  fontSize: theme.typography.fontSize.base,
137
184
  fontWeight: isActive ? theme.typography.fontWeight.semibold : theme.typography.fontWeight.medium
138
- }],
185
+ }, tabLabelStyle],
139
186
  numberOfLines: 1,
140
187
  children: tab.label
141
- })]
188
+ }), tab.badge !== undefined && tab.badge !== null ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
189
+ style: [styles.tabBadge, {
190
+ marginLeft: badgeGap,
191
+ backgroundColor: theme.colors.primaryMuted,
192
+ borderRadius: theme.radius.full,
193
+ paddingHorizontal: theme.spacing.xs
194
+ }, tabBadgeStyle],
195
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
196
+ style: {
197
+ color: theme.colors.primary,
198
+ fontSize: theme.typography.fontSize.xs,
199
+ fontWeight: theme.typography.fontWeight.semibold
200
+ },
201
+ numberOfLines: 1,
202
+ children: String(tab.badge)
203
+ })
204
+ }) : null]
142
205
  }, tab.key);
143
206
  });
144
207
  const baseRowStyle = {
@@ -152,7 +215,7 @@ const Tabs = exports.Tabs = /*#__PURE__*/(0, _react.forwardRef)((props, ref) =>
152
215
  style: [styles.container, {
153
216
  borderBottomColor: theme.colors.border.secondary,
154
217
  borderBottomWidth: variant === 'underline' ? _reactNative.StyleSheet.hairlineWidth : 0
155
- }, style],
218
+ }, variant === 'underline' ? dividerStyle : null, style, containerStyle],
156
219
  accessibilityRole: "tablist",
157
220
  accessibilityLabel: accessibilityLabel,
158
221
  testID: testID,
@@ -182,23 +245,23 @@ const buildStyles = _theme => _reactNative.StyleSheet.create({
182
245
  tabFlex: {
183
246
  flex: 1
184
247
  },
185
- tabIcon: {
186
- marginRight: 6
187
- },
248
+ tabIcon: {},
188
249
  tabLabel: {
189
250
  includeFontPadding: false
190
251
  },
252
+ tabBadge: {
253
+ minWidth: 18,
254
+ alignItems: 'center',
255
+ justifyContent: 'center'
256
+ },
191
257
  indicatorUnderline: {
192
258
  position: 'absolute',
193
259
  left: 0,
194
- bottom: 0,
195
- height: 2
260
+ bottom: 0
196
261
  },
197
262
  indicatorPill: {
198
263
  position: 'absolute',
199
264
  left: 0,
200
- top: 4,
201
- bottom: 4,
202
265
  zIndex: -1
203
266
  }
204
267
  });
@@ -6,12 +6,26 @@ Object.defineProperty(exports, "__esModule", {
6
6
  exports.default = exports.TimePicker = void 0;
7
7
  var _react = _interopRequireWildcard(require("react"));
8
8
  var _reactNative = require("react-native");
9
+ var _reactNativeSafeAreaContext = require("react-native-safe-area-context");
9
10
  var _index = require("../../theme/index.js");
10
11
  var _hapticUtils = require("../../utils/hapticUtils.js");
11
12
  var _Button = _interopRequireDefault(require("../Button/Button.js"));
13
+ var _PickerTrigger = require("../PickerTrigger/PickerTrigger.js");
12
14
  var _jsxRuntime = require("react/jsx-runtime");
13
15
  function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
14
16
  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); }
17
+ /**
18
+ * TimePicker supports two modes:
19
+ *
20
+ * 1. Controlled-modal mode — pass `visible`, `onSelect`, `onClose`. The
21
+ * component renders only the modal sheet and the caller owns open/close
22
+ * state plus its own trigger UI.
23
+ * 2. Trigger mode — omit `visible`. The component renders a PickerTrigger
24
+ * field (label / value / placeholder / chevron / clear / helper / error)
25
+ * and manages its own modal open state. `onSelect` is still called on
26
+ * confirm.
27
+ */
28
+
15
29
  const ITEM_HEIGHT = 40;
16
30
  const VISIBLE_ITEMS = 5;
17
31
  const PICKER_HEIGHT = ITEM_HEIGHT * VISIBLE_ITEMS;
@@ -84,6 +98,8 @@ const Wheel = ({
84
98
  });
85
99
  }
86
100
  }, [selectedIndex, scrollY]);
101
+ const hapticEnabled = theme.components.timePicker?.haptic ?? false;
102
+ const hapticDebounceMs = theme.components.timePicker?.hapticDebounceMs ?? HAPTIC_DEBOUNCE_MS;
87
103
  const onScroll = (0, _react.useMemo)(() => _reactNative.Animated.event([{
88
104
  nativeEvent: {
89
105
  contentOffset: {
@@ -97,14 +113,14 @@ const Wheel = ({
97
113
  const idx = Math.round(y / ITEM_HEIGHT);
98
114
  if (idx !== lastIndexRef.current && idx >= 0 && idx < data.length) {
99
115
  const now = Date.now();
100
- if (now - lastHapticAtRef.current >= HAPTIC_DEBOUNCE_MS) {
116
+ if (hapticEnabled && now - lastHapticAtRef.current >= hapticDebounceMs) {
101
117
  (0, _hapticUtils.triggerHaptic)('selection');
102
118
  lastHapticAtRef.current = now;
103
119
  }
104
120
  lastIndexRef.current = idx;
105
121
  }
106
122
  }
107
- }), [scrollY, data.length]);
123
+ }), [scrollY, data.length, hapticEnabled, hapticDebounceMs]);
108
124
  const onMomentumScrollEnd = (0, _react.useCallback)(event => {
109
125
  const y = event.nativeEvent.contentOffset.y;
110
126
  const idx = Math.max(0, Math.min(data.length - 1, Math.round(y / ITEM_HEIGHT)));
@@ -203,21 +219,48 @@ const Wheel = ({
203
219
  })]
204
220
  });
205
221
  };
206
- const TimePicker = ({
207
- visible,
208
- value,
209
- onSelect,
210
- onClose,
211
- format = '12h',
212
- minuteStep = 1,
213
- title = 'Select Time',
214
- confirmLabel = 'Confirm',
215
- cancelLabel = 'Cancel',
216
- testID,
217
- style
218
- }) => {
222
+ const TimePicker = props => {
223
+ const {
224
+ visible,
225
+ value,
226
+ onSelect,
227
+ onClose,
228
+ format = '12h',
229
+ minuteStep = 1,
230
+ title = 'Select Time',
231
+ confirmLabel = 'Confirm',
232
+ cancelLabel = 'Cancel',
233
+ testID,
234
+ style,
235
+ containerStyle,
236
+ headerLabelStyle,
237
+ footerButtonStyle,
238
+ label,
239
+ placeholder,
240
+ helperText,
241
+ error,
242
+ required,
243
+ disabled,
244
+ size,
245
+ variant,
246
+ clearable,
247
+ onClear,
248
+ formatValue,
249
+ triggerStyle
250
+ } = props;
251
+ const isControlled = props.visible !== undefined;
252
+ const [internalOpen, setInternalOpen] = (0, _react.useState)(false);
253
+ const open = isControlled ? visible : internalOpen;
219
254
  const theme = (0, _index.useTheme)();
255
+ const insets = (0, _reactNativeSafeAreaContext.useSafeAreaInsets)();
220
256
  const styles = (0, _react.useMemo)(() => buildStyles(theme), [theme]);
257
+ const handleCloseModal = (0, _react.useCallback)(() => {
258
+ if (isControlled) {
259
+ onClose?.();
260
+ } else {
261
+ setInternalOpen(false);
262
+ }
263
+ }, [isControlled, onClose]);
221
264
  const hours = (0, _react.useMemo)(() => format === '24h' ? range(0, 23) : range(1, 12), [format]);
222
265
  const minutes = (0, _react.useMemo)(() => range(0, 59, minuteStep), [minuteStep]);
223
266
  const periods = (0, _react.useMemo)(() => ['AM', 'PM'], []);
@@ -246,9 +289,9 @@ const TimePicker = ({
246
289
  });
247
290
  const [periodIndex, setPeriodIndex] = (0, _react.useState)(() => initial.period === 'PM' ? 1 : 0);
248
291
 
249
- // Re-sync on visible toggle / value change / format / step.
292
+ // Re-sync on open toggle / value change / format / step.
250
293
  (0, _react.useEffect)(() => {
251
- if (!visible) return;
294
+ if (!open) return;
252
295
  const h24 = value && Number.isFinite(value.hour) ? value.hour : new Date().getHours();
253
296
  const m = value && Number.isFinite(value.minute) ? value.minute : new Date().getMinutes();
254
297
  const stepped = clampMinuteToStep(m, minuteStep);
@@ -261,18 +304,20 @@ const TimePicker = ({
261
304
  const mIdx = minutes.indexOf(stepped);
262
305
  setMinuteIndex(mIdx >= 0 ? mIdx : 0);
263
306
  setPeriodIndex(period === 'PM' ? 1 : 0);
264
- }, [visible, value, format, minuteStep, hours, minutes]);
307
+ }, [open, value, format, minuteStep, hours, minutes]);
265
308
 
266
309
  // Sheet animations.
267
310
  const opacity = (0, _react.useRef)((0, _index.createAnimatedValue)(0)).current;
268
311
  const translateY = (0, _react.useRef)((0, _index.createAnimatedValue)(40)).current;
269
312
  (0, _react.useEffect)(() => {
270
- if (visible) {
271
- _reactNative.Animated.parallel([_reactNative.Animated.timing(opacity, {
313
+ if (open) {
314
+ _reactNative.Animated.parallel([
315
+ // Backdrop opacity uses JS driver — see Modal.tsx for the Fabric reason.
316
+ _reactNative.Animated.timing(opacity, {
272
317
  toValue: 1,
273
318
  duration: theme.motion.duration.normal,
274
319
  easing: _reactNative.Easing.out(_reactNative.Easing.cubic),
275
- useNativeDriver: true
320
+ useNativeDriver: false
276
321
  }), _reactNative.Animated.spring(translateY, {
277
322
  toValue: 0,
278
323
  damping: theme.motion.spring.snappy.damping,
@@ -281,10 +326,10 @@ const TimePicker = ({
281
326
  useNativeDriver: true
282
327
  })]).start();
283
328
  } else {
284
- (0, _index.setNativeValue)(opacity, 0);
329
+ opacity.setValue(0);
285
330
  (0, _index.setNativeValue)(translateY, 40);
286
331
  }
287
- }, [visible, opacity, translateY, theme.motion]);
332
+ }, [open, opacity, translateY, theme.motion]);
288
333
  const announce = (0, _react.useCallback)(msg => {
289
334
  if (_reactNative.Platform.OS === 'ios' || _reactNative.Platform.OS === 'android') {
290
335
  _reactNative.AccessibilityInfo.announceForAccessibility(msg);
@@ -303,21 +348,21 @@ const TimePicker = ({
303
348
  announce(periods[idx] ?? '');
304
349
  }, [periods, announce]);
305
350
  const handleCancel = (0, _react.useCallback)(() => {
306
- (0, _hapticUtils.triggerHaptic)('selection');
307
- onClose();
308
- }, [onClose]);
351
+ if (theme.components.timePicker?.haptic) (0, _hapticUtils.triggerHaptic)('selection');
352
+ handleCloseModal();
353
+ }, [handleCloseModal, theme.components.timePicker]);
309
354
  const handleConfirm = (0, _react.useCallback)(() => {
310
355
  const displayHour = hours[hourIndex] ?? 0;
311
356
  const period = periods[periodIndex] ?? 'AM';
312
357
  const hour24 = to24h(displayHour, period, format);
313
358
  const minute = minutes[minuteIndex] ?? 0;
314
- (0, _hapticUtils.triggerHaptic)('notificationSuccess');
315
- onSelect({
359
+ if (theme.components.timePicker?.haptic) (0, _hapticUtils.triggerHaptic)('notificationSuccess');
360
+ onSelect?.({
316
361
  hour: hour24,
317
362
  minute
318
363
  });
319
- onClose();
320
- }, [hours, hourIndex, periods, periodIndex, minutes, minuteIndex, format, onSelect, onClose]);
364
+ handleCloseModal();
365
+ }, [hours, hourIndex, periods, periodIndex, minutes, minuteIndex, format, onSelect, handleCloseModal, theme.components.timePicker]);
321
366
  const summary = (0, _react.useMemo)(() => {
322
367
  const displayHour = hours[hourIndex] ?? 0;
323
368
  const minute = minutes[minuteIndex] ?? 0;
@@ -328,28 +373,43 @@ const TimePicker = ({
328
373
  const formatHourItem = (0, _react.useCallback)(item => pad2(Number(item)), []);
329
374
  const formatMinuteItem = (0, _react.useCallback)(item => pad2(Number(item)), []);
330
375
  const formatPeriodItem = (0, _react.useCallback)(item => String(item), []);
331
- return /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Modal, {
332
- visible: visible,
376
+ const defaultFormatValue = (0, _react.useCallback)(t => {
377
+ if (format === '24h') return `${pad2(t.hour)}:${pad2(t.minute)}`;
378
+ const {
379
+ displayHour,
380
+ period
381
+ } = from24h(t.hour, '12h');
382
+ return `${displayHour}:${pad2(t.minute)} ${period}`;
383
+ }, [format]);
384
+ const triggerValue = !isControlled && value && Number.isFinite(value.hour) && Number.isFinite(value.minute) ? (formatValue ?? defaultFormatValue)(value) : undefined;
385
+ const modal = /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Modal, {
386
+ visible: open,
333
387
  transparent: true,
334
- statusBarTranslucent: true,
388
+ statusBarTranslucent: true
389
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
390
+ // @ts-ignore — Android-only RN 0.71+; iOS ignores it.
391
+ ,
392
+ navigationBarTranslucent: true,
335
393
  animationType: "none",
336
- onRequestClose: onClose,
394
+ onRequestClose: handleCloseModal,
337
395
  testID: testID,
338
- children: /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.Animated.View, {
339
- style: [styles.backdrop, {
340
- opacity
341
- }],
396
+ children: /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View
397
+ // Plain View + collapsable={false} — see Modal.tsx backdrop comment.
398
+ , {
399
+ collapsable: false,
400
+ style: styles.backdrop,
342
401
  children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Pressable, {
343
402
  style: _reactNative.StyleSheet.absoluteFill,
344
- onPress: onClose,
403
+ onPress: handleCloseModal,
345
404
  accessibilityLabel: "Close time picker",
346
405
  accessibilityRole: "button"
347
406
  }), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.Animated.View, {
348
407
  style: [styles.sheet, {
408
+ paddingBottom: insets.bottom + theme.spacing.xl,
349
409
  transform: [{
350
410
  translateY
351
411
  }]
352
- }, style],
412
+ }, style, containerStyle],
353
413
  accessibilityViewIsModal: true,
354
414
  accessible: true,
355
415
  accessibilityRole: "none",
@@ -357,7 +417,7 @@ const TimePicker = ({
357
417
  children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
358
418
  style: styles.handle
359
419
  }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
360
- style: styles.title,
420
+ style: [styles.title, headerLabelStyle],
361
421
  accessibilityRole: "header",
362
422
  children: title
363
423
  }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
@@ -420,7 +480,7 @@ const TimePicker = ({
420
480
  variant: "ghost",
421
481
  tone: "neutral",
422
482
  onPress: handleCancel,
423
- style: styles.footerBtn,
483
+ style: [styles.footerBtn, footerButtonStyle],
424
484
  accessibilityHint: "Dismiss without changes",
425
485
  testID: "time-picker-cancel"
426
486
  }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_Button.default, {
@@ -429,7 +489,7 @@ const TimePicker = ({
429
489
  tone: "primary",
430
490
  haptic: false,
431
491
  onPress: handleConfirm,
432
- style: styles.footerBtn,
492
+ style: [styles.footerBtn, footerButtonStyle],
433
493
  accessibilityHint: "Confirm selected time",
434
494
  testID: "time-picker-confirm"
435
495
  })]
@@ -437,6 +497,24 @@ const TimePicker = ({
437
497
  })]
438
498
  })
439
499
  });
500
+ if (isControlled) return modal;
501
+ return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_jsxRuntime.Fragment, {
502
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_PickerTrigger.PickerTrigger, {
503
+ label: label,
504
+ placeholder: placeholder,
505
+ helperText: helperText,
506
+ error: error,
507
+ required: required,
508
+ disabled: disabled,
509
+ size: size,
510
+ variant: variant,
511
+ clearable: clearable,
512
+ onClear: onClear,
513
+ value: triggerValue,
514
+ onPress: () => setInternalOpen(true),
515
+ triggerStyle: triggerStyle
516
+ }), modal]
517
+ });
440
518
  };
441
519
  exports.TimePicker = TimePicker;
442
520
  const styles = _reactNative.StyleSheet.create({
@@ -482,8 +560,8 @@ const buildStyles = theme => {
482
560
  },
483
561
  handle: {
484
562
  alignSelf: 'center',
485
- width: 36,
486
- height: 4,
563
+ width: theme.components.timePicker?.handleWidth ?? 36,
564
+ height: theme.components.timePicker?.handleHeight ?? 4,
487
565
  borderRadius: theme.radius.full,
488
566
  backgroundColor: theme.colors.border.secondary,
489
567
  marginBottom: theme.spacing.sm