@expokit/cli 0.4.4 → 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.
- package/README.md +30 -3
- package/bin/expo-kit.js +749 -288
- package/bin/lib.mjs +310 -3
- package/package.json +1 -1
- package/registry/_docs/action-sheet.json +1 -1
- package/registry/_docs/alert.json +6 -0
- package/registry/_docs/bottom-sheet.json +6 -0
- package/registry/_docs/bullet.json +6 -0
- package/registry/_docs/dialog.json +1 -1
- package/registry/_docs/drawer.json +3 -3
- package/registry/_docs/glass-search-bar.json +1 -1
- package/registry/_docs/grain.json +6 -1
- package/registry/_docs/isometric-bar.json +6 -0
- package/registry/_docs/liquidglass-tab.json +1 -1
- package/registry/_docs/password-input.json +1 -1
- package/registry/_docs/pixel-bar.json +6 -0
- package/registry/_docs/polar-area.json +6 -0
- package/registry/_docs/qr-code-button.json +9 -3
- package/registry/_docs/scratch-card.json +7 -1
- package/registry/_docs/search-bar.json +1 -1
- package/registry/_docs/select.json +2 -2
- package/registry/_docs/slide-to-confirm.json +2 -2
- package/registry/_docs/spinner.json +1 -1
- package/registry/_docs/stateful-button.json +2 -2
- package/registry/_docs/swipe-deck.json +1 -1
- package/registry/_docs/time-picker.json +2 -2
- package/registry/_docs/timeline-chart.json +6 -0
- package/registry/_docs/toast.json +15 -3
- package/registry/_docs/treemap.json +6 -0
- package/registry/_docs/waterfall.json +6 -0
- package/registry/accordion/files/src/components/ui/accordion.tsx +6 -4
- package/registry/accordion/files/src/lib/kit.tsx +363 -11
- package/registry/accordion.json +1 -0
- package/registry/action-sheet/files/src/components/ui/action-sheet.tsx +43 -48
- package/registry/action-sheet/files/src/lib/kit.tsx +363 -11
- package/registry/action-sheet.json +1 -0
- package/registry/alert/files/src/components/ui/alert.tsx +19 -12
- package/registry/alert/files/src/lib/kit.tsx +363 -11
- package/registry/alert.json +3 -4
- package/registry/assistant-app.json +1 -0
- package/registry/avatar/files/src/components/ui/avatar.tsx +84 -66
- package/registry/avatar/files/src/lib/kit.tsx +363 -11
- package/registry/avatar.json +1 -0
- package/registry/badge/files/src/components/ui/badge.tsx +34 -34
- package/registry/badge/files/src/lib/kit.tsx +363 -11
- package/registry/badge.json +1 -0
- package/registry/bottom-nav/files/src/components/ui/bottom-nav.tsx +28 -27
- package/registry/bottom-nav/files/src/lib/kit.tsx +363 -11
- package/registry/bottom-nav.json +5 -0
- package/registry/bottom-sheet/files/src/components/ui/bottom-sheet.tsx +353 -289
- package/registry/bottom-sheet/files/src/lib/kit.tsx +363 -11
- package/registry/bottom-sheet.json +5 -1
- package/registry/bullet.json +1 -0
- package/registry/button/files/src/components/ui/button.tsx +18 -16
- package/registry/button/files/src/lib/kit.tsx +363 -11
- package/registry/button-3d/files/src/components/ui/button-3d.tsx +2 -2
- package/registry/button-3d/files/src/lib/kit.tsx +363 -11
- package/registry/button-3d.json +1 -0
- package/registry/button.json +1 -0
- package/registry/calendar/files/src/components/ui/calendar.tsx +74 -76
- package/registry/calendar/files/src/lib/kit.tsx +363 -11
- package/registry/calendar.json +1 -0
- package/registry/card/files/src/components/ui/card.tsx +3 -3
- package/registry/card/files/src/lib/kit.tsx +363 -11
- package/registry/card-stack.json +1 -0
- package/registry/card.json +1 -0
- package/registry/carousel.json +1 -0
- package/registry/chat.json +7 -0
- package/registry/checkbox/files/src/components/ui/checkbox.tsx +4 -4
- package/registry/checkbox/files/src/lib/kit.tsx +363 -11
- package/registry/checkbox.json +1 -0
- package/registry/checkout.json +1 -0
- package/registry/chip-group/files/src/components/ui/chip-group.tsx +22 -22
- package/registry/chip-group/files/src/lib/kit.tsx +363 -11
- package/registry/chip-group.json +1 -0
- package/registry/confetti/files/src/components/ui/confetti.tsx +15 -14
- package/registry/confetti.json +3 -6
- package/registry/coupon/files/src/components/ui/coupon.tsx +42 -42
- package/registry/coupon/files/src/components/ui/flip-card.tsx +6 -5
- package/registry/coupon/files/src/components/ui/tilt-card.tsx +76 -91
- package/registry/coupon/files/src/lib/kit.tsx +363 -11
- package/registry/coupon/files/src/lib/ticket-shape.tsx +54 -44
- package/registry/coupon.json +1 -0
- package/registry/cube-pager.json +1 -0
- package/registry/dashboard.json +1 -0
- package/registry/date-picker/files/src/components/ui/calendar.tsx +74 -76
- package/registry/date-picker/files/src/components/ui/date-picker.tsx +55 -56
- package/registry/date-picker/files/src/lib/kit.tsx +363 -11
- package/registry/date-picker.json +1 -0
- package/registry/dialog/files/src/components/ui/dialog.tsx +60 -56
- package/registry/dialog/files/src/lib/kit.tsx +363 -11
- package/registry/dialog.json +1 -0
- package/registry/donut-shop.json +1 -0
- package/registry/drawer/files/src/components/ui/drawer.tsx +73 -69
- package/registry/drawer/files/src/lib/kit.tsx +363 -11
- package/registry/drawer.json +1 -0
- package/registry/fab.json +1 -0
- package/registry/fintech-app.json +1 -0
- package/registry/flip-calendar/files/src/components/ui/flip-calendar.tsx +92 -86
- package/registry/flip-calendar/files/src/lib/kit.tsx +363 -11
- package/registry/flip-calendar.json +7 -0
- package/registry/flip-card/files/src/components/ui/flip-card.tsx +6 -5
- package/registry/flip-card/files/src/lib/kit.tsx +363 -11
- package/registry/flip-card.json +1 -0
- package/registry/floating-input/files/src/components/ui/floating-input.tsx +33 -33
- package/registry/floating-input/files/src/lib/kit.tsx +363 -11
- package/registry/floating-input.json +1 -0
- package/registry/food-app.json +1 -0
- package/registry/gift-card.json +1 -0
- package/registry/glass-button.json +5 -0
- package/registry/glass-nav-bar.json +1 -0
- package/registry/glass-search-bar.json +1 -0
- package/registry/glass-segmented.json +1 -0
- package/registry/glass-sheet.json +1 -0
- package/registry/glass-tab-bar.json +5 -0
- package/registry/glass.json +1 -0
- package/registry/grain/files/src/components/ui/grain.tsx +16 -14
- package/registry/grain.json +8 -6
- package/registry/inbox.json +1 -0
- package/registry/isometric-bar.json +1 -0
- package/registry/kit/files/src/lib/kit.tsx +363 -11
- package/registry/kit.json +1 -0
- package/registry/liquidglass-tab/files/src/app/_layout.tsx +0 -1
- package/registry/liquidglass-tab/files/src/components/GlassTabBar.tsx +23 -9
- package/registry/liquidglass-tab/files/src/components/TabScreen.tsx +2 -2
- package/registry/liquidglass-tab/files/src/lib/tab-icons.ts +1 -1
- package/registry/liquidglass-tab.json +1 -0
- package/registry/list-item/files/src/components/ui/list-item.tsx +42 -42
- package/registry/list-item/files/src/lib/kit.tsx +363 -11
- package/registry/list-item.json +1 -0
- package/registry/loyalty-card.json +1 -0
- package/registry/morphing-button-group.json +1 -0
- package/registry/number-ticker.json +1 -0
- package/registry/offers.json +1 -0
- package/registry/onboarding.json +1 -0
- package/registry/orb-reveal.json +1 -0
- package/registry/otp-input/files/src/components/ui/otp-input.tsx +48 -29
- package/registry/otp-input/files/src/lib/kit.tsx +363 -11
- package/registry/otp-input.json +1 -0
- package/registry/parallax-layers.json +1 -0
- package/registry/parallax-scroll.json +1 -0
- package/registry/password-input/files/src/components/ui/floating-input.tsx +33 -33
- package/registry/password-input/files/src/components/ui/password-input.tsx +29 -25
- package/registry/password-input/files/src/lib/kit.tsx +363 -11
- package/registry/password-input.json +1 -0
- package/registry/payment-card/files/src/components/ui/flip-card.tsx +6 -5
- package/registry/payment-card/files/src/components/ui/payment-card.tsx +17 -17
- package/registry/payment-card/files/src/components/ui/tilt-card.tsx +76 -91
- package/registry/payment-card/files/src/lib/kit.tsx +363 -11
- package/registry/payment-card.json +1 -0
- package/registry/paywall.json +1 -0
- package/registry/pixel-bar.json +1 -0
- package/registry/polar-area.json +1 -0
- package/registry/profile.json +1 -0
- package/registry/progress/files/src/components/ui/progress.tsx +29 -29
- package/registry/progress/files/src/lib/kit.tsx +363 -11
- package/registry/progress-steps/files/src/components/ui/progress-steps.tsx +20 -20
- package/registry/progress-steps/files/src/lib/kit.tsx +363 -11
- package/registry/progress-steps.json +1 -0
- package/registry/progress.json +1 -0
- package/registry/qr-code-button.json +1 -0
- package/registry/radio-group/files/src/components/ui/radio-group.tsx +19 -19
- package/registry/radio-group/files/src/lib/kit.tsx +363 -11
- package/registry/radio-group.json +1 -0
- package/registry/rating.json +1 -0
- package/registry/ring-carousel.json +1 -0
- package/registry/ruler-time-picker/files/src/components/ui/ruler-time-picker.tsx +98 -82
- package/registry/ruler-time-picker/files/src/lib/kit.tsx +363 -11
- package/registry/ruler-time-picker.json +7 -0
- package/registry/scratch-card.json +1 -0
- package/registry/search-bar/files/src/components/ui/search-bar.tsx +25 -21
- package/registry/search-bar/files/src/lib/kit.tsx +363 -11
- package/registry/search-bar.json +1 -0
- package/registry/search-results.json +4 -0
- package/registry/segmented-control/files/src/components/ui/segmented-control.tsx +8 -7
- package/registry/segmented-control/files/src/lib/kit.tsx +363 -11
- package/registry/segmented-control.json +1 -0
- package/registry/select/files/src/components/ui/select.tsx +93 -88
- package/registry/select/files/src/lib/kit.tsx +363 -11
- package/registry/select.json +6 -0
- package/registry/settings.json +1 -0
- package/registry/sign-in.json +1 -0
- package/registry/skeleton/files/src/components/ui/skeleton.tsx +149 -80
- package/registry/skeleton/files/src/lib/kit.tsx +363 -11
- package/registry/skeleton.json +1 -0
- package/registry/slide-to-confirm.json +1 -0
- package/registry/slider/files/src/components/ui/slider.tsx +103 -96
- package/registry/slider/files/src/lib/kit.tsx +363 -11
- package/registry/slider.json +5 -0
- package/registry/spin-wheel.json +1 -0
- package/registry/spinner/files/src/components/ui/spinner.tsx +39 -29
- package/registry/spinner/files/src/lib/kit.tsx +363 -11
- package/registry/spinner.json +6 -0
- package/registry/stateful-button/files/src/components/ui/stateful-button.tsx +39 -32
- package/registry/stateful-button/files/src/lib/kit.tsx +363 -11
- package/registry/stateful-button.json +5 -0
- package/registry/stepper/files/src/components/ui/stepper.tsx +38 -36
- package/registry/stepper/files/src/lib/kit.tsx +363 -11
- package/registry/stepper.json +1 -0
- package/registry/swipe-deck.json +1 -0
- package/registry/swipeable-row.json +4 -0
- package/registry/switch/files/src/components/ui/switch.tsx +39 -42
- package/registry/switch/files/src/lib/kit.tsx +363 -11
- package/registry/switch.json +1 -0
- package/registry/tabs/files/src/components/ui/tabs.tsx +59 -62
- package/registry/tabs/files/src/lib/kit.tsx +363 -11
- package/registry/tabs.json +1 -0
- package/registry/text-animation/files/src/components/ui/text-animation.tsx +55 -42
- package/registry/text-animation/files/src/lib/kit.tsx +363 -11
- package/registry/text-animation.json +7 -0
- package/registry/textarea/files/src/components/ui/textarea.tsx +10 -10
- package/registry/textarea/files/src/lib/kit.tsx +363 -11
- package/registry/textarea.json +1 -0
- package/registry/ticket-card.json +1 -0
- package/registry/ticket-shape/files/src/lib/kit.tsx +363 -11
- package/registry/ticket-shape/files/src/lib/ticket-shape.tsx +54 -44
- package/registry/ticket-shape.json +1 -0
- package/registry/tilt-card/files/src/components/ui/tilt-card.tsx +76 -91
- package/registry/tilt-card/files/src/lib/kit.tsx +363 -11
- package/registry/tilt-card.json +1 -0
- package/registry/time-picker/files/src/components/ui/time-picker.tsx +122 -119
- package/registry/time-picker/files/src/lib/kit.tsx +363 -11
- package/registry/time-picker.json +1 -0
- package/registry/timeline/files/src/components/ui/avatar.tsx +84 -66
- package/registry/timeline/files/src/components/ui/timeline.tsx +44 -41
- package/registry/timeline/files/src/lib/kit.tsx +363 -11
- package/registry/timeline-chart.json +1 -0
- package/registry/timeline.json +1 -0
- package/registry/toast/files/src/components/ui/toast.tsx +541 -463
- package/registry/toast/files/src/lib/kit.tsx +363 -11
- package/registry/toast.json +7 -5
- package/registry/treemap.json +1 -0
- package/registry/waterfall.json +1 -0
- package/registry/wheel-list.json +1 -0
- package/schema/components.schema.json +1 -0
- package/registry/alert/files/src/components/ui/button.tsx +0 -290
- package/registry/confetti/files/src/lib/kit.tsx +0 -320
- package/registry/grain/files/src/lib/kit.tsx +0 -320
- package/registry/toast/files/src/components/ui/button.tsx +0 -290
|
@@ -1,5 +1,14 @@
|
|
|
1
|
-
import React, { createContext, useContext, useMemo } from 'react';
|
|
2
|
-
import {
|
|
1
|
+
import React, { createContext, useContext, useLayoutEffect, useMemo, useRef, useState } from 'react';
|
|
2
|
+
import {
|
|
3
|
+
PanResponder,
|
|
4
|
+
Platform,
|
|
5
|
+
useColorScheme,
|
|
6
|
+
useWindowDimensions,
|
|
7
|
+
type GestureResponderHandlers,
|
|
8
|
+
type PanResponderCallbacks,
|
|
9
|
+
type TextStyle,
|
|
10
|
+
type ViewStyle,
|
|
11
|
+
} from 'react-native';
|
|
3
12
|
|
|
4
13
|
/**
|
|
5
14
|
* ExpoKit design tokens. Every component reads them through useKit(), so one
|
|
@@ -9,9 +18,9 @@ import { Platform, useColorScheme, useWindowDimensions, type TextStyle, type Vie
|
|
|
9
18
|
|
|
10
19
|
/**
|
|
11
20
|
* Bumped whenever components start using a new kit API (2: radius.scale / radius.capsule,
|
|
12
|
-
* 3: useLayout / shadow). The CLI won't keep an edited kit.tsx older than the component being added needs.
|
|
21
|
+
* 3: useLayout / shadow, 4: labels, 5: visible labels such as Cancel / Done / Today, AM / PM, usePanResponder / useLatest). The CLI won't keep an edited kit.tsx older than the component being added needs.
|
|
13
22
|
*/
|
|
14
|
-
export const KIT_VERSION =
|
|
23
|
+
export const KIT_VERSION = 5;
|
|
15
24
|
|
|
16
25
|
export type ColorScheme = 'light' | 'dark';
|
|
17
26
|
|
|
@@ -60,10 +69,298 @@ export interface Theme {
|
|
|
60
69
|
space: (n: number) => number;
|
|
61
70
|
/** The same soft shadow on iOS, Android and web: `style={[styles.card, shadow('md')]}`. */
|
|
62
71
|
shadow: (level: ShadowLevel, color?: string) => ViewStyle;
|
|
63
|
-
font: { family?: string; mono: string };
|
|
72
|
+
font: { family?: string | undefined; mono: string };
|
|
64
73
|
text: Record<'xs' | 'sm' | 'md' | 'lg' | 'xl' | 'xxl', TextStyle>;
|
|
74
|
+
/** Text the kit shows or speaks on its own (buttons, placeholders, screen-reader names). Translate with <KitProvider labels={...}>. */
|
|
75
|
+
labels: Labels;
|
|
65
76
|
}
|
|
66
77
|
|
|
78
|
+
/**
|
|
79
|
+
* Every string the kit shows or speaks on its own: button text and placeholders (Cancel, Done, Today,
|
|
80
|
+
* Search…) and what screen readers say (close buttons, grabbers, hints). A prop on a component, like
|
|
81
|
+
* `cancelLabel` or `placeholder`, still wins over these.
|
|
82
|
+
* Pass a partial map to <KitProvider labels={...}>; keys you leave out stay English.
|
|
83
|
+
* Functions get the dynamic part, so word order can change per language.
|
|
84
|
+
*/
|
|
85
|
+
export interface Labels {
|
|
86
|
+
close: string;
|
|
87
|
+
dismiss: string;
|
|
88
|
+
closeSheet: string;
|
|
89
|
+
sheetGrabber: string;
|
|
90
|
+
sheetResizeHint: string;
|
|
91
|
+
sheetResizeOrCloseHint: string;
|
|
92
|
+
navigationDrawer: string;
|
|
93
|
+
closeDrawer: string;
|
|
94
|
+
closeMenu: string;
|
|
95
|
+
switchAccount: string;
|
|
96
|
+
openActions: string;
|
|
97
|
+
closeActions: string;
|
|
98
|
+
action: string;
|
|
99
|
+
loading: string;
|
|
100
|
+
clearSearch: string;
|
|
101
|
+
cancelSearch: string;
|
|
102
|
+
clearField: (field: string) => string;
|
|
103
|
+
back: string;
|
|
104
|
+
previous: string;
|
|
105
|
+
next: string;
|
|
106
|
+
goToToday: string;
|
|
107
|
+
goToSlide: (n: number) => string;
|
|
108
|
+
showAllCards: string;
|
|
109
|
+
expandNotification: string;
|
|
110
|
+
collapseNotification: string;
|
|
111
|
+
moreCount: (n: number) => string;
|
|
112
|
+
peopleCount: (n: number) => string;
|
|
113
|
+
namesAndMore: (names: string, n: number) => string;
|
|
114
|
+
newCount: (badge: string) => string;
|
|
115
|
+
remove: (item: string) => string;
|
|
116
|
+
selectedCount: (n: number) => string;
|
|
117
|
+
noneSelected: string;
|
|
118
|
+
notSet: string;
|
|
119
|
+
date: string;
|
|
120
|
+
time: string;
|
|
121
|
+
hour: string;
|
|
122
|
+
minute: string;
|
|
123
|
+
hours: (n: string) => string;
|
|
124
|
+
minutes: (n: number) => string;
|
|
125
|
+
booked: string;
|
|
126
|
+
unavailable: string;
|
|
127
|
+
timeDialHint: string;
|
|
128
|
+
flipCalendarHint: string;
|
|
129
|
+
increase: string;
|
|
130
|
+
decrease: string;
|
|
131
|
+
increaseItem: (item: string) => string;
|
|
132
|
+
decreaseItem: (item: string) => string;
|
|
133
|
+
range: string;
|
|
134
|
+
rangeMinimum: (name: string) => string;
|
|
135
|
+
rangeMaximum: (name: string) => string;
|
|
136
|
+
ratingStars: string;
|
|
137
|
+
ratingHearts: string;
|
|
138
|
+
showPassword: string;
|
|
139
|
+
hidePassword: string;
|
|
140
|
+
passwordStrength: (level: string) => string;
|
|
141
|
+
ruleMet: (rule: string) => string;
|
|
142
|
+
ruleUnmet: (rule: string) => string;
|
|
143
|
+
stepOf: (step: number, total: number, label: string) => string;
|
|
144
|
+
allStepsComplete: string;
|
|
145
|
+
stepCurrent: string;
|
|
146
|
+
stepCompleted: string;
|
|
147
|
+
stepNeedsAttention: string;
|
|
148
|
+
stepNotStarted: string;
|
|
149
|
+
goBackToStep: string;
|
|
150
|
+
activateCodeField: string;
|
|
151
|
+
qrCodeFor: (value: string) => string;
|
|
152
|
+
undoStroke: string;
|
|
153
|
+
signaturePad: string;
|
|
154
|
+
signaturePadSigned: string;
|
|
155
|
+
flipToBack: string;
|
|
156
|
+
flipToFront: string;
|
|
157
|
+
revealHint: string;
|
|
158
|
+
confirmHint: string;
|
|
159
|
+
prizeWheel: string;
|
|
160
|
+
spinHint: string;
|
|
161
|
+
prizes: (n: number, list: string) => string;
|
|
162
|
+
orbReveal: string;
|
|
163
|
+
orbBack: string;
|
|
164
|
+
// Visible text
|
|
165
|
+
cancel: string;
|
|
166
|
+
done: string;
|
|
167
|
+
doneCount: (n: number) => string;
|
|
168
|
+
doneDays: (n: number) => string;
|
|
169
|
+
clear: string;
|
|
170
|
+
continue: string;
|
|
171
|
+
delete: string;
|
|
172
|
+
failed: string;
|
|
173
|
+
search: string;
|
|
174
|
+
noResults: string;
|
|
175
|
+
noOptions: string;
|
|
176
|
+
nothingMatches: (query: string) => string;
|
|
177
|
+
selectPlaceholder: string;
|
|
178
|
+
selectDate: string;
|
|
179
|
+
selectDates: string;
|
|
180
|
+
pickStartDate: string;
|
|
181
|
+
pickEndDate: string;
|
|
182
|
+
selectTime: string;
|
|
183
|
+
setTime: (time: string) => string;
|
|
184
|
+
/** Clock periods, shown on 12-hour pickers and times. */
|
|
185
|
+
am: string;
|
|
186
|
+
pm: string;
|
|
187
|
+
/** Read for the AM / PM column. */
|
|
188
|
+
amPm: string;
|
|
189
|
+
morning: string;
|
|
190
|
+
afternoon: string;
|
|
191
|
+
evening: string;
|
|
192
|
+
slotsOpen: (n: number) => string;
|
|
193
|
+
full: string;
|
|
194
|
+
today: string;
|
|
195
|
+
tomorrow: string;
|
|
196
|
+
nextMonday: string;
|
|
197
|
+
inAWeek: string;
|
|
198
|
+
inAMonth: string;
|
|
199
|
+
next7Days: string;
|
|
200
|
+
nextWeekend: string;
|
|
201
|
+
thisMonth: string;
|
|
202
|
+
last7Days: string;
|
|
203
|
+
last30Days: string;
|
|
204
|
+
chooseOneOrMore: string;
|
|
205
|
+
/** After a rolling count, as in "2 selected". */
|
|
206
|
+
selectedSuffix: string;
|
|
207
|
+
chooseMonth: string;
|
|
208
|
+
chooseYear: string;
|
|
209
|
+
backToDays: string;
|
|
210
|
+
dayAndWeek: (day: number, week: number) => string;
|
|
211
|
+
daysLeft: (n: number) => string;
|
|
212
|
+
/** Too short, Weak, Okay, Strong, Very strong. */
|
|
213
|
+
passwordLevels: [string, string, string, string, string];
|
|
214
|
+
passwordsMatch: string;
|
|
215
|
+
passwordsDontMatch: string;
|
|
216
|
+
showQrCode: string;
|
|
217
|
+
copy: string;
|
|
218
|
+
copied: string;
|
|
219
|
+
slideToConfirm: string;
|
|
220
|
+
confirmed: string;
|
|
221
|
+
like: string;
|
|
222
|
+
nope: string;
|
|
223
|
+
swipeRight: string;
|
|
224
|
+
swipeLeft: string;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
export const defaultLabels: Labels = {
|
|
228
|
+
close: 'Close',
|
|
229
|
+
dismiss: 'Dismiss',
|
|
230
|
+
closeSheet: 'Close sheet',
|
|
231
|
+
sheetGrabber: 'Sheet grabber',
|
|
232
|
+
sheetResizeHint: 'Swipe up or down to resize',
|
|
233
|
+
sheetResizeOrCloseHint: 'Swipe up or down to resize or close',
|
|
234
|
+
navigationDrawer: 'Navigation drawer',
|
|
235
|
+
closeDrawer: 'Close drawer',
|
|
236
|
+
closeMenu: 'Close menu',
|
|
237
|
+
switchAccount: 'Switch account',
|
|
238
|
+
openActions: 'Open actions',
|
|
239
|
+
closeActions: 'Close actions',
|
|
240
|
+
action: 'Action',
|
|
241
|
+
loading: 'Loading',
|
|
242
|
+
clearSearch: 'Clear search',
|
|
243
|
+
cancelSearch: 'Cancel search',
|
|
244
|
+
clearField: (field) => `Clear ${field}`,
|
|
245
|
+
back: 'Back',
|
|
246
|
+
previous: 'Previous',
|
|
247
|
+
next: 'Next',
|
|
248
|
+
goToToday: 'Go to today',
|
|
249
|
+
goToSlide: (n) => `Go to slide ${n}`,
|
|
250
|
+
showAllCards: 'Shows all cards',
|
|
251
|
+
expandNotification: 'Expands the notification',
|
|
252
|
+
collapseNotification: 'Collapses the notification',
|
|
253
|
+
moreCount: (n) => `${n} more`,
|
|
254
|
+
peopleCount: (n) => `${n} people`,
|
|
255
|
+
namesAndMore: (names, n) => `${names} and ${n} more`,
|
|
256
|
+
newCount: (badge) => `${badge} new`,
|
|
257
|
+
remove: (item) => `Remove ${item}`,
|
|
258
|
+
selectedCount: (n) => `${n} selected`,
|
|
259
|
+
noneSelected: 'None selected',
|
|
260
|
+
notSet: 'Not set',
|
|
261
|
+
date: 'Date',
|
|
262
|
+
time: 'Time',
|
|
263
|
+
hour: 'Hour',
|
|
264
|
+
minute: 'Minute',
|
|
265
|
+
hours: (n) => `${n} hours`,
|
|
266
|
+
minutes: (n) => `${n} minutes`,
|
|
267
|
+
booked: 'booked',
|
|
268
|
+
unavailable: 'unavailable',
|
|
269
|
+
timeDialHint: 'Drag around the dial, or swipe up or down to adjust.',
|
|
270
|
+
flipCalendarHint: 'Swipe up to turn to the next day, down for the previous one.',
|
|
271
|
+
increase: 'Increase',
|
|
272
|
+
decrease: 'Decrease',
|
|
273
|
+
increaseItem: (item) => `Increase ${item}`,
|
|
274
|
+
decreaseItem: (item) => `Decrease ${item}`,
|
|
275
|
+
range: 'Range',
|
|
276
|
+
rangeMinimum: (name) => `${name} minimum`,
|
|
277
|
+
rangeMaximum: (name) => `${name} maximum`,
|
|
278
|
+
ratingStars: 'Rating, stars',
|
|
279
|
+
ratingHearts: 'Rating, hearts',
|
|
280
|
+
showPassword: 'Show password',
|
|
281
|
+
hidePassword: 'Hide password',
|
|
282
|
+
passwordStrength: (level) => `Password strength: ${level}`,
|
|
283
|
+
ruleMet: (rule) => `${rule}: done`,
|
|
284
|
+
ruleUnmet: (rule) => `${rule}: not yet`,
|
|
285
|
+
stepOf: (step, total, label) => `Step ${step} of ${total}, ${label}`,
|
|
286
|
+
allStepsComplete: 'All steps complete',
|
|
287
|
+
stepCurrent: 'current',
|
|
288
|
+
stepCompleted: 'completed',
|
|
289
|
+
stepNeedsAttention: 'needs attention',
|
|
290
|
+
stepNotStarted: 'not started',
|
|
291
|
+
goBackToStep: 'Goes back to this step',
|
|
292
|
+
activateCodeField: 'Activates the code field',
|
|
293
|
+
qrCodeFor: (value) => `QR code for ${value}`,
|
|
294
|
+
undoStroke: 'Undo last stroke',
|
|
295
|
+
signaturePad: 'Signature pad, draw your signature',
|
|
296
|
+
signaturePadSigned: 'Signature pad, signed',
|
|
297
|
+
flipToBack: 'Tap to flip to the back.',
|
|
298
|
+
flipToFront: 'Showing the back. Tap to flip to the front.',
|
|
299
|
+
revealHint: 'Double-tap to reveal',
|
|
300
|
+
confirmHint: 'Double tap to confirm',
|
|
301
|
+
prizeWheel: 'Prize wheel',
|
|
302
|
+
spinHint: 'Spins the wheel for a prize',
|
|
303
|
+
prizes: (n, list) => `${n} prizes: ${list}`,
|
|
304
|
+
orbReveal: 'Reveal',
|
|
305
|
+
orbBack: 'Glass orb, drag down to go back',
|
|
306
|
+
cancel: 'Cancel',
|
|
307
|
+
done: 'Done',
|
|
308
|
+
doneCount: (n) => `Done · ${n}`,
|
|
309
|
+
doneDays: (n) => `Done · ${n} days`,
|
|
310
|
+
clear: 'Clear',
|
|
311
|
+
continue: 'Continue',
|
|
312
|
+
delete: 'Delete',
|
|
313
|
+
failed: 'Failed',
|
|
314
|
+
search: 'Search',
|
|
315
|
+
noResults: 'No results',
|
|
316
|
+
noOptions: 'No options',
|
|
317
|
+
nothingMatches: (query) => `Nothing matches “${query}”.`,
|
|
318
|
+
selectPlaceholder: 'Select…',
|
|
319
|
+
selectDate: 'Select a date',
|
|
320
|
+
selectDates: 'Select dates',
|
|
321
|
+
pickStartDate: 'Pick a start date',
|
|
322
|
+
pickEndDate: 'pick an end date',
|
|
323
|
+
selectTime: 'Select a time',
|
|
324
|
+
setTime: (time) => `Set ${time}`,
|
|
325
|
+
am: 'AM',
|
|
326
|
+
pm: 'PM',
|
|
327
|
+
amPm: 'AM or PM',
|
|
328
|
+
morning: 'Morning',
|
|
329
|
+
afternoon: 'Afternoon',
|
|
330
|
+
evening: 'Evening',
|
|
331
|
+
slotsOpen: (n) => `${n} open`,
|
|
332
|
+
full: 'Full',
|
|
333
|
+
today: 'Today',
|
|
334
|
+
tomorrow: 'Tomorrow',
|
|
335
|
+
nextMonday: 'Next Monday',
|
|
336
|
+
inAWeek: 'In a week',
|
|
337
|
+
inAMonth: 'In a month',
|
|
338
|
+
next7Days: 'Next 7 days',
|
|
339
|
+
nextWeekend: 'Next weekend',
|
|
340
|
+
thisMonth: 'This month',
|
|
341
|
+
last7Days: 'Last 7 days',
|
|
342
|
+
last30Days: 'Last 30 days',
|
|
343
|
+
chooseOneOrMore: 'Choose one or more',
|
|
344
|
+
selectedSuffix: 'selected',
|
|
345
|
+
chooseMonth: 'choose month',
|
|
346
|
+
chooseYear: 'choose year',
|
|
347
|
+
backToDays: 'back to days',
|
|
348
|
+
dayAndWeek: (day, week) => `Day ${day} · Week ${week}`,
|
|
349
|
+
daysLeft: (n) => `${n} left`,
|
|
350
|
+
passwordLevels: ['Too short', 'Weak', 'Okay', 'Strong', 'Very strong'],
|
|
351
|
+
passwordsMatch: 'Passwords match',
|
|
352
|
+
passwordsDontMatch: "Passwords don't match",
|
|
353
|
+
showQrCode: 'Show QR Code',
|
|
354
|
+
copy: 'Copy',
|
|
355
|
+
copied: 'Copied',
|
|
356
|
+
slideToConfirm: 'Slide to confirm',
|
|
357
|
+
confirmed: 'Confirmed',
|
|
358
|
+
like: 'LIKE',
|
|
359
|
+
nope: 'NOPE',
|
|
360
|
+
swipeRight: 'Right',
|
|
361
|
+
swipeLeft: 'Left',
|
|
362
|
+
};
|
|
363
|
+
|
|
67
364
|
const light: Colors = {
|
|
68
365
|
background: '#ffffff',
|
|
69
366
|
foreground: '#09090b',
|
|
@@ -149,20 +446,27 @@ function build(scheme: ColorScheme, overrides?: ThemeOverrides): Theme {
|
|
|
149
446
|
xl: { fontSize: 22, lineHeight: 28, fontWeight: '400', letterSpacing: -0.3 },
|
|
150
447
|
xxl: { fontSize: 30, lineHeight: 36, fontWeight: '400', letterSpacing: -0.8 },
|
|
151
448
|
},
|
|
449
|
+
labels: overrides?.labels ? { ...defaultLabels, ...overrides.labels } : defaultLabels,
|
|
152
450
|
};
|
|
153
451
|
}
|
|
154
452
|
|
|
155
453
|
export interface ThemeOverrides {
|
|
156
454
|
/** Brand colour used for focus rings, selected states and accent buttons. */
|
|
157
|
-
accent?: string;
|
|
455
|
+
accent?: string | undefined;
|
|
456
|
+
|
|
158
457
|
/** Base corner radius in points (default 12). */
|
|
159
|
-
radius?: number;
|
|
160
|
-
|
|
458
|
+
radius?: number | undefined;
|
|
459
|
+
|
|
460
|
+
fontFamily?: string | undefined;
|
|
461
|
+
|
|
161
462
|
/** Override any token per scheme. */
|
|
162
|
-
colors?: Partial<Record<ColorScheme, Partial<Colors
|
|
463
|
+
colors?: Partial<Record<ColorScheme, Partial<Colors>>> | undefined;
|
|
464
|
+
|
|
465
|
+
/** Screen-reader strings in your language, e.g. { close: "बंद करें" }. Keys you leave out stay English. */
|
|
466
|
+
labels?: Partial<Labels> | undefined;
|
|
163
467
|
}
|
|
164
468
|
|
|
165
|
-
const KitContext = createContext<{ scheme?: ColorScheme; overrides?: ThemeOverrides } | null>(null);
|
|
469
|
+
const KitContext = createContext<{ scheme?: ColorScheme | undefined; overrides?: ThemeOverrides | undefined } | null>(null);
|
|
166
470
|
|
|
167
471
|
export function KitProvider({
|
|
168
472
|
scheme,
|
|
@@ -172,7 +476,7 @@ export function KitProvider({
|
|
|
172
476
|
const value = useMemo(
|
|
173
477
|
() => ({ scheme: scheme === 'system' ? undefined : scheme, overrides }),
|
|
174
478
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
175
|
-
[scheme, overrides.accent, overrides.radius, overrides.fontFamily, overrides.colors]
|
|
479
|
+
[scheme, overrides.accent, overrides.radius, overrides.fontFamily, overrides.colors, overrides.labels]
|
|
176
480
|
);
|
|
177
481
|
return <KitContext.Provider value={value}>{children}</KitContext.Provider>;
|
|
178
482
|
}
|
|
@@ -318,3 +622,51 @@ export function isTextNode(node: React.ReactNode): node is string | number | (st
|
|
|
318
622
|
if (typeof node === 'string' || typeof node === 'number') return true;
|
|
319
623
|
return Array.isArray(node) && node.length > 0 && node.every((n) => typeof n === 'string' || typeof n === 'number');
|
|
320
624
|
}
|
|
625
|
+
|
|
626
|
+
/**
|
|
627
|
+
* A ref that always holds the latest `value`, for gesture and timer callbacks that must not go stale.
|
|
628
|
+
* Read `.current` only inside callbacks and effects, never while rendering.
|
|
629
|
+
*/
|
|
630
|
+
export function useLatest<T>(value: T): React.MutableRefObject<T> {
|
|
631
|
+
const ref = useRef(value);
|
|
632
|
+
useLayoutEffect(() => {
|
|
633
|
+
ref.current = value;
|
|
634
|
+
});
|
|
635
|
+
return ref;
|
|
636
|
+
}
|
|
637
|
+
|
|
638
|
+
const panKeys = [
|
|
639
|
+
'onStartShouldSetPanResponder',
|
|
640
|
+
'onStartShouldSetPanResponderCapture',
|
|
641
|
+
'onMoveShouldSetPanResponder',
|
|
642
|
+
'onMoveShouldSetPanResponderCapture',
|
|
643
|
+
'onPanResponderGrant',
|
|
644
|
+
'onPanResponderStart',
|
|
645
|
+
'onPanResponderMove',
|
|
646
|
+
'onPanResponderEnd',
|
|
647
|
+
'onPanResponderRelease',
|
|
648
|
+
'onPanResponderReject',
|
|
649
|
+
'onPanResponderTerminate',
|
|
650
|
+
] as const;
|
|
651
|
+
|
|
652
|
+
/**
|
|
653
|
+
* PanResponder handlers that always call the latest `config`, created once. Write the callbacks inline:
|
|
654
|
+
* they may read refs and props freely, and nothing is recreated between renders, so a drag in progress
|
|
655
|
+
* is never cut off. Spread the result: `<View {...pan} />`.
|
|
656
|
+
*/
|
|
657
|
+
export function usePanResponder(config: PanResponderCallbacks): GestureResponderHandlers {
|
|
658
|
+
const latest = useLatest(config);
|
|
659
|
+
const [handlers] = useState(() => {
|
|
660
|
+
const forward: Record<string, (...args: never[]) => unknown> = {};
|
|
661
|
+
for (const key of panKeys) {
|
|
662
|
+
forward[key] = (...args) => (latest.current[key] as ((...a: never[]) => unknown) | undefined)?.(...args);
|
|
663
|
+
}
|
|
664
|
+
// React Native's defaults when these are left out are `true`, so keep them when the config has none.
|
|
665
|
+
forward.onPanResponderTerminationRequest = (...args) =>
|
|
666
|
+
(latest.current.onPanResponderTerminationRequest as ((...a: never[]) => boolean) | undefined)?.(...args) ?? true;
|
|
667
|
+
forward.onShouldBlockNativeResponder = (...args) =>
|
|
668
|
+
(latest.current.onShouldBlockNativeResponder as ((...a: never[]) => boolean) | undefined)?.(...args) ?? true;
|
|
669
|
+
return PanResponder.create(forward as PanResponderCallbacks).panHandlers;
|
|
670
|
+
});
|
|
671
|
+
return handlers;
|
|
672
|
+
}
|
package/registry/spinner.json
CHANGED
|
@@ -4,6 +4,12 @@
|
|
|
4
4
|
"title": "Spinner",
|
|
5
5
|
"description": "A loader pack: the comet ring whose tail breathes as it spins, a staggered dot wave, and ten more — equalizer bars, pulse ripple, orbit, squash-bounce, sine wave, 3×3 grid, typing bubble, counter-rotating arcs, morphing square and an indeterminate line. All native-driver loops, one size/colour/speed API, optional track and an animated-ellipsis label.",
|
|
6
6
|
"tier": "free",
|
|
7
|
+
"aliases": [
|
|
8
|
+
"loader",
|
|
9
|
+
"loading",
|
|
10
|
+
"activity-indicator",
|
|
11
|
+
"progress-indicator"
|
|
12
|
+
],
|
|
7
13
|
"dependencies": [
|
|
8
14
|
"react-native-svg"
|
|
9
15
|
],
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import React, { useEffect, useMemo, useRef, useState } from 'react';
|
|
1
|
+
import React, { useEffect, useLayoutEffect, useMemo, useRef, useState } from 'react';
|
|
2
2
|
import {
|
|
3
3
|
AccessibilityInfo,
|
|
4
4
|
Animated,
|
|
@@ -152,23 +152,23 @@ interface Roll {
|
|
|
152
152
|
color: string;
|
|
153
153
|
prev: { text: string; color: string; width: number } | null;
|
|
154
154
|
id: number;
|
|
155
|
+
/** Fresh per roll, so the first frame of a change already sits at its start. */
|
|
156
|
+
clock: Animated.Value;
|
|
155
157
|
}
|
|
156
158
|
|
|
157
159
|
/** Label whose letters roll up and out while the next label rolls in from below (crossfade with reduced motion). */
|
|
158
160
|
function RollLabel({ text, color, style, lh, space, reduce }: { text: string; color: string; style: StyleProp<TextStyle>; lh: number; space: number; reduce: boolean }) {
|
|
159
|
-
const width =
|
|
160
|
-
const [roll, setRoll] = useState<Roll>({ text, color, prev: null, id: 0 });
|
|
161
|
-
if (roll.text !== text)
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
const
|
|
165
|
-
if (!clockRef.current || clockRef.current.id !== roll.id) {
|
|
166
|
-
clockRef.current = { id: roll.id, v: new Animated.Value(roll.id === 0 ? END : 0) };
|
|
167
|
-
}
|
|
168
|
-
const clock = clockRef.current.v;
|
|
161
|
+
const [width, setWidth] = useState(0);
|
|
162
|
+
const [roll, setRoll] = useState<Roll>(() => ({ text, color, prev: null, id: 0, clock: new Animated.Value(END) }));
|
|
163
|
+
if (roll.text !== text) {
|
|
164
|
+
setRoll({ text, color, prev: { text: roll.text, color: roll.color, width }, id: roll.id + 1, clock: new Animated.Value(0) });
|
|
165
|
+
} else if (roll.color !== color) setRoll({ ...roll, color });
|
|
166
|
+
const clock = roll.clock;
|
|
169
167
|
|
|
170
168
|
const live = useRef({ next: 0, prev: 0, reduce });
|
|
171
|
-
|
|
169
|
+
useLayoutEffect(() => {
|
|
170
|
+
live.current = { next: split(roll.text).length, prev: roll.prev ? split(roll.prev.text).length : 0, reduce };
|
|
171
|
+
});
|
|
172
172
|
const id = roll.id;
|
|
173
173
|
useEffect(() => {
|
|
174
174
|
if (id === 0) return;
|
|
@@ -183,8 +183,8 @@ function RollLabel({ text, color, style, lh, space, reduce }: { text: string; co
|
|
|
183
183
|
return () => anim.stop();
|
|
184
184
|
}, [id, clock]);
|
|
185
185
|
|
|
186
|
-
const n =
|
|
187
|
-
const m =
|
|
186
|
+
const n = split(roll.text).length;
|
|
187
|
+
const m = roll.prev ? split(roll.prev.text).length : 0;
|
|
188
188
|
const enter = useMemo<Anim[]>(
|
|
189
189
|
() =>
|
|
190
190
|
Array.from({ length: n }, (_, i) =>
|
|
@@ -216,7 +216,7 @@ function RollLabel({ text, color, style, lh, space, reduce }: { text: string; co
|
|
|
216
216
|
lh={lh}
|
|
217
217
|
space={space}
|
|
218
218
|
anims={enter}
|
|
219
|
-
onLayout={(e) => (
|
|
219
|
+
onLayout={(e) => setWidth(e.nativeEvent.layout.width)}
|
|
220
220
|
/>
|
|
221
221
|
{roll.prev ? (
|
|
222
222
|
<View pointerEvents="none" style={[styles.prev, pw > 0 ? { left: '50%', marginLeft: -pw / 2, width: pw } : { left: 0 }]}>
|
|
@@ -237,8 +237,8 @@ export function StatefulButton({
|
|
|
237
237
|
state,
|
|
238
238
|
onPress,
|
|
239
239
|
loadingText,
|
|
240
|
-
successText
|
|
241
|
-
errorText
|
|
240
|
+
successText: successTextProp,
|
|
241
|
+
errorText: errorTextProp,
|
|
242
242
|
variant = 'primary',
|
|
243
243
|
size = 'md',
|
|
244
244
|
color,
|
|
@@ -253,7 +253,9 @@ export function StatefulButton({
|
|
|
253
253
|
style,
|
|
254
254
|
textStyle,
|
|
255
255
|
}: StatefulButtonProps) {
|
|
256
|
-
const { colors, radius, dark, font } = useKit();
|
|
256
|
+
const { colors, radius, dark, font, labels: kitLabels } = useKit();
|
|
257
|
+
const successText = successTextProp ?? kitLabels.done;
|
|
258
|
+
const errorText = errorTextProp ?? kitLabels.failed;
|
|
257
259
|
const reduce = useReduceMotion();
|
|
258
260
|
const s = SIZES[size];
|
|
259
261
|
const fontSize = StyleSheet.flatten(textStyle)?.fontSize ?? s.font;
|
|
@@ -314,31 +316,36 @@ export function StatefulButton({
|
|
|
314
316
|
const bw = variant === 'outline' ? StyleSheet.hairlineWidth * 2 : 0;
|
|
315
317
|
|
|
316
318
|
// JS driver (layout + colour + SVG) — on the surface, the icon slot and the stroke.
|
|
317
|
-
const tone =
|
|
318
|
-
const slot =
|
|
319
|
-
const draw =
|
|
319
|
+
const [tone] = useState(() => new Animated.Value(toneIndex));
|
|
320
|
+
const [slot] = useState(() => new Animated.Value(current === 'idle' ? 0 : s.icon + s.gap));
|
|
321
|
+
const [draw] = useState(() => new Animated.Value(1));
|
|
320
322
|
// Native driver — transforms and opacity on their own wrappers.
|
|
321
|
-
const press =
|
|
322
|
-
const shake =
|
|
323
|
-
const pop =
|
|
324
|
-
const spin =
|
|
323
|
+
const [press] = useState(() => new Animated.Value(1));
|
|
324
|
+
const [shake] = useState(() => new Animated.Value(0));
|
|
325
|
+
const [pop] = useState(() => new Animated.Value(current === 'idle' ? 0 : 1));
|
|
326
|
+
const [spin] = useState(() => new Animated.Value(0));
|
|
325
327
|
const spinLoop = useRef<Animated.CompositeAnimation | null>(null);
|
|
326
328
|
|
|
327
329
|
// The icon keeps showing the last busy/result state while it shrinks away on the way back to idle.
|
|
328
|
-
const
|
|
329
|
-
if (current !== 'idle'
|
|
330
|
-
const icon = lastIcon.current;
|
|
330
|
+
const [icon, setIcon] = useState<StatefulButtonState>(current === 'idle' ? 'loading' : current);
|
|
331
|
+
if (current !== 'idle' && icon !== current) setIcon(current);
|
|
331
332
|
|
|
332
333
|
// Width: measured from hidden copies of every label, sprung on the JS driver.
|
|
333
334
|
const [widths, setWidths] = useState<Record<string, number>>({});
|
|
334
335
|
const measured = widths[label];
|
|
335
336
|
const target = measured === undefined ? undefined : Math.max(s.h, Math.ceil(measured) + s.px * 2 + bw * 2 + (current === 'idle' ? 0 : s.icon + s.gap));
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
337
|
+
// Created at the first measured width, then sprung from there.
|
|
338
|
+
const [widthV, setWidthV] = useState<Animated.Value | null>(null);
|
|
339
|
+
let width = widthV;
|
|
340
|
+
if (!width && target !== undefined) {
|
|
341
|
+
width = new Animated.Value(target);
|
|
342
|
+
setWidthV(width);
|
|
343
|
+
}
|
|
339
344
|
|
|
340
345
|
const live = useRef({ reduce, haptics, onStateChange, label, slotTo: 0 });
|
|
341
|
-
|
|
346
|
+
useLayoutEffect(() => {
|
|
347
|
+
live.current = { reduce, haptics, onStateChange, label, slotTo: current === 'idle' ? 0 : s.icon + s.gap };
|
|
348
|
+
});
|
|
342
349
|
|
|
343
350
|
useEffect(() => {
|
|
344
351
|
if (!width || target === undefined) return;
|