@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
@@ -3,7 +3,6 @@ import {
3
3
  AccessibilityInfo,
4
4
  Animated,
5
5
  Easing,
6
- PanResponder,
7
6
  Pressable,
8
7
  StyleSheet,
9
8
  Text,
@@ -14,7 +13,7 @@ import {
14
13
  } from 'react-native';
15
14
  import Svg, { Path } from 'react-native-svg';
16
15
 
17
- import { alpha, motion, readableOn, useKit } from '@/lib/kit';
16
+ import { alpha, motion, readableOn, useKit, usePanResponder } from '@/lib/kit';
18
17
 
19
18
  export type CalendarMode = 'single' | 'range' | 'multiple';
20
19
 
@@ -30,65 +29,65 @@ export type CalendarMarks = Record<string, string | string[]>;
30
29
 
31
30
  export interface CalendarBaseProps {
32
31
  /** Controlled visible month (any date inside it). */
33
- month?: Date;
32
+ month?: Date | undefined;
34
33
  /** Month shown first (default: the selected date, else today). */
35
- defaultMonth?: Date;
36
- onMonthChange?: (month: Date) => void;
34
+ defaultMonth?: Date | undefined;
35
+ onMonthChange?: ((month: Date) => void) | undefined;
37
36
  /** 0 = Sunday, 1 = Monday. */
38
- weekStartsOn?: 0 | 1;
37
+ weekStartsOn?: 0 | 1 | undefined;
39
38
  /** BCP 47 locale for month and weekday names (default: device locale). */
40
- locale?: string;
39
+ locale?: string | undefined;
41
40
  /** Earliest selectable day. */
42
- minDate?: Date;
41
+ minDate?: Date | undefined;
43
42
  /** Latest selectable day. */
44
- maxDate?: Date;
43
+ maxDate?: Date | undefined;
45
44
  /** Return true to disable a day (booked, holidays…). */
46
- isDateDisabled?: (date: Date) => boolean;
45
+ isDateDisabled?: ((date: Date) => boolean) | undefined;
47
46
  /** Coloured dots under dates: `{ [toDateKey(date)]: '#22c55e' | ['#22c55e', '#f59e0b'] }`. */
48
- markedDates?: CalendarMarks;
47
+ markedDates?: CalendarMarks | undefined;
49
48
  /** Fill whole days with a colour (birthdays, shifts, people…): `{ [toDateKey(date)]: '#f472b6' }`. */
50
- highlightedDates?: Record<string, string>;
49
+ highlightedDates?: Record<string, string> | undefined;
51
50
  /** `tiles` puts every day on a soft tile; `minimal` shows bare numbers. */
52
- variant?: 'tiles' | 'minimal';
51
+ variant?: 'tiles' | 'minimal' | undefined;
53
52
  /** Weekday header: `narrow` (M T W) or `short` (Mon Tue Wed). */
54
- weekdayFormat?: 'narrow' | 'short';
53
+ weekdayFormat?: 'narrow' | 'short' | undefined;
55
54
  /** Show a "Today" pill in the header while another month is on screen. */
56
- showTodayButton?: boolean;
55
+ showTodayButton?: boolean | undefined;
57
56
  /** Show the faded trailing / leading days of the neighbouring months. */
58
- showOutsideDays?: boolean;
57
+ showOutsideDays?: boolean | undefined;
59
58
  /** Ring and tint today's date. */
60
- showToday?: boolean;
59
+ showToday?: boolean | undefined;
61
60
  /** Always render six week rows so the height never changes between months. */
62
- fixedWeeks?: boolean;
61
+ fixedWeeks?: boolean | undefined;
63
62
  /** Tap the month title to jump through a month / year grid. */
64
- monthPicker?: boolean;
63
+ monthPicker?: boolean | undefined;
65
64
  /** Most dates selectable in `multiple` mode. */
66
- max?: number;
65
+ max?: number | undefined;
67
66
  /** Selection and today colour (default: theme accent). */
68
- accent?: string;
69
- style?: StyleProp<ViewStyle>;
67
+ accent?: string | undefined;
68
+ style?: StyleProp<ViewStyle> | undefined;
70
69
  }
71
70
 
72
71
  export interface CalendarSingleProps {
73
- mode?: 'single';
74
- value?: Date | null;
75
- defaultValue?: Date | null;
76
- onChange?: (date: Date) => void;
72
+ mode?: 'single' | undefined;
73
+ value?: Date | null | undefined;
74
+ defaultValue?: Date | null | undefined;
75
+ onChange?: ((date: Date) => void) | undefined;
77
76
  }
78
77
 
79
78
  export interface CalendarRangeProps {
80
79
  mode: 'range';
81
- value?: DateRange | null;
82
- defaultValue?: DateRange | null;
80
+ value?: DateRange | null | undefined;
81
+ defaultValue?: DateRange | null | undefined;
83
82
  /** Fires on every tap: first with `{ start, end: null }`, then with both ends. */
84
- onChange?: (range: DateRange) => void;
83
+ onChange?: ((range: DateRange) => void) | undefined;
85
84
  }
86
85
 
87
86
  export interface CalendarMultipleProps {
88
87
  mode: 'multiple';
89
- value?: Date[];
90
- defaultValue?: Date[];
91
- onChange?: (dates: Date[]) => void;
88
+ value?: Date[] | undefined;
89
+ defaultValue?: Date[] | undefined;
90
+ onChange?: ((dates: Date[]) => void) | undefined;
92
91
  }
93
92
 
94
93
  export type CalendarProps = CalendarBaseProps & (CalendarSingleProps | CalendarRangeProps | CalendarMultipleProps);
@@ -161,11 +160,11 @@ function useFormatters(locale?: string) {
161
160
  }
162
161
  };
163
162
  return {
164
- title: make({ month: 'long', year: 'numeric' }, (d) => `${EN_MONTHS[d.getMonth()]} ${d.getFullYear()}`),
165
- month: make({ month: 'short' }, (d) => EN_MONTHS[d.getMonth()].slice(0, 3)),
166
- weekday: make({ weekday: 'short' }, (d) => EN_DAYS[d.getDay()]),
167
- weekdayNarrow: make({ weekday: 'narrow' }, (d) => EN_DAYS[d.getDay()][0]),
168
- weekdayLong: make({ weekday: 'long' }, (d) => EN_DAYS[d.getDay()]),
163
+ title: make({ month: 'long', year: 'numeric' }, (d) => `${EN_MONTHS[d.getMonth()] ?? ''} ${d.getFullYear()}`),
164
+ month: make({ month: 'short' }, (d) => (EN_MONTHS[d.getMonth()] ?? '').slice(0, 3)),
165
+ weekday: make({ weekday: 'short' }, (d) => EN_DAYS[d.getDay()] ?? ''),
166
+ weekdayNarrow: make({ weekday: 'narrow' }, (d) => (EN_DAYS[d.getDay()] ?? '').slice(0, 1)),
167
+ weekdayLong: make({ weekday: 'long' }, (d) => EN_DAYS[d.getDay()] ?? ''),
169
168
  full: make({ weekday: 'long', day: 'numeric', month: 'long', year: 'numeric' }, (d) => d.toDateString()),
170
169
  };
171
170
  }, [locale]);
@@ -206,7 +205,7 @@ export function Calendar(props: CalendarProps) {
206
205
  accent,
207
206
  style,
208
207
  } = props as unknown as FlatProps;
209
- const { colors, radius, font } = useKit();
208
+ const { colors, radius, font, labels } = useKit();
210
209
  const ff = font.family ? { fontFamily: font.family } : null;
211
210
  const tint = accent ?? colors.accent;
212
211
  const fmt = useFormatters(locale);
@@ -244,9 +243,10 @@ export function Calendar(props: CalendarProps) {
244
243
 
245
244
  /* month slide transition */
246
245
  const [width, setWidth] = useState(0);
247
- const slide = useRef(new Animated.Value(1)).current; // native
246
+ const [slide] = useState(() => new Animated.Value(1)); // native
248
247
  const [leaving, setLeaving] = useState<{ month: Date; dir: number } | null>(null);
249
- const dirRef = useRef(1);
248
+ // Which way the last month change went: the incoming grid slides in from that side.
249
+ const [slideDir, setSlideDir] = useState(1);
250
250
  const shownRef = useRef(visible);
251
251
  const visibleKey = monthIndex(visible);
252
252
  useLayoutEffect(() => {
@@ -254,7 +254,7 @@ export function Calendar(props: CalendarProps) {
254
254
  if (monthIndex(prev) === visibleKey) return;
255
255
  shownRef.current = visible;
256
256
  const dir = visibleKey > monthIndex(prev) ? 1 : -1;
257
- dirRef.current = dir;
257
+ setSlideDir(dir);
258
258
  setLeaving({ month: prev, dir });
259
259
  slide.stopAnimation();
260
260
  slide.setValue(0);
@@ -271,7 +271,7 @@ export function Calendar(props: CalendarProps) {
271
271
  /* days / months / years view */
272
272
  const [view, setView] = useState<'days' | 'months' | 'years'>('days');
273
273
  const [pickYear, setPickYear] = useState(visible.getFullYear());
274
- const viewAnim = useRef(new Animated.Value(1)).current; // native
274
+ const [viewAnim] = useState(() => new Animated.Value(1)); // native
275
275
  const [gridH, setGridH] = useState(0);
276
276
  const switchView = (next: 'days' | 'months' | 'years') => {
277
277
  if (next !== 'days' && view === 'days') setPickYear(visible.getFullYear());
@@ -283,7 +283,9 @@ export function Calendar(props: CalendarProps) {
283
283
 
284
284
  /* selection */
285
285
  const stateRef = useRef({ mode, current, value, onChange, max, visible, goTo });
286
- stateRef.current = { mode, current, value, onChange, max, visible, goTo };
286
+ useLayoutEffect(() => {
287
+ stateRef.current = { mode, current, value, onChange, max, visible, goTo };
288
+ });
287
289
  const onDayPress = useCallback((d: Date) => {
288
290
  const s = stateRef.current;
289
291
  let next: CalendarValue;
@@ -305,18 +307,14 @@ export function Calendar(props: CalendarProps) {
305
307
  if (monthIndex(d) !== monthIndex(s.visible)) s.goTo(d);
306
308
  }, []);
307
309
 
308
- const pan = useMemo(
309
- () =>
310
- PanResponder.create({
311
- onMoveShouldSetPanResponder: (_, g) => Math.abs(g.dx) > 14 && Math.abs(g.dx) > Math.abs(g.dy) * 1.4,
312
- onPanResponderRelease: (_, g) => {
313
- const s = stateRef.current;
314
- if (g.dx < -40 || g.vx < -0.5) s.goTo(addMonths(s.visible, 1));
315
- else if (g.dx > 40 || g.vx > 0.5) s.goTo(addMonths(s.visible, -1));
316
- },
317
- }),
318
- []
319
- );
310
+ const pan = usePanResponder({
311
+ onMoveShouldSetPanResponder: (_, g) => Math.abs(g.dx) > 14 && Math.abs(g.dx) > Math.abs(g.dy) * 1.4,
312
+ onPanResponderRelease: (_, g) => {
313
+ const s = stateRef.current;
314
+ if (g.dx < -40 || g.vx < -0.5) s.goTo(addMonths(s.visible, 1));
315
+ else if (g.dx > 40 || g.vx > 0.5) s.goTo(addMonths(s.visible, -1));
316
+ },
317
+ });
320
318
 
321
319
  const weekdays = useMemo(() => {
322
320
  const base = new Date(2023, 0, 1); // a Sunday
@@ -349,7 +347,7 @@ export function Calendar(props: CalendarProps) {
349
347
 
350
348
  const W = width || 320;
351
349
  // Reduce Motion: months swap with a fade only, no sideways slide.
352
- const dir = reduce ? 0 : dirRef.current;
350
+ const dir = reduce ? 0 : slideDir;
353
351
  const prevDisabled = view === 'days' ? monthIndex(visible) - 1 < minM : view === 'months' ? pickYear * 12 - 1 < minM : false;
354
352
  const nextDisabled = view === 'days' ? monthIndex(visible) + 1 > maxM : view === 'months' ? (pickYear + 1) * 12 > maxM : false;
355
353
  const decadeStart = Math.floor(pickYear / 12) * 12;
@@ -374,7 +372,7 @@ export function Calendar(props: CalendarProps) {
374
372
  onPress={monthPicker ? () => switchView(view === 'days' ? 'months' : view === 'months' ? 'years' : 'days') : undefined}
375
373
  disabled={!monthPicker}
376
374
  accessibilityRole={monthPicker ? 'button' : 'header'}
377
- accessibilityLabel={monthPicker ? `${title}, ${view === 'days' ? 'choose month' : view === 'months' ? 'choose year' : 'back to days'}` : title}
375
+ accessibilityLabel={monthPicker ? `${title}, ${view === 'days' ? labels.chooseMonth : view === 'months' ? labels.chooseYear : labels.backToDays}` : title}
378
376
  hitSlop={6}
379
377
  style={({ pressed }) => [styles.titleBtn, { borderRadius: radius.sm, backgroundColor: pressed ? colors.muted : 'transparent' }]}
380
378
  >
@@ -401,12 +399,12 @@ export function Calendar(props: CalendarProps) {
401
399
  <Pressable
402
400
  onPress={() => goTo(today)}
403
401
  accessibilityRole="button"
404
- accessibilityLabel="Go to today"
402
+ accessibilityLabel={labels.goToToday}
405
403
  hitSlop={4}
406
404
  style={({ pressed }) => [styles.todayBtn, { borderRadius: radius.capsule(32), backgroundColor: pressed ? colors.secondary : colors.muted }]}
407
405
  >
408
406
  <Text maxFontSizeMultiplier={FONT_CAP} style={[styles.todayText, ff, { color: tint }]}>
409
- Today
407
+ {labels.today}
410
408
  </Text>
411
409
  </Pressable>
412
410
  ) : null}
@@ -429,7 +427,7 @@ export function Calendar(props: CalendarProps) {
429
427
  </Text>
430
428
  ))}
431
429
  </View>
432
- <View {...pan.panHandlers} style={styles.gridClip} onLayout={(e) => setGridH(e.nativeEvent.layout.height)}>
430
+ <View {...pan} style={styles.gridClip} onLayout={(e) => setGridH(e.nativeEvent.layout.height)}>
433
431
  {leaving ? (
434
432
  <Animated.View
435
433
  pointerEvents="none"
@@ -525,16 +523,16 @@ interface MonthGridProps {
525
523
  fixedWeeks: boolean;
526
524
  showOutsideDays: boolean;
527
525
  showToday: boolean;
528
- minDate?: Date;
529
- maxDate?: Date;
530
- isDateDisabled?: (date: Date) => boolean;
531
- markedDates?: CalendarMarks;
532
- highlightedDates?: Record<string, string>;
526
+ minDate?: Date | undefined;
527
+ maxDate?: Date | undefined;
528
+ isDateDisabled?: ((date: Date) => boolean) | undefined;
529
+ markedDates?: CalendarMarks | undefined;
530
+ highlightedDates?: Record<string, string> | undefined;
533
531
  tiles: boolean;
534
- singleKey?: string;
535
- rangeStart?: number;
536
- rangeEnd?: number;
537
- manyKeys?: string;
532
+ singleKey?: string | undefined;
533
+ rangeStart?: number | undefined;
534
+ rangeEnd?: number | undefined;
535
+ manyKeys?: string | undefined;
538
536
  tint: string;
539
537
  fullLabel: (d: Date) => string;
540
538
  reduce: boolean;
@@ -636,8 +634,8 @@ interface DayCellProps {
636
634
  band: 'none' | 'start' | 'mid' | 'end';
637
635
  roundLeft: boolean;
638
636
  roundRight: boolean;
639
- marks?: string | string[];
640
- highlight?: string;
637
+ marks?: string | string[] | undefined;
638
+ highlight?: string | undefined;
641
639
  tile: boolean;
642
640
  tint: string;
643
641
  reduce: boolean;
@@ -665,8 +663,8 @@ const DayCell = memo(function DayCell({
665
663
  const { colors, radius, font } = useKit();
666
664
  const ff = font.family ? { fontFamily: font.family } : null;
667
665
  const r = tileRadius(radius.md);
668
- const pop = useRef(new Animated.Value(selected ? 1 : 0)).current; // native: circle scale + opacity
669
- const bandIn = useRef(new Animated.Value(band === 'none' ? 0 : 1)).current; // native: band opacity
666
+ const [pop] = useState(() => new Animated.Value(selected ? 1 : 0)); // native: circle scale + opacity
667
+ const [bandIn] = useState(() => new Animated.Value(band === 'none' ? 0 : 1)); // native: band opacity
670
668
  useEffect(() => {
671
669
  // Reduce Motion: the selection fills in with a quick fade, no scale pop.
672
670
  if (reduce) Animated.timing(pop, { toValue: selected ? 1 : 0, duration: 150, useNativeDriver: true }).start();
@@ -773,14 +771,14 @@ const DayCell = memo(function DayCell({
773
771
  /* ───────────────────────────────────── bits ───────────────────────────────────── */
774
772
 
775
773
  function NavButton({ dir, disabled, onPress }: { dir: 1 | -1; disabled: boolean; onPress: () => void }) {
776
- const { colors } = useKit();
774
+ const { colors, labels } = useKit();
777
775
  return (
778
776
  <Pressable
779
777
  onPress={onPress}
780
778
  disabled={disabled}
781
779
  hitSlop={4}
782
780
  accessibilityRole="button"
783
- accessibilityLabel={dir < 0 ? 'Previous' : 'Next'}
781
+ accessibilityLabel={dir < 0 ? labels.previous : labels.next}
784
782
  accessibilityState={{ disabled }}
785
783
  style={({ pressed }) => [styles.nav, { backgroundColor: pressed ? colors.secondary : colors.muted, opacity: disabled ? 0.3 : 1 }]}
786
784
  >
@@ -798,7 +796,7 @@ function NavButton({ dir, disabled, onPress }: { dir: 1 | -1; disabled: boolean;
798
796
  }
799
797
 
800
798
  function Chevron({ turned, color, reduce }: { turned: boolean; color: string; reduce: boolean }) {
801
- const turn = useRef(new Animated.Value(turned ? 1 : 0)).current; // native
799
+ const [turn] = useState(() => new Animated.Value(turned ? 1 : 0)); // native
802
800
  useEffect(() => {
803
801
  if (reduce) {
804
802
  turn.setValue(turned ? 1 : 0);
@@ -839,7 +837,7 @@ const styles = StyleSheet.create({
839
837
  navs: { flexDirection: 'row', alignItems: 'center', gap: 6 },
840
838
  nav: { width: 32, height: 32, borderRadius: 16, alignItems: 'center', justifyContent: 'center' },
841
839
  todayBtn: { minHeight: 32, paddingHorizontal: 12, alignItems: 'center', justifyContent: 'center' },
842
- todayText: { fontSize: 13, fontWeight: '400' },
840
+ todayText: { fontSize: 13, fontWeight: '400', includeFontPadding: false, textAlignVertical: 'center' },
843
841
  weekRow: { flexDirection: 'row', marginBottom: 6 },
844
842
  weekday: { flex: 1, textAlign: 'center', fontSize: 13, fontWeight: '400', letterSpacing: 0.2 },
845
843
  gridClip: { overflow: 'hidden' },
@@ -858,7 +856,7 @@ const styles = StyleSheet.create({
858
856
  alignSelf: 'center',
859
857
  },
860
858
  fill: { borderWidth: 0 },
861
- day: { fontSize: 15, fontWeight: '400', fontVariant: ['tabular-nums'] },
859
+ day: { fontSize: 15, fontWeight: '400', fontVariant: ['tabular-nums'], includeFontPadding: false, textAlignVertical: 'center' },
862
860
  dayStrong: { fontWeight: '400' },
863
861
  outside: { opacity: 0.4 },
864
862
  disabledText: { opacity: 0.35 },
@@ -867,5 +865,5 @@ const styles = StyleSheet.create({
867
865
  pickGrid: { flexDirection: 'row', flexWrap: 'wrap', alignContent: 'center', paddingTop: 4 },
868
866
  pickCell: { width: '33.333%', height: 56, alignItems: 'center', justifyContent: 'center' },
869
867
  pickInner: { minWidth: 76, minHeight: 40, paddingHorizontal: 14, alignItems: 'center', justifyContent: 'center', borderWidth: 1.5 },
870
- pickText: { fontSize: 15, fontWeight: '400' },
868
+ pickText: { fontSize: 15, fontWeight: '400', includeFontPadding: false, textAlignVertical: 'center' },
871
869
  });