@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,4 +1,4 @@
|
|
|
1
|
-
import React, { useCallback, useEffect, useMemo, useRef, useState, type ComponentRef } from 'react';
|
|
1
|
+
import React, { useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState, type ComponentRef } from 'react';
|
|
2
2
|
import {
|
|
3
3
|
AccessibilityInfo,
|
|
4
4
|
Animated,
|
|
@@ -7,7 +7,6 @@ import {
|
|
|
7
7
|
Keyboard,
|
|
8
8
|
KeyboardAvoidingView,
|
|
9
9
|
Modal,
|
|
10
|
-
PanResponder,
|
|
11
10
|
Platform,
|
|
12
11
|
Pressable,
|
|
13
12
|
ScrollView,
|
|
@@ -21,7 +20,7 @@ import {
|
|
|
21
20
|
} from 'react-native';
|
|
22
21
|
import Svg, { Circle, Path } from 'react-native-svg';
|
|
23
22
|
|
|
24
|
-
import { alpha, motion, readableOn, useKit, useLayout } from '@/lib/kit';
|
|
23
|
+
import { alpha, motion, readableOn, useKit, useLayout, usePanResponder } from '@/lib/kit';
|
|
25
24
|
|
|
26
25
|
export type SelectPresentation = 'dropdown' | 'sheet';
|
|
27
26
|
/** @deprecated Use `SelectPresentation`. */
|
|
@@ -165,12 +164,12 @@ export function Select<T extends string | number = string>({
|
|
|
165
164
|
maxChips = 2,
|
|
166
165
|
label,
|
|
167
166
|
floatingLabel = true,
|
|
168
|
-
placeholder
|
|
167
|
+
placeholder: placeholderProp,
|
|
169
168
|
presentation,
|
|
170
169
|
variant,
|
|
171
170
|
size = 'md',
|
|
172
171
|
searchable,
|
|
173
|
-
searchPlaceholder
|
|
172
|
+
searchPlaceholder: searchPlaceholderProp,
|
|
174
173
|
emptyText,
|
|
175
174
|
title,
|
|
176
175
|
error,
|
|
@@ -192,7 +191,9 @@ export function Select<T extends string | number = string>({
|
|
|
192
191
|
optionStyle,
|
|
193
192
|
optionTextStyle,
|
|
194
193
|
}: SelectProps<T>) {
|
|
195
|
-
const { colors, radius, dark, font, shadow } = useKit();
|
|
194
|
+
const { colors, radius, dark, font, shadow, labels } = useKit();
|
|
195
|
+
const placeholder = placeholderProp ?? labels.selectPlaceholder;
|
|
196
|
+
const searchPlaceholder = searchPlaceholderProp ?? labels.search;
|
|
196
197
|
const reduce = useReduceMotion();
|
|
197
198
|
const ff = font.family ? { fontFamily: font.family } : null;
|
|
198
199
|
const tint = accent ?? colors.accent;
|
|
@@ -232,17 +233,14 @@ export function Select<T extends string | number = string>({
|
|
|
232
233
|
const viewH = useRef(0);
|
|
233
234
|
const closeTimer = useRef<ReturnType<typeof setTimeout> | null>(null);
|
|
234
235
|
const alive = useRef(true);
|
|
235
|
-
// Read by the sheet's pan responder, which is created once.
|
|
236
|
-
const reduceRef = useRef(reduce);
|
|
237
|
-
reduceRef.current = reduce;
|
|
238
236
|
|
|
239
237
|
const floating = open || picked.length > 0;
|
|
240
|
-
const float =
|
|
241
|
-
const focus =
|
|
242
|
-
const halo =
|
|
243
|
-
const show =
|
|
244
|
-
const drag =
|
|
245
|
-
const shake =
|
|
238
|
+
const [float] = useState(() => new Animated.Value(floating ? 1 : 0)); // native
|
|
239
|
+
const [focus] = useState(() => new Animated.Value(0)); // JS: colours
|
|
240
|
+
const [halo] = useState(() => new Animated.Value(0)); // native: focus halo
|
|
241
|
+
const [show] = useState(() => new Animated.Value(0)); // native: backdrop + sheet/dropdown
|
|
242
|
+
const [drag] = useState(() => new Animated.Value(0)); // native: sheet drag offset
|
|
243
|
+
const [shake] = useState(() => new Animated.Value(0)); // native
|
|
246
244
|
|
|
247
245
|
useEffect(() => {
|
|
248
246
|
alive.current = true;
|
|
@@ -419,7 +417,8 @@ export function Select<T extends string | number = string>({
|
|
|
419
417
|
let i = from < 0 ? (dir > 0 ? -1 : n) : from;
|
|
420
418
|
for (let k = 0; k < n; k++) {
|
|
421
419
|
i = (i + dir + n) % n;
|
|
422
|
-
|
|
420
|
+
const o = flat[i];
|
|
421
|
+
if (o && !o.disabled) {
|
|
423
422
|
setHi(i);
|
|
424
423
|
reveal(i);
|
|
425
424
|
return;
|
|
@@ -429,35 +428,37 @@ export function Select<T extends string | number = string>({
|
|
|
429
428
|
|
|
430
429
|
// Web keyboard: ↑/↓ move, Home/End jump, Enter picks, Escape/Tab close.
|
|
431
430
|
const onKey = useRef<(e: KeyboardEvent) => void>(() => {});
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
step(e.key === 'ArrowDown' ? 1 : -1);
|
|
438
|
-
break;
|
|
439
|
-
case 'Home':
|
|
440
|
-
case 'End':
|
|
441
|
-
if (searchable && query) return; // let the caret move in the search field
|
|
442
|
-
e.preventDefault();
|
|
443
|
-
step(e.key === 'Home' ? 1 : -1, e.key === 'Home' ? -1 : flat.length);
|
|
444
|
-
break;
|
|
445
|
-
case 'Enter':
|
|
446
|
-
if (hi >= 0 && flat[hi]) {
|
|
431
|
+
useLayoutEffect(() => {
|
|
432
|
+
onKey.current = (e) => {
|
|
433
|
+
switch (e.key) {
|
|
434
|
+
case 'ArrowDown':
|
|
435
|
+
case 'ArrowUp':
|
|
447
436
|
e.preventDefault();
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
437
|
+
step(e.key === 'ArrowDown' ? 1 : -1);
|
|
438
|
+
break;
|
|
439
|
+
case 'Home':
|
|
440
|
+
case 'End':
|
|
441
|
+
if (searchable && query) return; // let the caret move in the search field
|
|
442
|
+
e.preventDefault();
|
|
443
|
+
step(e.key === 'Home' ? 1 : -1, e.key === 'Home' ? -1 : flat.length);
|
|
444
|
+
break;
|
|
445
|
+
case 'Enter':
|
|
446
|
+
if (hi >= 0 && flat[hi]) {
|
|
447
|
+
e.preventDefault();
|
|
448
|
+
choose(flat[hi]);
|
|
449
|
+
}
|
|
450
|
+
break;
|
|
451
|
+
case 'Escape':
|
|
452
|
+
e.preventDefault();
|
|
453
|
+
e.stopPropagation();
|
|
454
|
+
close();
|
|
455
|
+
break;
|
|
456
|
+
case 'Tab':
|
|
457
|
+
close();
|
|
458
|
+
break;
|
|
459
|
+
}
|
|
460
|
+
};
|
|
461
|
+
});
|
|
461
462
|
useEffect(() => {
|
|
462
463
|
if (!open || !isWeb || typeof document === 'undefined') return;
|
|
463
464
|
const handler = (e: KeyboardEvent) => onKey.current(e);
|
|
@@ -466,21 +467,19 @@ export function Select<T extends string | number = string>({
|
|
|
466
467
|
}, [open]);
|
|
467
468
|
|
|
468
469
|
// Drag the sheet's grabber down to dismiss.
|
|
469
|
-
const
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
});
|
|
483
|
-
}, [drag]);
|
|
470
|
+
const back = () =>
|
|
471
|
+
reduce
|
|
472
|
+
? Animated.timing(drag, { toValue: 0, duration: 150, easing: Easing.bezier(0.32, 0.72, 0, 1), useNativeDriver: true }).start()
|
|
473
|
+
: Animated.spring(drag, { toValue: 0, useNativeDriver: true, ...motion.snappy }).start();
|
|
474
|
+
const pan = usePanResponder({
|
|
475
|
+
onMoveShouldSetPanResponder: (_, g) => g.dy > 4 && Math.abs(g.dy) > Math.abs(g.dx),
|
|
476
|
+
onPanResponderMove: (_, g) => drag.setValue(Math.max(0, g.dy)),
|
|
477
|
+
onPanResponderRelease: (_, g) => {
|
|
478
|
+
if (g.dy > 110 || g.vy > 1.1) setOpen(false);
|
|
479
|
+
else back();
|
|
480
|
+
},
|
|
481
|
+
onPanResponderTerminate: back,
|
|
482
|
+
});
|
|
484
483
|
|
|
485
484
|
const active = error ? colors.danger : tint;
|
|
486
485
|
const borderColor = focus.interpolate({
|
|
@@ -524,7 +523,7 @@ export function Select<T extends string | number = string>({
|
|
|
524
523
|
onPress={() => onSearch('')}
|
|
525
524
|
hitSlop={12}
|
|
526
525
|
accessibilityRole="button"
|
|
527
|
-
accessibilityLabel=
|
|
526
|
+
accessibilityLabel={labels.clearSearch}
|
|
528
527
|
style={[styles.clear, { backgroundColor: alpha(colors.mutedForeground, 0.22) }]}
|
|
529
528
|
>
|
|
530
529
|
<Icon name="x" size={11} color={colors.foreground} strokeWidth={2.4} />
|
|
@@ -588,11 +587,11 @@ export function Select<T extends string | number = string>({
|
|
|
588
587
|
<Icon name="search" size={dense ? 16 : 20} color={colors.mutedForeground} />
|
|
589
588
|
</View>
|
|
590
589
|
<Text style={[styles.emptyTitle, ff, { color: colors.foreground, fontSize: dense ? 14 : 15 }]}>
|
|
591
|
-
{q ?
|
|
590
|
+
{q ? labels.noResults : labels.noOptions}
|
|
592
591
|
</Text>
|
|
593
592
|
{q ? (
|
|
594
593
|
<Text style={[styles.emptyText, ff, { color: colors.mutedForeground }]}>
|
|
595
|
-
{emptyText ??
|
|
594
|
+
{emptyText ?? labels.nothingMatches(query.trim())}
|
|
596
595
|
</Text>
|
|
597
596
|
) : null}
|
|
598
597
|
</View>
|
|
@@ -611,7 +610,7 @@ export function Select<T extends string | number = string>({
|
|
|
611
610
|
]}
|
|
612
611
|
>
|
|
613
612
|
<Text maxFontSizeMultiplier={FONT_CAP} style={[styles.footDenseText, ff, { color: colors.mutedForeground }]}>
|
|
614
|
-
|
|
613
|
+
{labels.clear}
|
|
615
614
|
</Text>
|
|
616
615
|
</Pressable>
|
|
617
616
|
<View style={styles.footMid}>
|
|
@@ -623,7 +622,7 @@ export function Select<T extends string | number = string>({
|
|
|
623
622
|
style={({ pressed }) => [styles.footSolid, { backgroundColor: tint, borderRadius: radius.capsule(32), opacity: pressed ? 0.85 : 1 }]}
|
|
624
623
|
>
|
|
625
624
|
<Text maxFontSizeMultiplier={FONT_CAP} style={[styles.footDenseText, styles.footStrong, ff, { color: readableOn(tint) }]}>
|
|
626
|
-
|
|
625
|
+
{labels.done}
|
|
627
626
|
</Text>
|
|
628
627
|
</Pressable>
|
|
629
628
|
</View>
|
|
@@ -636,7 +635,7 @@ export function Select<T extends string | number = string>({
|
|
|
636
635
|
style={({ pressed }) => [styles.footBtn, { borderRadius: radius.md, opacity: many.length ? (pressed ? 0.6 : 1) : 0.4 }]}
|
|
637
636
|
>
|
|
638
637
|
<Text maxFontSizeMultiplier={FONT_CAP} style={[styles.footText, ff, { color: colors.foreground }]}>
|
|
639
|
-
|
|
638
|
+
{labels.clear}
|
|
640
639
|
</Text>
|
|
641
640
|
</Pressable>
|
|
642
641
|
<Pressable
|
|
@@ -645,7 +644,7 @@ export function Select<T extends string | number = string>({
|
|
|
645
644
|
style={({ pressed }) => [styles.footBtn, styles.footMain, { backgroundColor: tint, borderRadius: radius.md, opacity: pressed ? 0.85 : 1 }]}
|
|
646
645
|
>
|
|
647
646
|
<Text maxFontSizeMultiplier={FONT_CAP} style={[styles.footText, styles.footStrong, styles.tabular, ff, { color: readableOn(tint) }]}>
|
|
648
|
-
{many.length ?
|
|
647
|
+
{many.length ? labels.doneCount(many.length) : labels.done}
|
|
649
648
|
</Text>
|
|
650
649
|
</Pressable>
|
|
651
650
|
</View>
|
|
@@ -702,7 +701,7 @@ export function Select<T extends string | number = string>({
|
|
|
702
701
|
disabled={disabled}
|
|
703
702
|
accessibilityRole="combobox"
|
|
704
703
|
accessibilityLabel={label}
|
|
705
|
-
accessibilityValue={{ text: picked.length ? picked.map((o) => o.label).join(', ') :
|
|
704
|
+
accessibilityValue={{ text: picked.length ? picked.map((o) => o.label).join(', ') : labels.noneSelected }}
|
|
706
705
|
accessibilityState={{ expanded: open, disabled: !!disabled }}
|
|
707
706
|
style={{ opacity: disabled ? 0.5 : 1 }}
|
|
708
707
|
>
|
|
@@ -759,7 +758,7 @@ export function Select<T extends string | number = string>({
|
|
|
759
758
|
onPress={() => item.option && remove(item.option.value)}
|
|
760
759
|
hitSlop={12}
|
|
761
760
|
accessibilityRole="button"
|
|
762
|
-
accessibilityLabel={
|
|
761
|
+
accessibilityLabel={labels.remove(item.option.label)}
|
|
763
762
|
style={({ pressed }) => [
|
|
764
763
|
styles.chipX,
|
|
765
764
|
{
|
|
@@ -777,7 +776,7 @@ export function Select<T extends string | number = string>({
|
|
|
777
776
|
) : (
|
|
778
777
|
<View
|
|
779
778
|
accessible
|
|
780
|
-
accessibilityLabel={maxChips > 0 ?
|
|
779
|
+
accessibilityLabel={maxChips > 0 ? labels.moreCount(item.more) : labels.selectedCount(item.more)}
|
|
781
780
|
style={[styles.chip, styles.more, { minHeight: sz.chip, backgroundColor: chipBg, borderRadius: radius.capsule(sz.chip) }]}
|
|
782
781
|
>
|
|
783
782
|
{maxChips > 0 ? (
|
|
@@ -788,7 +787,7 @@ export function Select<T extends string | number = string>({
|
|
|
788
787
|
<RollingNumber value={item.more} distance={sz.chipFont} reduce={reduce} style={[styles.chipText, ff, { color: tint, fontSize: sz.chipFont }]} />
|
|
789
788
|
{maxChips > 0 ? null : (
|
|
790
789
|
<Text maxFontSizeMultiplier={FONT_CAP} style={[styles.chipText, ff, { color: tint, fontSize: sz.chipFont, marginLeft: 3 }]}>
|
|
791
|
-
|
|
790
|
+
{labels.selectedSuffix}
|
|
792
791
|
</Text>
|
|
793
792
|
)}
|
|
794
793
|
</View>
|
|
@@ -852,7 +851,7 @@ export function Select<T extends string | number = string>({
|
|
|
852
851
|
|
|
853
852
|
<Modal visible={mounted} transparent animationType="none" statusBarTranslucent onRequestClose={close}>
|
|
854
853
|
<Animated.View style={[StyleSheet.absoluteFill, { backgroundColor: asSheet ? colors.overlay : 'transparent', opacity: show }]}>
|
|
855
|
-
<Pressable style={StyleSheet.absoluteFill} onPress={close} accessibilityLabel=
|
|
854
|
+
<Pressable style={StyleSheet.absoluteFill} onPress={close} accessibilityLabel={labels.close} accessibilityRole="button" />
|
|
856
855
|
</Animated.View>
|
|
857
856
|
|
|
858
857
|
{asSheet ? (
|
|
@@ -891,7 +890,7 @@ export function Select<T extends string | number = string>({
|
|
|
891
890
|
},
|
|
892
891
|
]}
|
|
893
892
|
>
|
|
894
|
-
<View {...pan
|
|
893
|
+
<View {...pan} style={styles.sheetHeader}>
|
|
895
894
|
{!wide ? <View style={[styles.grabber, { backgroundColor: colors.border }]} /> : null}
|
|
896
895
|
<Text style={[styles.title, ff, { color: colors.foreground }]}>{title ?? label}</Text>
|
|
897
896
|
{multiple ? (
|
|
@@ -899,7 +898,7 @@ export function Select<T extends string | number = string>({
|
|
|
899
898
|
{many.length ? (
|
|
900
899
|
<CountBadge count={many.length} tint={tint} reduce={reduce} />
|
|
901
900
|
) : (
|
|
902
|
-
<Text style={[styles.subtitle, ff, { color: colors.mutedForeground }]}>
|
|
901
|
+
<Text style={[styles.subtitle, ff, { color: colors.mutedForeground }]}>{labels.chooseOneOrMore}</Text>
|
|
903
902
|
)}
|
|
904
903
|
</View>
|
|
905
904
|
) : null}
|
|
@@ -942,7 +941,7 @@ export function Select<T extends string | number = string>({
|
|
|
942
941
|
}
|
|
943
942
|
|
|
944
943
|
/** Groups options by `group` (first-appearance order); a single untitled section when none are grouped. */
|
|
945
|
-
function sectionsOf<T extends string | number>(list: SelectOption<T>[]): { title?: string; rows: SelectOption<T>[] }[] {
|
|
944
|
+
function sectionsOf<T extends string | number>(list: SelectOption<T>[]): { title?: string | undefined; rows: SelectOption<T>[] }[] {
|
|
946
945
|
if (!list.some((o) => o.group)) return [{ rows: list }];
|
|
947
946
|
const map = new Map<string, SelectOption<T>[]>();
|
|
948
947
|
list.forEach((o) => map.set(o.group ?? '', [...(map.get(o.group ?? '') ?? []), o]));
|
|
@@ -982,7 +981,7 @@ function OptionRow<T extends string | number>({
|
|
|
982
981
|
}) {
|
|
983
982
|
const { colors, radius, font, dark } = useKit();
|
|
984
983
|
const ff = font.family ? { fontFamily: font.family } : null;
|
|
985
|
-
const check =
|
|
984
|
+
const [check] = useState(() => new Animated.Value(selected ? 1 : 0)); // native: scale + opacity
|
|
986
985
|
useEffect(() => {
|
|
987
986
|
// Reduce Motion: the check only fades (no pop / twist).
|
|
988
987
|
if (reduce) Animated.timing(check, { toValue: selected ? 1 : 0, duration: 150, useNativeDriver: true }).start();
|
|
@@ -1082,7 +1081,10 @@ function usePresence<V>(items: { key: string; item: V }[]) {
|
|
|
1082
1081
|
const out: Present<V>[] = [];
|
|
1083
1082
|
let next = 0;
|
|
1084
1083
|
const emitUpTo = (end: number) => {
|
|
1085
|
-
for (; next <= end; next++)
|
|
1084
|
+
for (; next <= end; next++) {
|
|
1085
|
+
const e = items[next];
|
|
1086
|
+
if (e) out.push({ ...e, leaving: false, appear: ready.current });
|
|
1087
|
+
}
|
|
1086
1088
|
};
|
|
1087
1089
|
for (const e of prev.current) {
|
|
1088
1090
|
if (live.has(e.key)) emitUpTo(items.findIndex((x) => x.key === e.key));
|
|
@@ -1121,11 +1123,13 @@ function AnimatedChip({
|
|
|
1121
1123
|
onGone: () => void;
|
|
1122
1124
|
children: React.ReactNode;
|
|
1123
1125
|
}) {
|
|
1124
|
-
const pop =
|
|
1125
|
-
const size =
|
|
1126
|
+
const [pop] = useState(() => new Animated.Value(appear ? 0 : 1)); // native: scale + opacity
|
|
1127
|
+
const [size] = useState(() => new Animated.Value(1)); // JS: width + margin of the outer slot
|
|
1126
1128
|
const [w, setW] = useState(0);
|
|
1127
1129
|
const gone = useRef(onGone);
|
|
1128
|
-
|
|
1130
|
+
useLayoutEffect(() => {
|
|
1131
|
+
gone.current = onGone;
|
|
1132
|
+
});
|
|
1129
1133
|
|
|
1130
1134
|
useEffect(() => {
|
|
1131
1135
|
let alive = true;
|
|
@@ -1238,12 +1242,13 @@ function RollingNumber({ value, style, distance = 10, reduce }: { value: number;
|
|
|
1238
1242
|
|
|
1239
1243
|
/** "N selected" pill whose number rolls; it pops out when the count drops to 0. */
|
|
1240
1244
|
function CountBadge({ count, tint, reduce }: { count: number; tint: string; reduce: boolean }) {
|
|
1241
|
-
const { radius, font } = useKit();
|
|
1245
|
+
const { radius, font, labels } = useKit();
|
|
1242
1246
|
const ff = font.family ? { fontFamily: font.family } : null;
|
|
1243
1247
|
const on = count > 0;
|
|
1244
|
-
const vis =
|
|
1245
|
-
|
|
1246
|
-
|
|
1248
|
+
const [vis] = useState(() => new Animated.Value(on ? 1 : 0)); // native
|
|
1249
|
+
// The last non-zero count, kept on screen while the badge pops out at 0.
|
|
1250
|
+
const [last, setLast] = useState(count);
|
|
1251
|
+
if (on && count !== last) setLast(count);
|
|
1247
1252
|
useEffect(() => {
|
|
1248
1253
|
const a = reduce
|
|
1249
1254
|
? Animated.timing(vis, { toValue: on ? 1 : 0, duration: 150, useNativeDriver: true })
|
|
@@ -1255,7 +1260,7 @@ function CountBadge({ count, tint, reduce }: { count: number; tint: string; redu
|
|
|
1255
1260
|
return (
|
|
1256
1261
|
<Animated.View
|
|
1257
1262
|
accessible
|
|
1258
|
-
accessibilityLabel={
|
|
1263
|
+
accessibilityLabel={labels.selectedCount(last)}
|
|
1259
1264
|
accessibilityLiveRegion="polite"
|
|
1260
1265
|
style={[
|
|
1261
1266
|
styles.badge,
|
|
@@ -1267,9 +1272,9 @@ function CountBadge({ count, tint, reduce }: { count: number; tint: string; redu
|
|
|
1267
1272
|
},
|
|
1268
1273
|
]}
|
|
1269
1274
|
>
|
|
1270
|
-
<RollingNumber value={last
|
|
1275
|
+
<RollingNumber value={last} distance={9} reduce={reduce} style={text} />
|
|
1271
1276
|
<Text maxFontSizeMultiplier={FONT_CAP} style={[text, styles.badgeSuffix]}>
|
|
1272
|
-
|
|
1277
|
+
{labels.selectedSuffix}
|
|
1273
1278
|
</Text>
|
|
1274
1279
|
</Animated.View>
|
|
1275
1280
|
);
|
|
@@ -1297,7 +1302,7 @@ function Highlight({ text, query, tint, style }: { text: string; query: string;
|
|
|
1297
1302
|
/** Helper / error line that fades and slides in; errors get an icon and are announced. */
|
|
1298
1303
|
function FieldMessage({ text, error, reduce, style }: { text: string; error: boolean; reduce: boolean; style?: StyleProp<TextStyle> }) {
|
|
1299
1304
|
const { colors, font } = useKit();
|
|
1300
|
-
const enter =
|
|
1305
|
+
const [enter] = useState(() => new Animated.Value(0)); // native
|
|
1301
1306
|
useEffect(() => {
|
|
1302
1307
|
enter.setValue(0);
|
|
1303
1308
|
if (reduce) Animated.timing(enter, { toValue: 1, duration: 150, useNativeDriver: true }).start();
|
|
@@ -1319,7 +1324,7 @@ function FieldMessage({ text, error, reduce, style }: { text: string; error: boo
|
|
|
1319
1324
|
}
|
|
1320
1325
|
|
|
1321
1326
|
function Chevron({ open, reduce, color, size, right }: { open: boolean; reduce: boolean; color: string; size: number; right: number }) {
|
|
1322
|
-
const turn =
|
|
1327
|
+
const [turn] = useState(() => new Animated.Value(open ? 1 : 0));
|
|
1323
1328
|
useEffect(() => {
|
|
1324
1329
|
if (reduce) turn.setValue(open ? 1 : 0);
|
|
1325
1330
|
else Animated.spring(turn, { toValue: open ? 1 : 0, useNativeDriver: true, ...motion.snappy }).start();
|