@expokit/cli 0.3.0 → 0.4.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 +8 -4
- package/bin/expo-kit.js +137 -24
- package/bin/lib.mjs +110 -1
- package/bin/mcp.mjs +40 -18
- package/package.json +2 -2
- package/registry/_docs/assistant-app.json +47 -0
- package/registry/_docs/avatar.json +1 -1
- package/registry/_docs/badge.json +1 -1
- package/registry/_docs/bottom-nav.json +6 -6
- package/registry/_docs/button-3d.json +2 -2
- package/registry/_docs/calendar.json +5 -5
- package/registry/_docs/checkout.json +7 -1
- package/registry/_docs/confetti.json +3 -3
- package/registry/_docs/date-picker.json +4 -4
- package/registry/_docs/donut-shop.json +88 -0
- package/registry/_docs/drawer.json +4 -4
- package/registry/_docs/fintech-app.json +49 -0
- package/registry/_docs/floating-input.json +5 -5
- package/registry/_docs/food-app.json +47 -0
- package/registry/_docs/glass.json +1 -1
- package/registry/_docs/grain.json +80 -0
- package/registry/_docs/morphing-button-group.json +96 -0
- package/registry/_docs/orb-reveal.json +132 -0
- package/registry/_docs/otp-input.json +4 -4
- package/registry/_docs/password-input.json +3 -3
- package/registry/_docs/qr-code-button.json +122 -0
- package/registry/_docs/search-bar.json +3 -3
- package/registry/_docs/select.json +7 -7
- package/registry/_docs/settings.json +6 -0
- package/registry/_docs/skeleton.json +2 -2
- package/registry/_docs/slider.json +6 -6
- package/registry/_docs/spinner.json +1 -1
- package/registry/_docs/stepper.json +7 -7
- package/registry/_docs/textarea.json +2 -2
- package/registry/_docs/ticket-shape.json +1 -1
- package/registry/_docs/tilt-card.json +4 -4
- package/registry/_docs/time-picker.json +6 -6
- package/registry/_docs/timeline.json +2 -2
- package/registry/_docs/toast.json +8 -8
- package/registry/accordion/files/src/components/ui/accordion.tsx +5 -4
- package/registry/accordion/files/src/lib/kit.tsx +8 -5
- package/registry/action-sheet/files/src/components/ui/action-sheet.tsx +9 -8
- package/registry/action-sheet/files/src/lib/kit.tsx +8 -5
- package/registry/alert/files/src/components/ui/alert.tsx +7 -4
- package/registry/alert/files/src/components/ui/button.tsx +4 -3
- package/registry/alert/files/src/lib/kit.tsx +8 -5
- package/registry/assistant-app.json +49 -0
- package/registry/avatar/files/src/components/ui/avatar.tsx +7 -4
- package/registry/avatar/files/src/lib/kit.tsx +8 -5
- package/registry/badge/files/src/components/ui/badge.tsx +21 -7
- package/registry/badge/files/src/lib/kit.tsx +8 -5
- package/registry/bottom-nav/files/src/components/ui/bottom-nav.tsx +14 -7
- package/registry/bottom-nav/files/src/lib/kit.tsx +8 -5
- package/registry/bottom-sheet/files/src/components/ui/bottom-sheet.tsx +7 -6
- package/registry/bottom-sheet/files/src/lib/kit.tsx +8 -5
- package/registry/button/files/src/components/ui/button.tsx +4 -3
- package/registry/button/files/src/lib/kit.tsx +8 -5
- package/registry/button-3d/files/src/components/ui/button-3d.tsx +3 -2
- package/registry/button-3d/files/src/lib/kit.tsx +8 -5
- package/registry/calendar/files/src/components/ui/calendar.tsx +9 -5
- package/registry/calendar/files/src/lib/kit.tsx +8 -5
- package/registry/card/files/src/components/ui/card.tsx +8 -6
- package/registry/card/files/src/lib/kit.tsx +8 -5
- package/registry/checkbox/files/src/components/ui/checkbox.tsx +6 -5
- package/registry/checkbox/files/src/lib/kit.tsx +8 -5
- package/registry/chip-group/files/src/components/ui/chip-group.tsx +4 -2
- package/registry/chip-group/files/src/lib/kit.tsx +8 -5
- package/registry/confetti/files/src/lib/kit.tsx +8 -5
- package/registry/coupon/files/src/components/ui/coupon.tsx +23 -20
- package/registry/coupon/files/src/components/ui/flip-card.tsx +1 -1
- package/registry/coupon/files/src/components/ui/tilt-card.tsx +2 -2
- package/registry/coupon/files/src/lib/kit.tsx +8 -5
- package/registry/date-picker/files/src/components/ui/calendar.tsx +9 -5
- package/registry/date-picker/files/src/components/ui/date-picker.tsx +2 -2
- package/registry/date-picker/files/src/lib/kit.tsx +8 -5
- package/registry/dialog/files/src/components/ui/dialog.tsx +12 -6
- package/registry/dialog/files/src/lib/kit.tsx +8 -5
- package/registry/donut-shop.json +18 -0
- package/registry/drawer/files/src/components/ui/drawer.tsx +25 -19
- package/registry/drawer/files/src/lib/kit.tsx +8 -5
- package/registry/fintech-app.json +57 -0
- package/registry/flip-card/files/src/components/ui/flip-card.tsx +1 -1
- package/registry/flip-card/files/src/lib/kit.tsx +8 -5
- package/registry/floating-input/files/src/components/ui/floating-input.tsx +16 -6
- package/registry/floating-input/files/src/lib/kit.tsx +8 -5
- package/registry/food-app.json +55 -0
- package/registry/grain/files/src/components/ui/grain.tsx +113 -0
- package/registry/{tag-input → grain}/files/src/lib/kit.tsx +8 -5
- package/registry/grain.json +17 -0
- package/registry/kit/files/src/lib/kit.tsx +8 -5
- package/registry/liquidglass-tab/files/src/components/GlassTabBar.tsx +1 -1
- package/registry/liquidglass-tab/files/src/lib/tab-bar.ts +1 -1
- package/registry/list-item/files/src/components/ui/list-item.tsx +20 -16
- package/registry/list-item/files/src/lib/kit.tsx +8 -5
- package/registry/morphing-button-group.json +18 -0
- package/registry/orb-reveal.json +20 -0
- package/registry/otp-input/files/src/components/ui/otp-input.tsx +8 -6
- package/registry/otp-input/files/src/lib/kit.tsx +8 -5
- package/registry/password-input/files/src/components/ui/floating-input.tsx +16 -6
- package/registry/password-input/files/src/components/ui/password-input.tsx +2 -2
- package/registry/password-input/files/src/lib/kit.tsx +8 -5
- package/registry/payment-card/files/src/components/ui/flip-card.tsx +1 -1
- package/registry/payment-card/files/src/components/ui/payment-card.tsx +27 -14
- package/registry/payment-card/files/src/components/ui/tilt-card.tsx +2 -2
- package/registry/payment-card/files/src/lib/kit.tsx +8 -5
- package/registry/progress/files/src/components/ui/progress.tsx +8 -5
- package/registry/progress/files/src/lib/kit.tsx +8 -5
- package/registry/progress-steps/files/src/components/ui/progress-steps.tsx +15 -11
- package/registry/progress-steps/files/src/lib/kit.tsx +8 -5
- package/registry/qr-code-button.json +18 -0
- package/registry/radio-group/files/src/components/ui/radio-group.tsx +10 -9
- package/registry/radio-group/files/src/lib/kit.tsx +8 -5
- package/registry/search-bar/files/src/components/ui/search-bar.tsx +13 -11
- package/registry/search-bar/files/src/lib/kit.tsx +8 -5
- package/registry/segmented-control/files/src/components/ui/segmented-control.tsx +4 -2
- package/registry/segmented-control/files/src/lib/kit.tsx +8 -5
- package/registry/select/files/src/components/ui/select.tsx +3 -3
- package/registry/select/files/src/lib/kit.tsx +8 -5
- package/registry/skeleton/files/src/components/ui/skeleton.tsx +4 -4
- package/registry/skeleton/files/src/lib/kit.tsx +8 -5
- package/registry/slider/files/src/components/ui/slider.tsx +5 -4
- package/registry/slider/files/src/lib/kit.tsx +8 -5
- package/registry/spinner/files/src/components/ui/spinner.tsx +17 -12
- package/registry/spinner/files/src/lib/kit.tsx +8 -5
- package/registry/stateful-button/files/src/lib/kit.tsx +8 -5
- package/registry/stepper/files/src/components/ui/stepper.tsx +8 -4
- package/registry/stepper/files/src/lib/kit.tsx +8 -5
- package/registry/switch/files/src/components/ui/switch.tsx +4 -3
- package/registry/switch/files/src/lib/kit.tsx +8 -5
- package/registry/tabs/files/src/components/ui/tabs.tsx +10 -8
- package/registry/tabs/files/src/lib/kit.tsx +8 -5
- package/registry/text-animation/files/src/components/ui/text-animation.tsx +4 -4
- package/registry/text-animation/files/src/lib/kit.tsx +8 -5
- package/registry/textarea/files/src/components/ui/textarea.tsx +11 -9
- package/registry/textarea/files/src/lib/kit.tsx +8 -5
- package/registry/ticket-shape/files/src/lib/kit.tsx +8 -5
- package/registry/tilt-card/files/src/components/ui/tilt-card.tsx +2 -2
- package/registry/tilt-card/files/src/lib/kit.tsx +8 -5
- package/registry/time-picker/files/src/components/ui/time-picker.tsx +2 -2
- package/registry/time-picker/files/src/lib/kit.tsx +8 -5
- package/registry/timeline/files/src/components/ui/avatar.tsx +7 -4
- package/registry/timeline/files/src/components/ui/timeline.tsx +12 -10
- package/registry/timeline/files/src/lib/kit.tsx +8 -5
- package/registry/toast/files/src/components/ui/button.tsx +4 -3
- package/registry/toast/files/src/components/ui/toast.tsx +13 -11
- package/registry/toast/files/src/lib/kit.tsx +8 -5
- package/schema/components.schema.json +1 -1
- package/registry/_docs/color-swatch.json +0 -82
- package/registry/_docs/kpi-card.json +0 -14
- package/registry/_docs/like-button.json +0 -92
- package/registry/_docs/morph-button.json +0 -128
- package/registry/_docs/pagination-dots.json +0 -108
- package/registry/_docs/shimmer-button.json +0 -98
- package/registry/_docs/tag-input.json +0 -148
- package/registry/color-swatch.json +0 -17
- package/registry/kpi-card/files/src/components/charts/kpi-card.tsx +0 -45
- package/registry/kpi-card.json +0 -14
- package/registry/like-button.json +0 -18
- package/registry/morph-button.json +0 -18
- package/registry/pagination-dots/files/src/components/ui/pagination-dots.tsx +0 -262
- package/registry/pagination-dots/files/src/lib/kit.tsx +0 -219
- package/registry/pagination-dots.json +0 -15
- package/registry/shimmer-button.json +0 -17
- package/registry/tag-input/files/src/components/ui/tag-input.tsx +0 -720
- package/registry/tag-input.json +0 -17
|
@@ -89,7 +89,8 @@ export function Alert({
|
|
|
89
89
|
color,
|
|
90
90
|
style,
|
|
91
91
|
}: AlertProps) {
|
|
92
|
-
const { colors, radius, dark } = useKit();
|
|
92
|
+
const { colors, radius, dark, font } = useKit();
|
|
93
|
+
const ff = font.family ? { fontFamily: font.family } : null;
|
|
93
94
|
const uid = useId().replace(/[^a-zA-Z0-9]/g, '');
|
|
94
95
|
const reduceMotion = useReduceMotion();
|
|
95
96
|
const tones: Record<AlertVariant, string> = {
|
|
@@ -322,9 +323,9 @@ export function Alert({
|
|
|
322
323
|
<>
|
|
323
324
|
{iconNode}
|
|
324
325
|
<View style={[styles.body, { paddingTop: textTop }]}>
|
|
325
|
-
{title ? <Text style={[styles.title, { color: fg }]}>{title}</Text> : null}
|
|
326
|
+
{title ? <Text style={[styles.title, ff, { color: fg }]}>{title}</Text> : null}
|
|
326
327
|
{typeof description === 'string' ? (
|
|
327
|
-
<Text style={[styles.desc, { color: title ? sub : fg }]}>{description}</Text>
|
|
328
|
+
<Text style={[styles.desc, ff, { color: title ? sub : fg }]}>{description}</Text>
|
|
328
329
|
) : (
|
|
329
330
|
description
|
|
330
331
|
)}
|
|
@@ -443,6 +444,8 @@ function Pill({
|
|
|
443
444
|
bg: string;
|
|
444
445
|
fg: string;
|
|
445
446
|
}) {
|
|
447
|
+
const { font } = useKit();
|
|
448
|
+
const ff = font.family ? { fontFamily: font.family } : null;
|
|
446
449
|
return (
|
|
447
450
|
<Pressable
|
|
448
451
|
accessibilityRole="button"
|
|
@@ -455,7 +458,7 @@ function Pill({
|
|
|
455
458
|
pressed ? { opacity: 0.75, transform: [{ scale: 0.97 }] } : null,
|
|
456
459
|
]}
|
|
457
460
|
>
|
|
458
|
-
<Text style={[styles.pillText, { color: fg }]} numberOfLines={1}>
|
|
461
|
+
<Text style={[styles.pillText, ff, { color: fg }]} numberOfLines={1}>
|
|
459
462
|
{action.label}
|
|
460
463
|
</Text>
|
|
461
464
|
</Pressable>
|
|
@@ -116,7 +116,8 @@ export function Button({
|
|
|
116
116
|
onPressOut,
|
|
117
117
|
...props
|
|
118
118
|
}: ButtonProps) {
|
|
119
|
-
const { colors, radius, dark } = useKit();
|
|
119
|
+
const { colors, radius, dark, font } = useKit();
|
|
120
|
+
const ff = font.family ? { fontFamily: font.family } : null;
|
|
120
121
|
const gid = 'btn' + useId().replace(/[^a-zA-Z0-9]/g, '');
|
|
121
122
|
const scale = useRef(new Animated.Value(1)).current;
|
|
122
123
|
const isDisabled = disabled || loading;
|
|
@@ -149,7 +150,7 @@ export function Button({
|
|
|
149
150
|
const label = isTextNode(children) ? (
|
|
150
151
|
<Text
|
|
151
152
|
numberOfLines={1}
|
|
152
|
-
style={[styles.label, { color: fg, fontSize: s.font }, variant === 'link' && styles.link, textStyle]}
|
|
153
|
+
style={[styles.label, ff, { color: fg, fontSize: s.font }, variant === 'link' && styles.link, textStyle]}
|
|
153
154
|
>
|
|
154
155
|
{children}
|
|
155
156
|
</Text>
|
|
@@ -235,7 +236,7 @@ export function Button({
|
|
|
235
236
|
<View style={styles.row}>
|
|
236
237
|
<ActivityIndicator size="small" color={fg} />
|
|
237
238
|
{size !== 'icon' && isTextNode(children) ? (
|
|
238
|
-
<Text style={[styles.label, { color: fg, fontSize: s.font, opacity: 0.85 }]}>{children}</Text>
|
|
239
|
+
<Text style={[styles.label, ff, { color: fg, fontSize: s.font, opacity: 0.85 }]}>{children}</Text>
|
|
239
240
|
) : null}
|
|
240
241
|
</View>
|
|
241
242
|
) : (
|
|
@@ -181,14 +181,17 @@ export function useKit(): Theme {
|
|
|
181
181
|
return useMemo(() => build(scheme, ctx?.overrides), [scheme, ctx?.overrides]);
|
|
182
182
|
}
|
|
183
183
|
|
|
184
|
-
/**
|
|
184
|
+
/**
|
|
185
|
+
* Shared motion presets so the whole kit moves the same way. Every spring is critically damped
|
|
186
|
+
* (damping ≥ 2·√(stiffness·mass)): it settles smoothly with no overshoot or wobble.
|
|
187
|
+
*/
|
|
185
188
|
export const motion = {
|
|
186
189
|
/** Toggles, selection indicators. */
|
|
187
|
-
snappy: { damping:
|
|
188
|
-
/** Press feedback, pops. */
|
|
189
|
-
bouncy: { damping:
|
|
190
|
+
snappy: { damping: 30, stiffness: 260, mass: 0.8 },
|
|
191
|
+
/** Press feedback, pops. (Kept under its old name; it no longer bounces.) */
|
|
192
|
+
bouncy: { damping: 26, stiffness: 220, mass: 0.7 },
|
|
190
193
|
/** Sheets, layout changes. */
|
|
191
|
-
gentle: { damping:
|
|
194
|
+
gentle: { damping: 27, stiffness: 160, mass: 1 },
|
|
192
195
|
fast: 160,
|
|
193
196
|
normal: 240,
|
|
194
197
|
};
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "assistant-app",
|
|
3
|
+
"type": "template",
|
|
4
|
+
"title": "AI assistant app",
|
|
5
|
+
"description": "A complete Expo Router app for an AI chat assistant: onboarding once, Apple / Google / email-code sign in, a streaming chat with suggestions and stop, conversation history, profile and settings.",
|
|
6
|
+
"tier": "pro",
|
|
7
|
+
"dependencies": [
|
|
8
|
+
"react-native-svg",
|
|
9
|
+
"expo-haptics",
|
|
10
|
+
"expo-router",
|
|
11
|
+
"expo-splash-screen",
|
|
12
|
+
"expo-status-bar",
|
|
13
|
+
"react-native-safe-area-context",
|
|
14
|
+
"react-native-screens",
|
|
15
|
+
"@react-native-async-storage/async-storage"
|
|
16
|
+
],
|
|
17
|
+
"registryDependencies": [
|
|
18
|
+
"kit",
|
|
19
|
+
"bottom-nav",
|
|
20
|
+
"onboarding",
|
|
21
|
+
"sign-in",
|
|
22
|
+
"chat",
|
|
23
|
+
"inbox",
|
|
24
|
+
"profile",
|
|
25
|
+
"settings"
|
|
26
|
+
],
|
|
27
|
+
"sharedFiles": [
|
|
28
|
+
"lib/kit.tsx",
|
|
29
|
+
"components/ui/bottom-nav.tsx",
|
|
30
|
+
"components/blocks/onboarding.tsx",
|
|
31
|
+
"components/ui/button.tsx",
|
|
32
|
+
"components/ui/floating-input.tsx",
|
|
33
|
+
"components/ui/password-input.tsx",
|
|
34
|
+
"components/ui/otp-input.tsx",
|
|
35
|
+
"components/blocks/sign-in.tsx",
|
|
36
|
+
"components/blocks/chat.tsx",
|
|
37
|
+
"components/ui/avatar.tsx",
|
|
38
|
+
"components/ui/badge.tsx",
|
|
39
|
+
"components/ui/chip-group.tsx",
|
|
40
|
+
"components/ui/search-bar.tsx",
|
|
41
|
+
"components/ui/swipeable-row.tsx",
|
|
42
|
+
"components/blocks/inbox.tsx",
|
|
43
|
+
"components/blocks/profile.tsx",
|
|
44
|
+
"components/ui/segmented-control.tsx",
|
|
45
|
+
"components/ui/switch.tsx",
|
|
46
|
+
"components/blocks/settings.tsx"
|
|
47
|
+
],
|
|
48
|
+
"filesDir": null
|
|
49
|
+
}
|
|
@@ -131,7 +131,8 @@ export function Avatar({
|
|
|
131
131
|
haptics = true,
|
|
132
132
|
style,
|
|
133
133
|
}: AvatarProps) {
|
|
134
|
-
const { colors, radius, dark } = useKit();
|
|
134
|
+
const { colors, radius, dark, font } = useKit();
|
|
135
|
+
const ff = font.family ? { fontFamily: font.family } : null;
|
|
135
136
|
const reduceMotion = useReduceMotion();
|
|
136
137
|
const uid = useId().replace(/[^a-zA-Z0-9]/g, '');
|
|
137
138
|
const px = resolveSize(size);
|
|
@@ -280,6 +281,7 @@ export function Avatar({
|
|
|
280
281
|
numberOfLines={1}
|
|
281
282
|
style={[
|
|
282
283
|
styles.initials,
|
|
284
|
+
ff,
|
|
283
285
|
{
|
|
284
286
|
color: ink,
|
|
285
287
|
fontSize: Math.max(9, px * (initials.length > 1 ? 0.37 : 0.42)),
|
|
@@ -448,7 +450,7 @@ export function Avatar({
|
|
|
448
450
|
{badgeText ? (
|
|
449
451
|
<Text
|
|
450
452
|
allowFontScaling={false}
|
|
451
|
-
style={[styles.badgeText, { color: colors.dangerForeground, fontSize: Math.max(9, badgeH * 0.6) }]}
|
|
453
|
+
style={[styles.badgeText, ff, { color: colors.dangerForeground, fontSize: Math.max(9, badgeH * 0.6) }]}
|
|
452
454
|
>
|
|
453
455
|
{badgeText}
|
|
454
456
|
</Text>
|
|
@@ -623,7 +625,8 @@ export function AvatarGroup({
|
|
|
623
625
|
onPressMore,
|
|
624
626
|
style,
|
|
625
627
|
}: AvatarGroupProps) {
|
|
626
|
-
const { colors, radius, dark } = useKit();
|
|
628
|
+
const { colors, radius, dark, font } = useKit();
|
|
629
|
+
const ff = font.family ? { fontFamily: font.family } : null;
|
|
627
630
|
const reduceMotion = useReduceMotion();
|
|
628
631
|
const px = resolveSize(size);
|
|
629
632
|
const bg = surface ?? colors.background;
|
|
@@ -699,7 +702,7 @@ export function AvatarGroup({
|
|
|
699
702
|
<Text
|
|
700
703
|
allowFontScaling={false}
|
|
701
704
|
numberOfLines={1}
|
|
702
|
-
style={[styles.moreText, { color: colors.foreground, fontSize: Math.max(8, px * (extraText.length <= 2 ? 0.34 : extraText.length === 3 ? 0.29 : 0.24)) }]}
|
|
705
|
+
style={[styles.moreText, ff, { color: colors.foreground, fontSize: Math.max(8, px * (extraText.length <= 2 ? 0.34 : extraText.length === 3 ? 0.29 : 0.24)) }]}
|
|
703
706
|
>
|
|
704
707
|
+{extraText}
|
|
705
708
|
</Text>
|
|
@@ -181,14 +181,17 @@ export function useKit(): Theme {
|
|
|
181
181
|
return useMemo(() => build(scheme, ctx?.overrides), [scheme, ctx?.overrides]);
|
|
182
182
|
}
|
|
183
183
|
|
|
184
|
-
/**
|
|
184
|
+
/**
|
|
185
|
+
* Shared motion presets so the whole kit moves the same way. Every spring is critically damped
|
|
186
|
+
* (damping ≥ 2·√(stiffness·mass)): it settles smoothly with no overshoot or wobble.
|
|
187
|
+
*/
|
|
185
188
|
export const motion = {
|
|
186
189
|
/** Toggles, selection indicators. */
|
|
187
|
-
snappy: { damping:
|
|
188
|
-
/** Press feedback, pops. */
|
|
189
|
-
bouncy: { damping:
|
|
190
|
+
snappy: { damping: 30, stiffness: 260, mass: 0.8 },
|
|
191
|
+
/** Press feedback, pops. (Kept under its old name; it no longer bounces.) */
|
|
192
|
+
bouncy: { damping: 26, stiffness: 220, mass: 0.7 },
|
|
190
193
|
/** Sheets, layout changes. */
|
|
191
|
-
gentle: { damping:
|
|
194
|
+
gentle: { damping: 27, stiffness: 160, mass: 1 },
|
|
192
195
|
fast: 160,
|
|
193
196
|
normal: 240,
|
|
194
197
|
};
|
|
@@ -243,6 +243,8 @@ function RollingLabel({
|
|
|
243
243
|
perLetter: boolean;
|
|
244
244
|
duration: number;
|
|
245
245
|
}) {
|
|
246
|
+
const { font } = useKit();
|
|
247
|
+
const ff = font.family ? { fontFamily: font.family } : null;
|
|
246
248
|
const pieces = perLetter ? [...text].map((ch) => (ch === ' ' ? ' ' : ch)) : [text];
|
|
247
249
|
const distance = Math.ceil(fontSize * 1.35);
|
|
248
250
|
return (
|
|
@@ -262,7 +264,7 @@ function RollingLabel({
|
|
|
262
264
|
],
|
|
263
265
|
}}
|
|
264
266
|
>
|
|
265
|
-
<Text numberOfLines={1} allowFontScaling={false} style={[styles.label, { color, fontSize }]}>
|
|
267
|
+
<Text numberOfLines={1} allowFontScaling={false} style={[styles.label, ff, { color, fontSize }]}>
|
|
266
268
|
{piece}
|
|
267
269
|
</Text>
|
|
268
270
|
</Animated.View>
|
|
@@ -288,7 +290,8 @@ export function Badge({
|
|
|
288
290
|
animateChanges = true,
|
|
289
291
|
style,
|
|
290
292
|
}: BadgeProps) {
|
|
291
|
-
const { colors, radius, dark } = useKit();
|
|
293
|
+
const { colors, radius, dark, font } = useKit();
|
|
294
|
+
const ff = font.family ? { fontFamily: font.family } : null;
|
|
292
295
|
const reduce = useReduceMotion();
|
|
293
296
|
const s = SIZES[size];
|
|
294
297
|
const c = color ?? toneColor(colors, tone);
|
|
@@ -328,7 +331,7 @@ export function Badge({
|
|
|
328
331
|
const natural = useRef<number | null>(null);
|
|
329
332
|
const rowWidth = useRef<number | null>(null);
|
|
330
333
|
const widthV = useRef(new Animated.Value(0)).current;
|
|
331
|
-
const flat =
|
|
334
|
+
const flat = flattenView(style);
|
|
332
335
|
const canSize = flat.width == null && flat.minWidth == null && flat.flex == null && flat.flexGrow == null && flat.alignSelf !== 'stretch';
|
|
333
336
|
|
|
334
337
|
const textChanged = text !== last.text;
|
|
@@ -410,7 +413,7 @@ export function Badge({
|
|
|
410
413
|
<Animated.Text
|
|
411
414
|
numberOfLines={1}
|
|
412
415
|
allowFontScaling={false}
|
|
413
|
-
style={[styles.label, { color: from && !roll ? mix(from.fg, fg) : fg, fontSize: s.font }, roll ? styles.hidden : null]}
|
|
416
|
+
style={[styles.label, ff, { color: from && !roll ? mix(from.fg, fg) : fg, fontSize: s.font }, roll ? styles.hidden : null]}
|
|
414
417
|
>
|
|
415
418
|
{text}
|
|
416
419
|
</Animated.Text>
|
|
@@ -540,7 +543,8 @@ export function NotificationBadge({
|
|
|
540
543
|
offset = [0, 0],
|
|
541
544
|
style,
|
|
542
545
|
}: NotificationBadgeProps) {
|
|
543
|
-
const { colors } = useKit();
|
|
546
|
+
const { colors, font } = useKit();
|
|
547
|
+
const ff = font.family ? { fontFamily: font.family } : null;
|
|
544
548
|
const c = color ?? toneColor(colors, tone);
|
|
545
549
|
const fg = !color && tone === 'accent' ? colors.accentForeground : readableOn(c);
|
|
546
550
|
const visible = count > 0 || !!showZero;
|
|
@@ -556,7 +560,7 @@ export function NotificationBadge({
|
|
|
556
560
|
Animated.spring(show, { toValue: visible ? 1 : 0, useNativeDriver: true, ...motion.bouncy }).start();
|
|
557
561
|
if (visible && prev.current !== count && prev.current > 0) {
|
|
558
562
|
pop.setValue(1.35);
|
|
559
|
-
Animated.spring(pop, { toValue: 1, useNativeDriver: true, damping:
|
|
563
|
+
Animated.spring(pop, { toValue: 1, useNativeDriver: true, damping: 29, stiffness: 320, mass: 0.6 }).start();
|
|
560
564
|
}
|
|
561
565
|
prev.current = count;
|
|
562
566
|
}, [count, visible, show, pop]);
|
|
@@ -587,7 +591,7 @@ export function NotificationBadge({
|
|
|
587
591
|
]}
|
|
588
592
|
>
|
|
589
593
|
{dot ? null : (
|
|
590
|
-
<Text allowFontScaling={false} numberOfLines={1} style={[styles.count, { color: fg, fontSize: size === 'sm' ? 10 : 11.5 }]}>
|
|
594
|
+
<Text allowFontScaling={false} numberOfLines={1} style={[styles.count, ff, { color: fg, fontSize: size === 'sm' ? 10 : 11.5 }]}>
|
|
591
595
|
{text}
|
|
592
596
|
</Text>
|
|
593
597
|
)}
|
|
@@ -610,6 +614,16 @@ export function NotificationBadge({
|
|
|
610
614
|
);
|
|
611
615
|
}
|
|
612
616
|
|
|
617
|
+
/**
|
|
618
|
+
* The user's root style as one object. Not StyleSheet.flatten: with TypeScript 6 its RN 0.88 signature
|
|
619
|
+
* rejects a plain StyleProp<ViewStyle> once expo/types adds web-only keys to ViewStyle.
|
|
620
|
+
*/
|
|
621
|
+
function flattenView(style: StyleProp<ViewStyle>): ViewStyle {
|
|
622
|
+
if (!style || typeof style !== 'object') return {};
|
|
623
|
+
if (Array.isArray(style)) return Object.assign({}, ...style.map((s) => flattenView(s as StyleProp<ViewStyle>)));
|
|
624
|
+
return style as ViewStyle;
|
|
625
|
+
}
|
|
626
|
+
|
|
613
627
|
const styles = StyleSheet.create({
|
|
614
628
|
base: { flexDirection: 'row', alignItems: 'center', alignSelf: 'flex-start', borderWidth: 1 },
|
|
615
629
|
label: { fontWeight: '400', letterSpacing: 0.1 },
|
|
@@ -181,14 +181,17 @@ export function useKit(): Theme {
|
|
|
181
181
|
return useMemo(() => build(scheme, ctx?.overrides), [scheme, ctx?.overrides]);
|
|
182
182
|
}
|
|
183
183
|
|
|
184
|
-
/**
|
|
184
|
+
/**
|
|
185
|
+
* Shared motion presets so the whole kit moves the same way. Every spring is critically damped
|
|
186
|
+
* (damping ≥ 2·√(stiffness·mass)): it settles smoothly with no overshoot or wobble.
|
|
187
|
+
*/
|
|
185
188
|
export const motion = {
|
|
186
189
|
/** Toggles, selection indicators. */
|
|
187
|
-
snappy: { damping:
|
|
188
|
-
/** Press feedback, pops. */
|
|
189
|
-
bouncy: { damping:
|
|
190
|
+
snappy: { damping: 30, stiffness: 260, mass: 0.8 },
|
|
191
|
+
/** Press feedback, pops. (Kept under its old name; it no longer bounces.) */
|
|
192
|
+
bouncy: { damping: 26, stiffness: 220, mass: 0.7 },
|
|
190
193
|
/** Sheets, layout changes. */
|
|
191
|
-
gentle: { damping:
|
|
194
|
+
gentle: { damping: 27, stiffness: 160, mass: 1 },
|
|
192
195
|
fast: 160,
|
|
193
196
|
normal: 240,
|
|
194
197
|
};
|
|
@@ -109,8 +109,8 @@ const PILL_H = 42;
|
|
|
109
109
|
/** Flex weight of the active item in the `pill` look (the others are 1). */
|
|
110
110
|
const PILL_GROW = 2.3;
|
|
111
111
|
// Liquid move: the edge in the direction of travel leads, the other one trails behind.
|
|
112
|
-
const LEAD = { damping:
|
|
113
|
-
const TRAIL = { damping:
|
|
112
|
+
const LEAD = { damping: 31, stiffness: 320, mass: 0.7 };
|
|
113
|
+
const TRAIL = { damping: 24, stiffness: 150, mass: 0.9 };
|
|
114
114
|
|
|
115
115
|
/**
|
|
116
116
|
* Bottom navigation in five looks — minimal dot, floating capsule, expanding pill, notched centre
|
|
@@ -444,6 +444,8 @@ interface NavButtonProps {
|
|
|
444
444
|
}
|
|
445
445
|
|
|
446
446
|
function NavButton({ item, active, look, tint, idle, surface, fab, showLabels, reduce, onPress }: NavButtonProps) {
|
|
447
|
+
const { font } = useKit();
|
|
448
|
+
const ff = font.family ? { fontFamily: font.family } : null;
|
|
447
449
|
const press = useRef(new Animated.Value(1)).current; // press squish (native)
|
|
448
450
|
const pop = useRef(new Animated.Value(active ? 1 : 0)).current; // active state (native)
|
|
449
451
|
const grow = useRef(new Animated.Value(active ? 1 : 0)).current; // pill width (JS — layout)
|
|
@@ -512,6 +514,7 @@ function NavButton({ item, active, look, tint, idle, surface, fab, showLabels, r
|
|
|
512
514
|
numberOfLines={1}
|
|
513
515
|
style={[
|
|
514
516
|
styles.pillLabel,
|
|
517
|
+
ff,
|
|
515
518
|
{
|
|
516
519
|
width: labelW + 1,
|
|
517
520
|
color: tint,
|
|
@@ -528,7 +531,7 @@ function NavButton({ item, active, look, tint, idle, surface, fab, showLabels, r
|
|
|
528
531
|
{/* Invisible measurer: the label's natural width, so it never ellipsizes while growing. */}
|
|
529
532
|
{showLabels ? (
|
|
530
533
|
<View pointerEvents="none" style={styles.measure} accessibilityElementsHidden importantForAccessibility="no-hide-descendants">
|
|
531
|
-
<Text style={[styles.pillLabel, styles.selfStart]} onLayout={(e) => setLabelW(Math.ceil(e.nativeEvent.layout.width))}>
|
|
534
|
+
<Text style={[styles.pillLabel, styles.selfStart, ff]} onLayout={(e) => setLabelW(Math.ceil(e.nativeEvent.layout.width))}>
|
|
532
535
|
{item.label}
|
|
533
536
|
</Text>
|
|
534
537
|
</View>
|
|
@@ -561,6 +564,7 @@ function NavButton({ item, active, look, tint, idle, surface, fab, showLabels, r
|
|
|
561
564
|
style={[
|
|
562
565
|
styles.label,
|
|
563
566
|
styles.floatLabel,
|
|
567
|
+
ff,
|
|
564
568
|
{ color: tint, opacity: fadeIn, transform: [{ translateY: pop.interpolate({ inputRange: [0, 1], outputRange: [6, 0] }) }] },
|
|
565
569
|
]}
|
|
566
570
|
>
|
|
@@ -587,7 +591,7 @@ function NavButton({ item, active, look, tint, idle, surface, fab, showLabels, r
|
|
|
587
591
|
{badge}
|
|
588
592
|
</Animated.View>
|
|
589
593
|
{showLabels ? (
|
|
590
|
-
<Text numberOfLines={1} style={[styles.label, { color: active ? tint : idle }]}>
|
|
594
|
+
<Text numberOfLines={1} style={[styles.label, ff, { color: active ? tint : idle }]}>
|
|
591
595
|
{item.label}
|
|
592
596
|
</Text>
|
|
593
597
|
) : null}
|
|
@@ -653,6 +657,8 @@ function CentreAction({
|
|
|
653
657
|
showLabel: boolean;
|
|
654
658
|
onPress: () => void;
|
|
655
659
|
}) {
|
|
660
|
+
const { font } = useKit();
|
|
661
|
+
const ff = font.family ? { fontFamily: font.family } : null;
|
|
656
662
|
const press = useRef(new Animated.Value(1)).current;
|
|
657
663
|
const pressTo = (v: number) =>
|
|
658
664
|
Animated.spring(press, { toValue: v, useNativeDriver: true, ...(v < 1 ? motion.snappy : motion.bouncy) }).start();
|
|
@@ -671,7 +677,7 @@ function CentreAction({
|
|
|
671
677
|
</FabFace>
|
|
672
678
|
</Animated.View>
|
|
673
679
|
{showLabel ? (
|
|
674
|
-
<Text numberOfLines={1} style={[styles.label, styles.abs, { top: labelTop, color: labelColor }]}>
|
|
680
|
+
<Text numberOfLines={1} style={[styles.label, styles.abs, ff, { top: labelTop, color: labelColor }]}>
|
|
675
681
|
{item.label}
|
|
676
682
|
</Text>
|
|
677
683
|
) : null}
|
|
@@ -758,7 +764,8 @@ function FabFace({
|
|
|
758
764
|
|
|
759
765
|
/** Dot or count. Pops in with a spring when it appears or its value changes. */
|
|
760
766
|
function Badge({ value, ring, reduce }: { value: true | number; ring: string; reduce: boolean }) {
|
|
761
|
-
const { colors, radius } = useKit();
|
|
767
|
+
const { colors, radius, font } = useKit();
|
|
768
|
+
const ff = font.family ? { fontFamily: font.family } : null;
|
|
762
769
|
const s = useRef(new Animated.Value(reduce ? 1 : 0.3)).current;
|
|
763
770
|
useEffect(() => {
|
|
764
771
|
if (reduce) {
|
|
@@ -784,7 +791,7 @@ function Badge({ value, ring, reduce }: { value: true | number; ring: string; re
|
|
|
784
791
|
},
|
|
785
792
|
]}
|
|
786
793
|
>
|
|
787
|
-
{!dot && <Text style={[styles.badgeText, { color: colors.dangerForeground }]}>{text}</Text>}
|
|
794
|
+
{!dot && <Text style={[styles.badgeText, ff, { color: colors.dangerForeground }]}>{text}</Text>}
|
|
788
795
|
</Animated.View>
|
|
789
796
|
);
|
|
790
797
|
}
|
|
@@ -181,14 +181,17 @@ export function useKit(): Theme {
|
|
|
181
181
|
return useMemo(() => build(scheme, ctx?.overrides), [scheme, ctx?.overrides]);
|
|
182
182
|
}
|
|
183
183
|
|
|
184
|
-
/**
|
|
184
|
+
/**
|
|
185
|
+
* Shared motion presets so the whole kit moves the same way. Every spring is critically damped
|
|
186
|
+
* (damping ≥ 2·√(stiffness·mass)): it settles smoothly with no overshoot or wobble.
|
|
187
|
+
*/
|
|
185
188
|
export const motion = {
|
|
186
189
|
/** Toggles, selection indicators. */
|
|
187
|
-
snappy: { damping:
|
|
188
|
-
/** Press feedback, pops. */
|
|
189
|
-
bouncy: { damping:
|
|
190
|
+
snappy: { damping: 30, stiffness: 260, mass: 0.8 },
|
|
191
|
+
/** Press feedback, pops. (Kept under its old name; it no longer bounces.) */
|
|
192
|
+
bouncy: { damping: 26, stiffness: 220, mass: 0.7 },
|
|
190
193
|
/** Sheets, layout changes. */
|
|
191
|
-
gentle: { damping:
|
|
194
|
+
gentle: { damping: 27, stiffness: 160, mass: 1 },
|
|
192
195
|
fast: 160,
|
|
193
196
|
normal: 240,
|
|
194
197
|
};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as Haptics from 'expo-haptics';
|
|
2
|
-
import React, { useEffect, useMemo, useRef, useState } from 'react';
|
|
2
|
+
import React, { useEffect, useMemo, useRef, useState, type ComponentRef } from 'react';
|
|
3
3
|
import {
|
|
4
4
|
AccessibilityInfo,
|
|
5
5
|
Animated,
|
|
@@ -75,7 +75,7 @@ export interface BottomSheetProps {
|
|
|
75
75
|
|
|
76
76
|
const DEFAULT_BOTTOM_INSET = Platform.select({ ios: 20, android: 12, default: 16 }) ?? 16;
|
|
77
77
|
/** Kit gentle, firmed up — glides between detents without bouncing past them. */
|
|
78
|
-
const SNAP_SPRING = { ...motion.gentle, damping:
|
|
78
|
+
const SNAP_SPRING = { ...motion.gentle, damping: 29, stiffness: 220, mass: 0.9 };
|
|
79
79
|
/** Extra sheet below the screen edge, so pulling up past the top snap never shows a gap. */
|
|
80
80
|
const OVERDRAG = 120;
|
|
81
81
|
/** Never let the sheet's top go closer than this to the top of the screen. */
|
|
@@ -122,7 +122,8 @@ export function BottomSheet({
|
|
|
122
122
|
style,
|
|
123
123
|
contentStyle,
|
|
124
124
|
}: BottomSheetProps) {
|
|
125
|
-
const { colors, radius, dark } = useKit();
|
|
125
|
+
const { colors, radius, dark, font } = useKit();
|
|
126
|
+
const ff = font.family ? { fontFamily: font.family } : null;
|
|
126
127
|
const reduceMotion = useReduceMotion();
|
|
127
128
|
const { height: screen } = useWindowDimensions();
|
|
128
129
|
|
|
@@ -164,7 +165,7 @@ export function BottomSheet({
|
|
|
164
165
|
const shown = useRef(false); // auto: slid in once measured
|
|
165
166
|
const index = useRef(initialSnap);
|
|
166
167
|
const scrollY = useRef(0);
|
|
167
|
-
const rootRef = useRef<View
|
|
168
|
+
const rootRef = useRef<ComponentRef<typeof View>>(null);
|
|
168
169
|
|
|
169
170
|
const bodyDrags = dragFromContent ?? scrollable;
|
|
170
171
|
const live = useRef({ stops, closed, max, dismissible, onClose, onSnapChange, haptics, reduceMotion, scrollable, bodyDrags, expanded });
|
|
@@ -473,12 +474,12 @@ export function BottomSheet({
|
|
|
473
474
|
<View style={[styles.header, !handle && { paddingTop: 20 }]}>
|
|
474
475
|
<View style={styles.headerText}>
|
|
475
476
|
{title ? (
|
|
476
|
-
<Text accessibilityRole="header" style={[styles.title, { color: colors.foreground }]} numberOfLines={1}>
|
|
477
|
+
<Text accessibilityRole="header" style={[styles.title, ff, { color: colors.foreground }]} numberOfLines={1}>
|
|
477
478
|
{title}
|
|
478
479
|
</Text>
|
|
479
480
|
) : null}
|
|
480
481
|
{subtitle ? (
|
|
481
|
-
<Text style={[styles.subtitle, { color: colors.mutedForeground }]} numberOfLines={1}>
|
|
482
|
+
<Text style={[styles.subtitle, ff, { color: colors.mutedForeground }]} numberOfLines={1}>
|
|
482
483
|
{subtitle}
|
|
483
484
|
</Text>
|
|
484
485
|
) : null}
|
|
@@ -181,14 +181,17 @@ export function useKit(): Theme {
|
|
|
181
181
|
return useMemo(() => build(scheme, ctx?.overrides), [scheme, ctx?.overrides]);
|
|
182
182
|
}
|
|
183
183
|
|
|
184
|
-
/**
|
|
184
|
+
/**
|
|
185
|
+
* Shared motion presets so the whole kit moves the same way. Every spring is critically damped
|
|
186
|
+
* (damping ≥ 2·√(stiffness·mass)): it settles smoothly with no overshoot or wobble.
|
|
187
|
+
*/
|
|
185
188
|
export const motion = {
|
|
186
189
|
/** Toggles, selection indicators. */
|
|
187
|
-
snappy: { damping:
|
|
188
|
-
/** Press feedback, pops. */
|
|
189
|
-
bouncy: { damping:
|
|
190
|
+
snappy: { damping: 30, stiffness: 260, mass: 0.8 },
|
|
191
|
+
/** Press feedback, pops. (Kept under its old name; it no longer bounces.) */
|
|
192
|
+
bouncy: { damping: 26, stiffness: 220, mass: 0.7 },
|
|
190
193
|
/** Sheets, layout changes. */
|
|
191
|
-
gentle: { damping:
|
|
194
|
+
gentle: { damping: 27, stiffness: 160, mass: 1 },
|
|
192
195
|
fast: 160,
|
|
193
196
|
normal: 240,
|
|
194
197
|
};
|
|
@@ -116,7 +116,8 @@ export function Button({
|
|
|
116
116
|
onPressOut,
|
|
117
117
|
...props
|
|
118
118
|
}: ButtonProps) {
|
|
119
|
-
const { colors, radius, dark } = useKit();
|
|
119
|
+
const { colors, radius, dark, font } = useKit();
|
|
120
|
+
const ff = font.family ? { fontFamily: font.family } : null;
|
|
120
121
|
const gid = 'btn' + useId().replace(/[^a-zA-Z0-9]/g, '');
|
|
121
122
|
const scale = useRef(new Animated.Value(1)).current;
|
|
122
123
|
const isDisabled = disabled || loading;
|
|
@@ -149,7 +150,7 @@ export function Button({
|
|
|
149
150
|
const label = isTextNode(children) ? (
|
|
150
151
|
<Text
|
|
151
152
|
numberOfLines={1}
|
|
152
|
-
style={[styles.label, { color: fg, fontSize: s.font }, variant === 'link' && styles.link, textStyle]}
|
|
153
|
+
style={[styles.label, ff, { color: fg, fontSize: s.font }, variant === 'link' && styles.link, textStyle]}
|
|
153
154
|
>
|
|
154
155
|
{children}
|
|
155
156
|
</Text>
|
|
@@ -235,7 +236,7 @@ export function Button({
|
|
|
235
236
|
<View style={styles.row}>
|
|
236
237
|
<ActivityIndicator size="small" color={fg} />
|
|
237
238
|
{size !== 'icon' && isTextNode(children) ? (
|
|
238
|
-
<Text style={[styles.label, { color: fg, fontSize: s.font, opacity: 0.85 }]}>{children}</Text>
|
|
239
|
+
<Text style={[styles.label, ff, { color: fg, fontSize: s.font, opacity: 0.85 }]}>{children}</Text>
|
|
239
240
|
) : null}
|
|
240
241
|
</View>
|
|
241
242
|
) : (
|
|
@@ -181,14 +181,17 @@ export function useKit(): Theme {
|
|
|
181
181
|
return useMemo(() => build(scheme, ctx?.overrides), [scheme, ctx?.overrides]);
|
|
182
182
|
}
|
|
183
183
|
|
|
184
|
-
/**
|
|
184
|
+
/**
|
|
185
|
+
* Shared motion presets so the whole kit moves the same way. Every spring is critically damped
|
|
186
|
+
* (damping ≥ 2·√(stiffness·mass)): it settles smoothly with no overshoot or wobble.
|
|
187
|
+
*/
|
|
185
188
|
export const motion = {
|
|
186
189
|
/** Toggles, selection indicators. */
|
|
187
|
-
snappy: { damping:
|
|
188
|
-
/** Press feedback, pops. */
|
|
189
|
-
bouncy: { damping:
|
|
190
|
+
snappy: { damping: 30, stiffness: 260, mass: 0.8 },
|
|
191
|
+
/** Press feedback, pops. (Kept under its old name; it no longer bounces.) */
|
|
192
|
+
bouncy: { damping: 26, stiffness: 220, mass: 0.7 },
|
|
190
193
|
/** Sheets, layout changes. */
|
|
191
|
-
gentle: { damping:
|
|
194
|
+
gentle: { damping: 27, stiffness: 160, mass: 1 },
|
|
192
195
|
fast: 160,
|
|
193
196
|
normal: 240,
|
|
194
197
|
};
|
|
@@ -105,7 +105,8 @@ export function Button3D({
|
|
|
105
105
|
accessibilityLabel,
|
|
106
106
|
style,
|
|
107
107
|
}: Button3DProps) {
|
|
108
|
-
const { dark } = useKit();
|
|
108
|
+
const { dark, font } = useKit();
|
|
109
|
+
const ff = font.family ? { fontFamily: font.family } : null;
|
|
109
110
|
const s = SIZES[size];
|
|
110
111
|
const depth = depthProp ?? s.depth;
|
|
111
112
|
const kind = appearance === 'auto' ? (dark ? 'light' : 'dark') : appearance;
|
|
@@ -122,7 +123,7 @@ export function Button3D({
|
|
|
122
123
|
) : isTextNode(children) ? (
|
|
123
124
|
// No numberOfLines: on a narrow fixed-width key ("esc", "Q") the label may use the padding
|
|
124
125
|
// instead of being cut to an ellipsis.
|
|
125
|
-
<Text style={{ color: m.ink, fontSize: round ? s.font + 4 : s.font, fontWeight: '600', letterSpacing: 0.1, flexShrink: 0, textAlign: 'center' }}>
|
|
126
|
+
<Text style={[{ color: m.ink, fontSize: round ? s.font + 4 : s.font, fontWeight: '600', letterSpacing: 0.1, flexShrink: 0, textAlign: 'center' }, ff]}>
|
|
126
127
|
{children}
|
|
127
128
|
</Text>
|
|
128
129
|
) : (
|
|
@@ -181,14 +181,17 @@ export function useKit(): Theme {
|
|
|
181
181
|
return useMemo(() => build(scheme, ctx?.overrides), [scheme, ctx?.overrides]);
|
|
182
182
|
}
|
|
183
183
|
|
|
184
|
-
/**
|
|
184
|
+
/**
|
|
185
|
+
* Shared motion presets so the whole kit moves the same way. Every spring is critically damped
|
|
186
|
+
* (damping ≥ 2·√(stiffness·mass)): it settles smoothly with no overshoot or wobble.
|
|
187
|
+
*/
|
|
185
188
|
export const motion = {
|
|
186
189
|
/** Toggles, selection indicators. */
|
|
187
|
-
snappy: { damping:
|
|
188
|
-
/** Press feedback, pops. */
|
|
189
|
-
bouncy: { damping:
|
|
190
|
+
snappy: { damping: 30, stiffness: 260, mass: 0.8 },
|
|
191
|
+
/** Press feedback, pops. (Kept under its old name; it no longer bounces.) */
|
|
192
|
+
bouncy: { damping: 26, stiffness: 220, mass: 0.7 },
|
|
190
193
|
/** Sheets, layout changes. */
|
|
191
|
-
gentle: { damping:
|
|
194
|
+
gentle: { damping: 27, stiffness: 160, mass: 1 },
|
|
192
195
|
fast: 160,
|
|
193
196
|
normal: 240,
|
|
194
197
|
};
|