@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/chip-group.json
CHANGED
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
"title": "Chip Group",
|
|
5
5
|
"description": "Filter chips for single or multiple choice. A check mark draws itself in while the chip widens smoothly to make room and its colours cross-fade. Wrapping or horizontally scrolling.",
|
|
6
6
|
"tier": "free",
|
|
7
|
+
"aliases": [],
|
|
7
8
|
"dependencies": [
|
|
8
9
|
"react-native-svg"
|
|
9
10
|
],
|
|
@@ -5,13 +5,13 @@ export type ConfettiOrigin = 'top' | 'center' | 'bottom';
|
|
|
5
5
|
|
|
6
6
|
export interface ConfettiBurst {
|
|
7
7
|
/** Where it comes from (default: the `origin` prop). */
|
|
8
|
-
origin?: ConfettiOrigin;
|
|
8
|
+
origin?: ConfettiOrigin | undefined;
|
|
9
9
|
/** For `center`: the burst point in the overlay, in points (default: the middle). */
|
|
10
|
-
x?: number;
|
|
11
|
-
y?: number;
|
|
10
|
+
x?: number | undefined;
|
|
11
|
+
y?: number | undefined;
|
|
12
12
|
/** Pieces in this burst (default: the `count` prop). */
|
|
13
|
-
count?: number;
|
|
14
|
-
colors?: readonly string[];
|
|
13
|
+
count?: number | undefined;
|
|
14
|
+
colors?: readonly string[] | undefined;
|
|
15
15
|
}
|
|
16
16
|
|
|
17
17
|
export interface ConfettiHandle {
|
|
@@ -21,20 +21,20 @@ export interface ConfettiHandle {
|
|
|
21
21
|
|
|
22
22
|
export interface ConfettiProps {
|
|
23
23
|
/** Pieces per burst (default 80, max 160). */
|
|
24
|
-
count?: number;
|
|
25
|
-
colors?: readonly string[];
|
|
24
|
+
count?: number | undefined;
|
|
25
|
+
colors?: readonly string[] | undefined;
|
|
26
26
|
/** `top` rains down, `center` pops outward, `bottom` fires two cannons from the corners (default "bottom"). */
|
|
27
|
-
origin?: ConfettiOrigin;
|
|
27
|
+
origin?: ConfettiOrigin | undefined;
|
|
28
28
|
/** How long a burst lasts in ms (default 2600). */
|
|
29
|
-
duration?: number;
|
|
29
|
+
duration?: number | undefined;
|
|
30
30
|
/** Fire a burst whenever this value changes (not on mount) — no ref needed. */
|
|
31
|
-
trigger?: unknown;
|
|
31
|
+
trigger?: unknown | undefined;
|
|
32
32
|
/** Fire once on mount. */
|
|
33
|
-
autoplay?: boolean;
|
|
33
|
+
autoplay?: boolean | undefined;
|
|
34
34
|
/** Called when a burst has finished. */
|
|
35
|
-
onDone?: () => void;
|
|
35
|
+
onDone?: (() => void) | undefined;
|
|
36
36
|
/** The overlay fills its parent by default; it never takes touches. */
|
|
37
|
-
style?: StyleProp<ViewStyle
|
|
37
|
+
style?: StyleProp<ViewStyle> | undefined;
|
|
38
38
|
}
|
|
39
39
|
|
|
40
40
|
const PALETTE = ['#ff3d77', '#ffb000', '#3ddcff', '#7cff6b', '#a855ff', '#ffffff', '#ff7a1a'];
|
|
@@ -145,7 +145,8 @@ export const Confetti = forwardRef<ConfettiHandle, ConfettiProps>(function Confe
|
|
|
145
145
|
const turns = (Math.random() < 0.5 ? -1 : 1) * (1 + Math.random() * 2.5);
|
|
146
146
|
pieces.push({
|
|
147
147
|
key: i,
|
|
148
|
-
|
|
148
|
+
// An empty `colors` list falls back to white rather than an invisible piece.
|
|
149
|
+
color: palette[Math.floor(Math.random() * palette.length)] ?? '#ffffff',
|
|
149
150
|
w: round ? 7 : strip ? 4 : 7,
|
|
150
151
|
h: round ? 7 : strip ? 16 : 11,
|
|
151
152
|
round,
|
package/registry/confetti.json
CHANGED
|
@@ -4,12 +4,9 @@
|
|
|
4
4
|
"title": "Confetti",
|
|
5
5
|
"description": "Confetti for the moments that deserve it — a coupon applied, a reward revealed, an order placed. Pieces fly on real arcs (launch, gravity, air drag) and flutter as they fall; one native-driven animation moves them all. Cannons, rain or a pop under your finger; respects Reduce Motion.",
|
|
6
6
|
"tier": "free",
|
|
7
|
+
"aliases": [],
|
|
7
8
|
"dependencies": [],
|
|
8
|
-
"registryDependencies": [
|
|
9
|
-
|
|
10
|
-
],
|
|
11
|
-
"sharedFiles": [
|
|
12
|
-
"lib/kit.tsx"
|
|
13
|
-
],
|
|
9
|
+
"registryDependencies": [],
|
|
10
|
+
"sharedFiles": [],
|
|
14
11
|
"filesDir": "confetti/files"
|
|
15
12
|
}
|
|
@@ -30,13 +30,13 @@ export interface CouponTheme {
|
|
|
30
30
|
/** Text on the value panel. */
|
|
31
31
|
ink: string;
|
|
32
32
|
/** Buttons, the code chip and the applied ring (default: the fill's last colour). */
|
|
33
|
-
accent?: string;
|
|
33
|
+
accent?: string | undefined;
|
|
34
34
|
/** Details panel paint (default: the app's card colour). */
|
|
35
|
-
body?: string | readonly string[];
|
|
35
|
+
body?: string | readonly string[] | undefined;
|
|
36
36
|
/** Text on the details panel (default: the app's foreground). */
|
|
37
|
-
bodyInk?: string;
|
|
37
|
+
bodyInk?: string | undefined;
|
|
38
38
|
/** Texture on the value panel. */
|
|
39
|
-
pattern?: TicketPattern;
|
|
39
|
+
pattern?: TicketPattern | undefined;
|
|
40
40
|
}
|
|
41
41
|
|
|
42
42
|
export const couponThemes: Record<CouponThemeName, CouponTheme> = {
|
|
@@ -74,52 +74,52 @@ export interface CouponProps {
|
|
|
74
74
|
/** The headline: "50%", "₹200", "FREE", "BOGO". */
|
|
75
75
|
value: string;
|
|
76
76
|
/** Under the value: "OFF", "CASHBACK". */
|
|
77
|
-
unit?: string;
|
|
77
|
+
unit?: string | undefined;
|
|
78
78
|
/** Above the value: "FLAT", "UP TO". */
|
|
79
|
-
prefix?: string;
|
|
80
|
-
title?: string;
|
|
81
|
-
description?: string;
|
|
79
|
+
prefix?: string | undefined;
|
|
80
|
+
title?: string | undefined;
|
|
81
|
+
description?: string | undefined;
|
|
82
82
|
/** Promo code, shown in a dashed chip (tap to copy when `onCopy` is set). */
|
|
83
|
-
code?: string;
|
|
84
|
-
brand?: string;
|
|
83
|
+
code?: string | undefined;
|
|
84
|
+
brand?: string | undefined;
|
|
85
85
|
/** Logo before the brand (e.g. an <Image>). */
|
|
86
|
-
logo?: React.ReactNode;
|
|
86
|
+
logo?: React.ReactNode | undefined;
|
|
87
87
|
/** Expiry line, e.g. "Valid till 31 Dec". */
|
|
88
|
-
expires?: string;
|
|
88
|
+
expires?: string | undefined;
|
|
89
89
|
/** Live countdown to this moment; the coupon turns expired when it passes. */
|
|
90
|
-
expiresAt?: Date | number;
|
|
90
|
+
expiresAt?: Date | number | undefined;
|
|
91
91
|
/** Shown on the back — the "T&C" link turns the coupon over. */
|
|
92
|
-
terms?: string[];
|
|
93
|
-
status?: CouponStatus;
|
|
92
|
+
terms?: string[] | undefined;
|
|
93
|
+
status?: CouponStatus | undefined;
|
|
94
94
|
/** Why it's locked, e.g. "Add ₹120 more to unlock". */
|
|
95
|
-
lockedHint?: string;
|
|
95
|
+
lockedHint?: string | undefined;
|
|
96
96
|
/** A preset or your own colours (default "sunset"). */
|
|
97
|
-
theme?: CouponThemeName | CouponTheme;
|
|
97
|
+
theme?: CouponThemeName | CouponTheme | undefined;
|
|
98
98
|
/** Override the theme's texture. */
|
|
99
|
-
pattern?: TicketPattern;
|
|
99
|
+
pattern?: TicketPattern | undefined;
|
|
100
100
|
/** `horizontal` (value panel on the left) or `vertical` (value panel on top). */
|
|
101
|
-
layout?: 'horizontal' | 'vertical';
|
|
102
|
-
variant?: CouponVariant;
|
|
103
|
-
size?: CouponSize;
|
|
101
|
+
layout?: 'horizontal' | 'vertical' | undefined;
|
|
102
|
+
variant?: CouponVariant | undefined;
|
|
103
|
+
size?: CouponSize | undefined;
|
|
104
104
|
/** A light sweep across the value panel every few seconds. */
|
|
105
|
-
shine?: boolean;
|
|
105
|
+
shine?: boolean | undefined;
|
|
106
106
|
/** 3D: tilts toward the finger with a moving reflection. */
|
|
107
|
-
tilt?: boolean;
|
|
107
|
+
tilt?: boolean | undefined;
|
|
108
108
|
/** With `tilt`: a rainbow foil sheen. */
|
|
109
|
-
holo?: boolean;
|
|
109
|
+
holo?: boolean | undefined;
|
|
110
110
|
/** With `tilt`: sway slowly on its own. */
|
|
111
|
-
idle?: boolean;
|
|
111
|
+
idle?: boolean | undefined;
|
|
112
112
|
/** Called with the code from the chip — wire it to expo-clipboard. */
|
|
113
|
-
onCopy?: (code: string) => void;
|
|
113
|
+
onCopy?: ((code: string) => void) | undefined;
|
|
114
114
|
/** Shows the Apply button. */
|
|
115
|
-
onApply?: () => void;
|
|
115
|
+
onApply?: (() => void) | undefined;
|
|
116
116
|
/** Tap on the coupon itself (e.g. open details or select it). */
|
|
117
|
-
onPress?: () => void;
|
|
118
|
-
flipped?: boolean;
|
|
119
|
-
defaultFlipped?: boolean;
|
|
120
|
-
onFlip?: (flipped: boolean) => void;
|
|
121
|
-
labels?: CouponLabels;
|
|
122
|
-
style?: StyleProp<ViewStyle
|
|
117
|
+
onPress?: (() => void) | undefined;
|
|
118
|
+
flipped?: boolean | undefined;
|
|
119
|
+
defaultFlipped?: boolean | undefined;
|
|
120
|
+
onFlip?: ((flipped: boolean) => void) | undefined;
|
|
121
|
+
labels?: CouponLabels | undefined;
|
|
122
|
+
style?: StyleProp<ViewStyle> | undefined;
|
|
123
123
|
}
|
|
124
124
|
|
|
125
125
|
const VARIANTS: Record<CouponVariant, { r: number; notch: number; edge?: TicketEdge; edgeSize: number; ends?: boolean }> = {
|
|
@@ -159,11 +159,11 @@ function contrast(a: string, b: string) {
|
|
|
159
159
|
const full = hex.length === 4 ? '#' + [...hex.slice(1)].map((c) => c + c).join('') : hex;
|
|
160
160
|
const n = parseInt(full.slice(1, 7), 16);
|
|
161
161
|
if (!/^#[0-9a-f]{6}/i.test(full) || Number.isNaN(n)) return -1;
|
|
162
|
-
const
|
|
162
|
+
const [red = 0, green = 0, blue = 0] = [(n >> 16) & 255, (n >> 8) & 255, n & 255].map((v) => {
|
|
163
163
|
const c = v / 255;
|
|
164
164
|
return c <= 0.03928 ? c / 12.92 : ((c + 0.055) / 1.055) ** 2.4;
|
|
165
165
|
});
|
|
166
|
-
return 0.2126 *
|
|
166
|
+
return 0.2126 * red + 0.7152 * green + 0.0722 * blue;
|
|
167
167
|
};
|
|
168
168
|
const [x, y] = [lum(a), lum(b)];
|
|
169
169
|
if (x < 0 || y < 0) return 21;
|
|
@@ -201,13 +201,13 @@ function useRemaining(at?: Date | number) {
|
|
|
201
201
|
}
|
|
202
202
|
|
|
203
203
|
/** The promo code in a dashed chip; a tap copies it and flips the icon to a check for a moment. */
|
|
204
|
-
function CodeChip({ code, color, ink, fontSize, onCopy, labels, reduce }: { code: string; color: string; ink: string; fontSize: number; onCopy?: (code: string) => void; labels: Required<CouponLabels>; reduce: boolean }) {
|
|
204
|
+
function CodeChip({ code, color, ink, fontSize, onCopy, labels, reduce }: { code: string; color: string; ink: string; fontSize: number; onCopy?: ((code: string) => void) | undefined; labels: Required<CouponLabels>; reduce: boolean }) {
|
|
205
205
|
const { font } = useKit();
|
|
206
206
|
const ff = font.family ? { fontFamily: font.family } : null;
|
|
207
207
|
const [copied, setCopied] = useState(false);
|
|
208
208
|
const [box, setBox] = useState({ w: 0, h: 0 });
|
|
209
209
|
const timer = useRef<ReturnType<typeof setTimeout> | undefined>(undefined);
|
|
210
|
-
const pop =
|
|
210
|
+
const [pop] = useState(() => new Animated.Value(1));
|
|
211
211
|
useEffect(() => () => clearTimeout(timer.current), []);
|
|
212
212
|
const copy = () => {
|
|
213
213
|
onCopy?.(code);
|
|
@@ -248,7 +248,7 @@ function CodeChip({ code, color, ink, fontSize, onCopy, labels, reduce }: { code
|
|
|
248
248
|
|
|
249
249
|
/** A light band that sweeps across, every few seconds, through the given windows. */
|
|
250
250
|
function Shine({ windows, width, height }: { windows: TicketRect[]; width: number; height: number }) {
|
|
251
|
-
const t =
|
|
251
|
+
const [t] = useState(() => new Animated.Value(0));
|
|
252
252
|
useEffect(() => {
|
|
253
253
|
const loop = Animated.loop(
|
|
254
254
|
Animated.sequence([Animated.timing(t, { toValue: 1, duration: 1100, easing: Easing.inOut(Easing.quad), useNativeDriver: true }), Animated.delay(2400)])
|
|
@@ -338,12 +338,12 @@ export function Coupon({
|
|
|
338
338
|
const reduce = useReduceMotion();
|
|
339
339
|
const theme = typeof themeProp === 'object' ? themeProp : couponThemes[themeProp];
|
|
340
340
|
const fills = typeof theme.fill === 'string' ? [theme.fill] : theme.fill;
|
|
341
|
-
const accent = theme.accent ?? fills[fills.length - 1];
|
|
341
|
+
const accent = theme.accent ?? fills[fills.length - 1] ?? colors.primary;
|
|
342
342
|
const body = theme.body ?? (dark ? colors.popover : colors.card);
|
|
343
343
|
const bodyInk = theme.bodyInk ?? colors.foreground;
|
|
344
344
|
const bodySoft = alpha(bodyInk, 0.6);
|
|
345
345
|
// The accent as text on the details panel — or the panel's ink when they'd blend (yellow on white).
|
|
346
|
-
const textAccent = contrast(accent, typeof body === 'string' ? body : body[0]) >= 2.6 ? accent : bodyInk;
|
|
346
|
+
const textAccent = contrast(accent, typeof body === 'string' ? body : (body[0] ?? colors.card)) >= 2.6 ? accent : bodyInk;
|
|
347
347
|
const s = SIZES[size];
|
|
348
348
|
const v = VARIANTS[variant];
|
|
349
349
|
const horizontal = layout === 'horizontal';
|
|
@@ -387,8 +387,8 @@ export function Coupon({
|
|
|
387
387
|
const n = v.notch;
|
|
388
388
|
const endEdge = v.edge;
|
|
389
389
|
const sideEdge = v.ends ? undefined : v.edge;
|
|
390
|
-
const valueEdges: Partial<Record<TicketSide, TicketEdge>> = horizontal ? { left: endEdge, top: sideEdge, bottom: sideEdge } : { top: endEdge, left: sideEdge, right: sideEdge };
|
|
391
|
-
const detailEdges: Partial<Record<TicketSide, TicketEdge>> = horizontal ? { right: endEdge, top: sideEdge, bottom: sideEdge } : { bottom: endEdge, left: sideEdge, right: sideEdge };
|
|
390
|
+
const valueEdges: Partial<Record<TicketSide, TicketEdge | undefined>> = horizontal ? { left: endEdge, top: sideEdge, bottom: sideEdge } : { top: endEdge, left: sideEdge, right: sideEdge };
|
|
391
|
+
const detailEdges: Partial<Record<TicketSide, TicketEdge | undefined>> = horizontal ? { right: endEdge, top: sideEdge, bottom: sideEdge } : { bottom: endEdge, left: sideEdge, right: sideEdge };
|
|
392
392
|
const corners = (tl: number, tr: number, br: number, bl: number): TicketCorners => [tl, tr, br, bl];
|
|
393
393
|
const valueCorners = horizontal ? corners(v.r, -n, -n, v.r) : corners(v.r, v.r, -n, -n);
|
|
394
394
|
const detailCorners = horizontal ? corners(-n, v.r, v.r, -n) : corners(-n, -n, v.r, v.r);
|