@expokit/cli 0.4.3 → 0.5.0

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 (242) hide show
  1. package/README.md +30 -3
  2. package/bin/expo-kit.js +749 -288
  3. package/bin/lib.mjs +313 -4
  4. package/package.json +1 -1
  5. package/registry/_docs/action-sheet.json +1 -1
  6. package/registry/_docs/alert.json +6 -0
  7. package/registry/_docs/bottom-sheet.json +6 -0
  8. package/registry/_docs/bullet.json +6 -0
  9. package/registry/_docs/dialog.json +1 -1
  10. package/registry/_docs/drawer.json +3 -3
  11. package/registry/_docs/flip-calendar.json +106 -0
  12. package/registry/_docs/glass-search-bar.json +1 -1
  13. package/registry/_docs/grain.json +6 -1
  14. package/registry/_docs/isometric-bar.json +6 -0
  15. package/registry/_docs/liquidglass-tab.json +1 -1
  16. package/registry/_docs/password-input.json +1 -1
  17. package/registry/_docs/paywall.json +144 -0
  18. package/registry/_docs/pixel-bar.json +6 -0
  19. package/registry/_docs/polar-area.json +6 -0
  20. package/registry/_docs/qr-code-button.json +9 -3
  21. package/registry/_docs/ruler-time-picker.json +147 -0
  22. package/registry/_docs/scratch-card.json +7 -1
  23. package/registry/_docs/search-bar.json +1 -1
  24. package/registry/_docs/select.json +2 -2
  25. package/registry/_docs/slide-to-confirm.json +2 -2
  26. package/registry/_docs/spinner.json +1 -1
  27. package/registry/_docs/stateful-button.json +2 -2
  28. package/registry/_docs/swipe-deck.json +1 -1
  29. package/registry/_docs/time-picker.json +2 -2
  30. package/registry/_docs/timeline-chart.json +6 -0
  31. package/registry/_docs/toast.json +15 -3
  32. package/registry/_docs/treemap.json +6 -0
  33. package/registry/_docs/waterfall.json +6 -0
  34. package/registry/accordion/files/src/components/ui/accordion.tsx +6 -4
  35. package/registry/accordion/files/src/lib/kit.tsx +462 -12
  36. package/registry/accordion.json +1 -0
  37. package/registry/action-sheet/files/src/components/ui/action-sheet.tsx +50 -58
  38. package/registry/action-sheet/files/src/lib/kit.tsx +462 -12
  39. package/registry/action-sheet.json +1 -0
  40. package/registry/alert/files/src/components/ui/alert.tsx +20 -13
  41. package/registry/alert/files/src/lib/kit.tsx +462 -12
  42. package/registry/alert.json +3 -4
  43. package/registry/assistant-app.json +1 -0
  44. package/registry/avatar/files/src/components/ui/avatar.tsx +89 -74
  45. package/registry/avatar/files/src/lib/kit.tsx +462 -12
  46. package/registry/avatar.json +1 -0
  47. package/registry/badge/files/src/components/ui/badge.tsx +36 -36
  48. package/registry/badge/files/src/lib/kit.tsx +462 -12
  49. package/registry/badge.json +1 -0
  50. package/registry/bottom-nav/files/src/components/ui/bottom-nav.tsx +39 -44
  51. package/registry/bottom-nav/files/src/lib/kit.tsx +462 -12
  52. package/registry/bottom-nav.json +5 -0
  53. package/registry/bottom-sheet/files/src/components/ui/bottom-sheet.tsx +357 -300
  54. package/registry/bottom-sheet/files/src/lib/kit.tsx +462 -12
  55. package/registry/bottom-sheet.json +5 -1
  56. package/registry/bullet.json +1 -0
  57. package/registry/button/files/src/components/ui/button.tsx +23 -34
  58. package/registry/button/files/src/lib/kit.tsx +462 -12
  59. package/registry/button-3d/files/src/components/ui/button-3d.tsx +6 -9
  60. package/registry/button-3d/files/src/lib/kit.tsx +462 -12
  61. package/registry/button-3d.json +1 -0
  62. package/registry/button.json +1 -0
  63. package/registry/calendar/files/src/components/ui/calendar.tsx +77 -79
  64. package/registry/calendar/files/src/lib/kit.tsx +462 -12
  65. package/registry/calendar.json +1 -0
  66. package/registry/card/files/src/components/ui/card.tsx +7 -6
  67. package/registry/card/files/src/lib/kit.tsx +462 -12
  68. package/registry/card-stack.json +1 -0
  69. package/registry/card.json +1 -0
  70. package/registry/carousel.json +1 -0
  71. package/registry/chat.json +7 -0
  72. package/registry/checkbox/files/src/components/ui/checkbox.tsx +4 -4
  73. package/registry/checkbox/files/src/lib/kit.tsx +462 -12
  74. package/registry/checkbox.json +1 -0
  75. package/registry/checkout.json +1 -0
  76. package/registry/chip-group/files/src/components/ui/chip-group.tsx +24 -24
  77. package/registry/chip-group/files/src/lib/kit.tsx +462 -12
  78. package/registry/chip-group.json +1 -0
  79. package/registry/confetti/files/src/components/ui/confetti.tsx +15 -14
  80. package/registry/confetti.json +3 -6
  81. package/registry/coupon/files/src/components/ui/coupon.tsx +47 -52
  82. package/registry/coupon/files/src/components/ui/flip-card.tsx +9 -14
  83. package/registry/coupon/files/src/components/ui/tilt-card.tsx +80 -101
  84. package/registry/coupon/files/src/lib/kit.tsx +462 -12
  85. package/registry/coupon/files/src/lib/ticket-shape.tsx +54 -44
  86. package/registry/coupon.json +1 -0
  87. package/registry/cube-pager.json +1 -0
  88. package/registry/dashboard.json +1 -0
  89. package/registry/date-picker/files/src/components/ui/calendar.tsx +77 -79
  90. package/registry/date-picker/files/src/components/ui/date-picker.tsx +64 -71
  91. package/registry/date-picker/files/src/lib/kit.tsx +462 -12
  92. package/registry/date-picker.json +1 -0
  93. package/registry/dialog/files/src/components/ui/dialog.tsx +66 -68
  94. package/registry/dialog/files/src/lib/kit.tsx +462 -12
  95. package/registry/dialog.json +1 -0
  96. package/registry/donut-shop.json +1 -0
  97. package/registry/drawer/files/src/components/ui/drawer.tsx +76 -88
  98. package/registry/drawer/files/src/lib/kit.tsx +462 -12
  99. package/registry/drawer.json +1 -0
  100. package/registry/fab.json +1 -0
  101. package/registry/fintech-app.json +1 -0
  102. package/registry/flip-calendar/files/src/components/ui/flip-calendar.tsx +632 -0
  103. package/registry/flip-calendar/files/src/lib/kit.tsx +672 -0
  104. package/registry/flip-calendar.json +24 -0
  105. package/registry/flip-card/files/src/components/ui/flip-card.tsx +9 -14
  106. package/registry/flip-card/files/src/lib/kit.tsx +462 -12
  107. package/registry/flip-card.json +1 -0
  108. package/registry/floating-input/files/src/components/ui/floating-input.tsx +33 -33
  109. package/registry/floating-input/files/src/lib/kit.tsx +462 -12
  110. package/registry/floating-input.json +1 -0
  111. package/registry/food-app.json +1 -0
  112. package/registry/gift-card.json +1 -0
  113. package/registry/glass-button.json +5 -0
  114. package/registry/glass-nav-bar.json +1 -0
  115. package/registry/glass-search-bar.json +1 -0
  116. package/registry/glass-segmented.json +1 -0
  117. package/registry/glass-sheet.json +1 -0
  118. package/registry/glass-tab-bar.json +5 -0
  119. package/registry/glass.json +1 -0
  120. package/registry/grain/files/src/components/ui/grain.tsx +16 -14
  121. package/registry/grain.json +8 -6
  122. package/registry/inbox.json +1 -0
  123. package/registry/isometric-bar.json +1 -0
  124. package/registry/kit/files/src/lib/kit.tsx +462 -12
  125. package/registry/kit.json +1 -0
  126. package/registry/liquidglass-tab/files/src/app/_layout.tsx +0 -1
  127. package/registry/liquidglass-tab/files/src/components/GlassTabBar.tsx +29 -16
  128. package/registry/liquidglass-tab/files/src/components/TabScreen.tsx +33 -19
  129. package/registry/liquidglass-tab/files/src/lib/tab-icons.ts +1 -1
  130. package/registry/liquidglass-tab.json +1 -0
  131. package/registry/list-item/files/src/components/ui/list-item.tsx +43 -43
  132. package/registry/list-item/files/src/lib/kit.tsx +462 -12
  133. package/registry/list-item.json +1 -0
  134. package/registry/loyalty-card.json +1 -0
  135. package/registry/morphing-button-group.json +1 -0
  136. package/registry/number-ticker.json +1 -0
  137. package/registry/offers.json +1 -0
  138. package/registry/onboarding.json +1 -0
  139. package/registry/orb-reveal.json +1 -0
  140. package/registry/otp-input/files/src/components/ui/otp-input.tsx +49 -30
  141. package/registry/otp-input/files/src/lib/kit.tsx +462 -12
  142. package/registry/otp-input.json +1 -0
  143. package/registry/parallax-layers.json +1 -0
  144. package/registry/parallax-scroll.json +1 -0
  145. package/registry/password-input/files/src/components/ui/floating-input.tsx +33 -33
  146. package/registry/password-input/files/src/components/ui/password-input.tsx +29 -25
  147. package/registry/password-input/files/src/lib/kit.tsx +462 -12
  148. package/registry/password-input.json +1 -0
  149. package/registry/payment-card/files/src/components/ui/flip-card.tsx +9 -14
  150. package/registry/payment-card/files/src/components/ui/payment-card.tsx +26 -20
  151. package/registry/payment-card/files/src/components/ui/tilt-card.tsx +80 -101
  152. package/registry/payment-card/files/src/lib/kit.tsx +462 -12
  153. package/registry/payment-card.json +1 -0
  154. package/registry/paywall.json +23 -0
  155. package/registry/pixel-bar.json +1 -0
  156. package/registry/polar-area.json +1 -0
  157. package/registry/profile.json +1 -0
  158. package/registry/progress/files/src/components/ui/progress.tsx +31 -29
  159. package/registry/progress/files/src/lib/kit.tsx +462 -12
  160. package/registry/progress-steps/files/src/components/ui/progress-steps.tsx +21 -21
  161. package/registry/progress-steps/files/src/lib/kit.tsx +462 -12
  162. package/registry/progress-steps.json +1 -0
  163. package/registry/progress.json +1 -0
  164. package/registry/qr-code-button.json +1 -0
  165. package/registry/radio-group/files/src/components/ui/radio-group.tsx +19 -19
  166. package/registry/radio-group/files/src/lib/kit.tsx +462 -12
  167. package/registry/radio-group.json +1 -0
  168. package/registry/rating.json +1 -0
  169. package/registry/ring-carousel.json +1 -0
  170. package/registry/ruler-time-picker/files/src/components/ui/ruler-time-picker.tsx +832 -0
  171. package/registry/ruler-time-picker/files/src/lib/kit.tsx +672 -0
  172. package/registry/ruler-time-picker.json +26 -0
  173. package/registry/scratch-card.json +1 -0
  174. package/registry/search-bar/files/src/components/ui/search-bar.tsx +28 -28
  175. package/registry/search-bar/files/src/lib/kit.tsx +462 -12
  176. package/registry/search-bar.json +1 -0
  177. package/registry/search-results.json +4 -0
  178. package/registry/segmented-control/files/src/components/ui/segmented-control.tsx +11 -17
  179. package/registry/segmented-control/files/src/lib/kit.tsx +462 -12
  180. package/registry/segmented-control.json +1 -0
  181. package/registry/select/files/src/components/ui/select.tsx +107 -104
  182. package/registry/select/files/src/lib/kit.tsx +462 -12
  183. package/registry/select.json +6 -0
  184. package/registry/settings.json +1 -0
  185. package/registry/sign-in.json +1 -0
  186. package/registry/skeleton/files/src/components/ui/skeleton.tsx +149 -80
  187. package/registry/skeleton/files/src/lib/kit.tsx +462 -12
  188. package/registry/skeleton.json +1 -0
  189. package/registry/slide-to-confirm.json +1 -0
  190. package/registry/slider/files/src/components/ui/slider.tsx +106 -108
  191. package/registry/slider/files/src/lib/kit.tsx +462 -12
  192. package/registry/slider.json +5 -0
  193. package/registry/spin-wheel.json +1 -0
  194. package/registry/spinner/files/src/components/ui/spinner.tsx +39 -29
  195. package/registry/spinner/files/src/lib/kit.tsx +462 -12
  196. package/registry/spinner.json +6 -0
  197. package/registry/stateful-button/files/src/components/ui/stateful-button.tsx +39 -32
  198. package/registry/stateful-button/files/src/lib/kit.tsx +462 -12
  199. package/registry/stateful-button.json +5 -0
  200. package/registry/stepper/files/src/components/ui/stepper.tsx +40 -38
  201. package/registry/stepper/files/src/lib/kit.tsx +462 -12
  202. package/registry/stepper.json +1 -0
  203. package/registry/swipe-deck.json +1 -0
  204. package/registry/swipeable-row.json +4 -0
  205. package/registry/switch/files/src/components/ui/switch.tsx +41 -47
  206. package/registry/switch/files/src/lib/kit.tsx +462 -12
  207. package/registry/switch.json +1 -0
  208. package/registry/tabs/files/src/components/ui/tabs.tsx +61 -64
  209. package/registry/tabs/files/src/lib/kit.tsx +462 -12
  210. package/registry/tabs.json +1 -0
  211. package/registry/text-animation/files/src/components/ui/text-animation.tsx +55 -42
  212. package/registry/text-animation/files/src/lib/kit.tsx +462 -12
  213. package/registry/text-animation.json +7 -0
  214. package/registry/textarea/files/src/components/ui/textarea.tsx +10 -10
  215. package/registry/textarea/files/src/lib/kit.tsx +462 -12
  216. package/registry/textarea.json +1 -0
  217. package/registry/ticket-card.json +1 -0
  218. package/registry/ticket-shape/files/src/lib/kit.tsx +462 -12
  219. package/registry/ticket-shape/files/src/lib/ticket-shape.tsx +54 -44
  220. package/registry/ticket-shape.json +1 -0
  221. package/registry/tilt-card/files/src/components/ui/tilt-card.tsx +80 -101
  222. package/registry/tilt-card/files/src/lib/kit.tsx +462 -12
  223. package/registry/tilt-card.json +1 -0
  224. package/registry/time-picker/files/src/components/ui/time-picker.tsx +136 -131
  225. package/registry/time-picker/files/src/lib/kit.tsx +462 -12
  226. package/registry/time-picker.json +1 -0
  227. package/registry/timeline/files/src/components/ui/avatar.tsx +89 -74
  228. package/registry/timeline/files/src/components/ui/timeline.tsx +49 -57
  229. package/registry/timeline/files/src/lib/kit.tsx +462 -12
  230. package/registry/timeline-chart.json +1 -0
  231. package/registry/timeline.json +1 -0
  232. package/registry/toast/files/src/components/ui/toast.tsx +543 -465
  233. package/registry/toast/files/src/lib/kit.tsx +462 -12
  234. package/registry/toast.json +7 -5
  235. package/registry/treemap.json +1 -0
  236. package/registry/waterfall.json +1 -0
  237. package/registry/wheel-list.json +1 -0
  238. package/schema/components.schema.json +1 -0
  239. package/registry/alert/files/src/components/ui/button.tsx +0 -303
  240. package/registry/confetti/files/src/lib/kit.tsx +0 -222
  241. package/registry/grain/files/src/lib/kit.tsx +0 -222
  242. package/registry/toast/files/src/components/ui/button.tsx +0 -303
@@ -1,5 +1,5 @@
1
1
  import * as Haptics from 'expo-haptics';
2
- import React, { useEffect, useId, useRef, useState } from 'react';
2
+ import React, { useEffect, useId, useLayoutEffect, useRef, useState } from 'react';
3
3
  import {
4
4
  AccessibilityInfo,
5
5
  ActivityIndicator,
@@ -39,68 +39,68 @@ export interface DialogAction {
39
39
  * Receives the prompt's text (if any). Return a promise to show a spinner on the button until
40
40
  * it settles. Return `false` (or resolve to it) to keep the dialog open and shake it as invalid.
41
41
  */
42
- onPress?: (value: string) => void | boolean | Promise<void | boolean>;
42
+ onPress?: ((value: string) => void | boolean | Promise<void | boolean>) | undefined;
43
43
  /** 'primary' is the main call to action; 'destructive' uses the danger colour; 'cancel' is the quiet one. */
44
- role?: 'primary' | 'default' | 'destructive' | 'cancel';
45
- disabled?: boolean;
44
+ role?: 'primary' | 'default' | 'destructive' | 'cancel' | undefined;
45
+ disabled?: boolean | undefined;
46
46
  }
47
47
 
48
48
  /** A single-line text field inside the dialog (a prompt). */
49
49
  export interface DialogPrompt {
50
- defaultValue?: string;
50
+ defaultValue?: string | undefined;
51
51
  /** Controlled text. */
52
- value?: string;
53
- onChangeText?: (value: string) => void;
54
- placeholder?: string;
52
+ value?: string | undefined;
53
+ onChangeText?: ((value: string) => void) | undefined;
54
+ placeholder?: string | undefined;
55
55
  /** Accessibility label of the field (default: the placeholder or title). */
56
- label?: string;
57
- secureTextEntry?: boolean;
58
- keyboardType?: KeyboardTypeOptions;
59
- autoCapitalize?: TextInputProps['autoCapitalize'];
60
- maxLength?: number;
56
+ label?: string | undefined;
57
+ secureTextEntry?: boolean | undefined;
58
+ keyboardType?: KeyboardTypeOptions | undefined;
59
+ autoCapitalize?: TextInputProps['autoCapitalize'] | undefined;
60
+ maxLength?: number | undefined;
61
61
  /** Select the text when the dialog opens (default true). */
62
- selectTextOnFocus?: boolean;
62
+ selectTextOnFocus?: boolean | undefined;
63
63
  }
64
64
 
65
65
  export interface DialogProps {
66
- open?: boolean;
67
- defaultOpen?: boolean;
68
- onOpenChange?: (open: boolean) => void;
66
+ open?: boolean | undefined;
67
+ defaultOpen?: boolean | undefined;
68
+ onOpenChange?: ((open: boolean) => void) | undefined;
69
69
  /** `sheet` is deprecated and renders as `default`. */
70
- variant?: DialogVariant;
70
+ variant?: DialogVariant | undefined;
71
71
  /** Living icon in a halo above the title, plus a soft glow of its colour. Destructive defaults to a warning icon. */
72
- tone?: DialogTone;
72
+ tone?: DialogTone | undefined;
73
73
  /** `modern` pill buttons (default) or `ios` hairline-separated text buttons. */
74
- appearance?: DialogAppearance;
75
- title?: string;
76
- description?: string;
74
+ appearance?: DialogAppearance | undefined;
75
+ title?: string | undefined;
76
+ description?: string | undefined;
77
77
  /** Custom content between the description and the actions. */
78
- children?: React.ReactNode;
78
+ children?: React.ReactNode | undefined;
79
79
  /** Turns the dialog into a prompt with a text field; the text is passed to `onConfirm` / `onPress`. */
80
- prompt?: DialogPrompt;
80
+ prompt?: DialogPrompt | undefined;
81
81
  /** Error text under the description / field, in the danger colour. */
82
- error?: string;
82
+ error?: string | undefined;
83
83
  /** Buttons. Defaults to Cancel + Confirm built from the labels below. */
84
- actions?: DialogAction[];
85
- confirmLabel?: string;
84
+ actions?: DialogAction[] | undefined;
85
+ confirmLabel?: string | undefined;
86
86
  /** Label of the default cancel button; `null` leaves only the confirm button. */
87
- cancelLabel?: string | null;
88
- onConfirm?: DialogAction['onPress'];
87
+ cancelLabel?: string | null | undefined;
88
+ onConfirm?: DialogAction['onPress'] | undefined;
89
89
  /** Called when the default cancel button, the scrim, back or Escape closes the dialog. */
90
- onCancel?: () => void;
90
+ onCancel?: (() => void) | undefined;
91
91
  /** Spinner on the confirm button and every other button disabled (controlled busy state). */
92
- loading?: boolean;
92
+ loading?: boolean | undefined;
93
93
  /** `auto` puts two short buttons side by side and stacks the rest. */
94
- actionsLayout?: 'auto' | 'row' | 'stack';
94
+ actionsLayout?: 'auto' | 'row' | 'stack' | undefined;
95
95
  /** Custom icon inside the halo, or `false` to hide the tone icon. */
96
- icon?: React.ReactNode | false;
96
+ icon?: React.ReactNode | false | undefined;
97
97
  /** Close when the scrim is tapped, on back and on Escape (default true). */
98
- dismissible?: boolean;
98
+ dismissible?: boolean | undefined;
99
99
  /** Notification haptic on open (warning for destructive, success for success) and error on shake (default true). */
100
- haptics?: boolean;
100
+ haptics?: boolean | undefined;
101
101
  /** Colour of the primary action (default: theme primary; accent in `ios`). */
102
- accent?: string;
103
- style?: StyleProp<ViewStyle>;
102
+ accent?: string | undefined;
103
+ style?: StyleProp<ViewStyle> | undefined;
104
104
  }
105
105
 
106
106
  const SHAKE = [10, -9, 7, -5, 3, 0];
@@ -129,7 +129,7 @@ export function Dialog({
129
129
  error,
130
130
  actions,
131
131
  confirmLabel,
132
- cancelLabel = 'Cancel',
132
+ cancelLabel: cancelLabelProp,
133
133
  onConfirm,
134
134
  onCancel,
135
135
  loading = false,
@@ -140,7 +140,8 @@ export function Dialog({
140
140
  accent,
141
141
  style,
142
142
  }: DialogProps) {
143
- const { colors, radius, dark, font } = useKit();
143
+ const { colors, radius, dark, font, labels } = useKit();
144
+ const cancelLabel = cancelLabelProp === undefined ? labels.cancel : cancelLabelProp; // null hides it
144
145
  const ff = font.family ? { fontFamily: font.family } : null;
145
146
  const uid = useId().replace(/[^a-zA-Z0-9]/g, '');
146
147
  const reduceMotion = useReduceMotion();
@@ -149,9 +150,9 @@ export function Dialog({
149
150
  const [inner, setInner] = useState(defaultOpen);
150
151
  const isOpen = open ?? inner;
151
152
  // Stays mounted while the exit animation runs; cleared in its completion callback.
152
- const keep = useRef(isOpen);
153
- const [, rerender] = useState(0);
154
- const mounted = isOpen || keep.current;
153
+ const [keep, setKeep] = useState(isOpen);
154
+ if (isOpen && !keep) setKeep(true);
155
+ const mounted = isOpen || keep;
155
156
  const [busy, setBusy] = useState<number | null>(null);
156
157
  // null = untouched since opening, so the field shows `prompt.defaultValue`.
157
158
  const [text, setText] = useState<string | null>(null);
@@ -160,12 +161,12 @@ export function Dialog({
160
161
  const value = prompt?.value ?? text ?? prompt?.defaultValue ?? '';
161
162
 
162
163
  // Native: card life (opacity + scale), scrim, shake, icon glyph pop, halo ripple. JS: icon outline draw.
163
- const t = useRef(new Animated.Value(0)).current;
164
- const scrim = useRef(new Animated.Value(0)).current;
165
- const shake = useRef(new Animated.Value(0)).current;
166
- const draw = useRef(new Animated.Value(0)).current;
167
- const glyph = useRef(new Animated.Value(0)).current;
168
- const ripple = useRef(new Animated.Value(0)).current;
164
+ const [t] = useState(() => new Animated.Value(0));
165
+ const [scrim] = useState(() => new Animated.Value(0));
166
+ const [shake] = useState(() => new Animated.Value(0));
167
+ const [draw] = useState(() => new Animated.Value(0));
168
+ const [glyph] = useState(() => new Animated.Value(0));
169
+ const [ripple] = useState(() => new Animated.Value(0));
169
170
 
170
171
  const tones: Record<DialogTone, string> = {
171
172
  info: dark ? '#60a5fa' : '#2563eb',
@@ -181,7 +182,7 @@ export function Dialog({
181
182
  const list: DialogAction[] = actions ?? [
182
183
  ...(cancelLabel !== null ? [{ label: cancelLabel, role: 'cancel' as const, onPress: () => onCancel?.() }] : []),
183
184
  {
184
- label: confirmLabel ?? (destructive ? 'Delete' : 'Continue'),
185
+ label: confirmLabel ?? (destructive ? labels.delete : labels.continue),
185
186
  role: destructive ? ('destructive' as const) : ('primary' as const),
186
187
  onPress: onConfirm,
187
188
  },
@@ -202,7 +203,9 @@ export function Dialog({
202
203
  setOpen(false);
203
204
  };
204
205
  const live = useRef({ requestClose });
205
- live.current = { requestClose };
206
+ useLayoutEffect(() => {
207
+ live.current = { requestClose };
208
+ });
206
209
 
207
210
  const playIcon = () => {
208
211
  if (reduceMotion) {
@@ -221,7 +224,6 @@ export function Dialog({
221
224
 
222
225
  useEffect(() => {
223
226
  if (isOpen) {
224
- keep.current = true;
225
227
  shake.setValue(0);
226
228
  if (haptics) {
227
229
  const type =
@@ -245,10 +247,9 @@ export function Dialog({
245
247
  Animated.timing(scrim, { toValue: 0, duration: 200, easing: Easing.in(Easing.quad), useNativeDriver: true }),
246
248
  ]).start(({ finished }) => {
247
249
  if (!finished) return;
248
- keep.current = false;
250
+ setKeep(false);
249
251
  setText(null);
250
252
  setBusy(null);
251
- rerender((n) => n + 1);
252
253
  });
253
254
  }
254
255
  // eslint-disable-next-line react-hooks/exhaustive-deps
@@ -330,7 +331,10 @@ export function Dialog({
330
331
  autoFocus
331
332
  maxFontSizeMultiplier={FONT_CAP}
332
333
  returnKeyType="done"
333
- onSubmitEditing={() => run(list[confirmIndex], confirmIndex)}
334
+ onSubmitEditing={() => {
335
+ const confirm = list[confirmIndex];
336
+ if (confirm) run(confirm, confirmIndex);
337
+ }}
334
338
  onFocus={() => setFocused(true)}
335
339
  onBlur={() => setFocused(false)}
336
340
  selectionColor={accent ?? colors.accent}
@@ -476,13 +480,13 @@ export function Dialog({
476
480
  maxWidth: ios ? 300 : 340,
477
481
  borderRadius: corner,
478
482
  backgroundColor: colors.popover,
479
- shadowOpacity: dark ? 0.55 : 0.18,
483
+ boxShadow: `0px 16px 64px rgba(0,0,0,${dark ? 0.55 : 0.18})`,
480
484
  },
481
485
  lifted,
482
486
  style,
483
487
  ]}
484
488
  >
485
- <View style={[styles.contact, { borderRadius: corner, backgroundColor: colors.popover, shadowOpacity: dark ? 0.3 : 0.06 }]}>
489
+ <View style={{ borderRadius: corner, backgroundColor: colors.popover, boxShadow: `0px 1px 6px rgba(0,0,0,${dark ? 0.3 : 0.06})` }}>
486
490
  <View
487
491
  onLayout={(e) => {
488
492
  const { width: w, height: h } = e.nativeEvent.layout;
@@ -522,7 +526,7 @@ function PillButton({
522
526
  }) {
523
527
  const { font } = useKit();
524
528
  const ff = font.family ? { fontFamily: font.family } : null;
525
- const press = useRef(new Animated.Value(0)).current;
529
+ const [press] = useState(() => new Animated.Value(0));
526
530
  const to = (v: number) => Animated.spring(press, { toValue: v, useNativeDriver: true, ...motion.snappy }).start();
527
531
  return (
528
532
  <Pressable
@@ -575,7 +579,7 @@ function IosButton({
575
579
  }) {
576
580
  const { font } = useKit();
577
581
  const ff = font.family ? { fontFamily: font.family } : null;
578
- const hl = useRef(new Animated.Value(0)).current;
582
+ const [hl] = useState(() => new Animated.Value(0));
579
583
  return (
580
584
  <Pressable
581
585
  onPress={onPress}
@@ -734,14 +738,8 @@ function useReduceMotion() {
734
738
 
735
739
  const styles = StyleSheet.create({
736
740
  center: { flex: 1, alignItems: 'center', justifyContent: 'center', padding: 24 },
737
- ambient: {
738
- width: '100%',
739
- shadowColor: '#000',
740
- shadowRadius: 32,
741
- shadowOffset: { width: 0, height: 16 },
742
- elevation: 18,
743
- },
744
- contact: { shadowColor: '#000', shadowRadius: 3, shadowOffset: { width: 0, height: 1 } },
741
+ // Shadows are boxShadow (set inline): the same on iOS, Android and web.
742
+ ambient: { width: '100%' },
745
743
  clip: { overflow: 'hidden', borderWidth: StyleSheet.hairlineWidth },
746
744
  content: { paddingHorizontal: 22, paddingTop: 24 },
747
745
  contentIos: { paddingHorizontal: 18, paddingTop: 20, paddingBottom: 18 },
@@ -762,8 +760,8 @@ const styles = StyleSheet.create({
762
760
  flex: { flex: 1 },
763
761
  actions: { gap: 10, padding: 22, paddingTop: 22 },
764
762
  pill: { minHeight: 48, alignItems: 'center', justifyContent: 'center', paddingHorizontal: 18 },
765
- pillText: { fontSize: 16, lineHeight: 21, fontWeight: '400', letterSpacing: -0.1 },
763
+ pillText: { fontSize: 16, lineHeight: 21, fontWeight: '400', letterSpacing: -0.1, includeFontPadding: false, textAlignVertical: 'center' },
766
764
  iosActions: { borderTopWidth: StyleSheet.hairlineWidth },
767
765
  iosButton: { minHeight: 46, alignItems: 'center', justifyContent: 'center', paddingHorizontal: 12 },
768
- iosText: { fontSize: 17, lineHeight: 22, fontWeight: '400', letterSpacing: -0.3 },
766
+ iosText: { fontSize: 17, lineHeight: 22, fontWeight: '400', letterSpacing: -0.3, includeFontPadding: false, textAlignVertical: 'center' },
769
767
  });