@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
|
@@ -24,60 +24,60 @@ export interface FloatingInputProps extends Omit<TextInputProps, 'style' | 'plac
|
|
|
24
24
|
/** Sits inside the field like a placeholder, then floats onto the border when focused or filled. */
|
|
25
25
|
label: string;
|
|
26
26
|
/** `false` puts the label above the field as static text (no notch) and shows `placeholder` inside. */
|
|
27
|
-
floatingLabel?: boolean;
|
|
27
|
+
floatingLabel?: boolean | undefined;
|
|
28
28
|
/** Hint inside the empty field — only used when `floatingLabel` is false. */
|
|
29
|
-
placeholder?: string;
|
|
30
|
-
variant?: FloatingInputVariant;
|
|
29
|
+
placeholder?: string | undefined;
|
|
30
|
+
variant?: FloatingInputVariant | undefined;
|
|
31
31
|
/** Error message. Turns the field red, shows it with an icon and shakes the field once when it appears. */
|
|
32
|
-
error?: string;
|
|
32
|
+
error?: string | undefined;
|
|
33
33
|
/** Valid state: success border and an animated check. A string is shown as the message under the field. */
|
|
34
|
-
success?: boolean | string;
|
|
34
|
+
success?: boolean | string | undefined;
|
|
35
35
|
/** Hint under the field (replaced by the error / success message while one is shown). */
|
|
36
|
-
helper?: string;
|
|
36
|
+
helper?: string | undefined;
|
|
37
37
|
/** Colour of the focused border, halo and floating label (default: theme accent). */
|
|
38
|
-
accent?: string;
|
|
38
|
+
accent?: string | undefined;
|
|
39
39
|
/** Background behind the field — the floating label cuts its notch with this colour. */
|
|
40
|
-
surface?: string;
|
|
41
|
-
left?: React.ReactNode;
|
|
42
|
-
right?: React.ReactNode;
|
|
40
|
+
surface?: string | undefined;
|
|
41
|
+
left?: React.ReactNode | undefined;
|
|
42
|
+
right?: React.ReactNode | undefined;
|
|
43
43
|
/** Text before the value, shown once the label floats — '₹', '+91', 'https://'. */
|
|
44
|
-
prefix?: string;
|
|
44
|
+
prefix?: string | undefined;
|
|
45
45
|
/** Text after the value, shown once the label floats — 'INR', 'kg', '.com'. */
|
|
46
|
-
suffix?: string;
|
|
46
|
+
suffix?: string | undefined;
|
|
47
47
|
/** Show an animated clear button while there is text. */
|
|
48
|
-
clearable?: boolean;
|
|
48
|
+
clearable?: boolean | undefined;
|
|
49
49
|
/** Show `length/maxLength` under the field (needs `maxLength`). */
|
|
50
|
-
counter?: boolean;
|
|
50
|
+
counter?: boolean | undefined;
|
|
51
51
|
/** 'sm' 44pt / 14px · 'md' 54pt / 16px · 'lg' 64pt / 18px — type, padding and icons scale too. */
|
|
52
|
-
size?: 'sm' | 'md' | 'lg';
|
|
52
|
+
size?: 'sm' | 'md' | 'lg' | undefined;
|
|
53
53
|
/** Root wrapper (the one that shakes) — margins, width, flex. */
|
|
54
|
-
style?: StyleProp<ViewStyle
|
|
54
|
+
style?: StyleProp<ViewStyle> | undefined;
|
|
55
55
|
/**
|
|
56
56
|
* The bordered box: background, border width / colour, radius, height, padding. Applied after
|
|
57
57
|
* the computed style, so it wins. A `borderColor` replaces the resting border only — focus
|
|
58
58
|
* (accent), error and success colours still take over in those states. A numeric `height` /
|
|
59
59
|
* `borderRadius` also re-centres the label and resizes the focus halo.
|
|
60
60
|
*/
|
|
61
|
-
fieldStyle?: StyleProp<ViewStyle
|
|
61
|
+
fieldStyle?: StyleProp<ViewStyle> | undefined;
|
|
62
62
|
/** The typed text — fontSize, fontWeight, color, letterSpacing, fontFamily… */
|
|
63
|
-
inputStyle?: StyleProp<TextStyle
|
|
63
|
+
inputStyle?: StyleProp<TextStyle> | undefined;
|
|
64
64
|
/**
|
|
65
65
|
* The label, floating or above the field. Its `color` is the resting colour; focus (accent),
|
|
66
66
|
* error (danger) and success colours still take over in those states. With `fontSize` the
|
|
67
67
|
* floating label rests at that size and floats at the same ratio as the default, and the notch
|
|
68
68
|
* follows the rendered label width.
|
|
69
69
|
*/
|
|
70
|
-
labelStyle?: StyleProp<TextStyle
|
|
70
|
+
labelStyle?: StyleProp<TextStyle> | undefined;
|
|
71
71
|
/** Helper / error / success text under the field. `color` applies to the helper; error and success keep their tone colour. */
|
|
72
|
-
messageStyle?: StyleProp<TextStyle
|
|
72
|
+
messageStyle?: StyleProp<TextStyle> | undefined;
|
|
73
73
|
/** `prefix` text. */
|
|
74
|
-
prefixStyle?: StyleProp<TextStyle
|
|
74
|
+
prefixStyle?: StyleProp<TextStyle> | undefined;
|
|
75
75
|
/** `suffix` text. */
|
|
76
|
-
suffixStyle?: StyleProp<TextStyle
|
|
76
|
+
suffixStyle?: StyleProp<TextStyle> | undefined;
|
|
77
77
|
/** The `length/maxLength` counter. Turns danger at the limit regardless. */
|
|
78
|
-
counterStyle?: StyleProp<TextStyle
|
|
78
|
+
counterStyle?: StyleProp<TextStyle> | undefined;
|
|
79
79
|
/** Built-in icons at rest — the clear button (default: theme mutedForeground). */
|
|
80
|
-
iconColor?: string;
|
|
80
|
+
iconColor?: string | undefined;
|
|
81
81
|
}
|
|
82
82
|
|
|
83
83
|
/** Everything that scales with `size`: height, type, padding, icons and the floated label. */
|
|
@@ -169,7 +169,7 @@ export const FloatingInput = forwardRef<ComponentRef<typeof TextInput>, Floating
|
|
|
169
169
|
},
|
|
170
170
|
ref
|
|
171
171
|
) {
|
|
172
|
-
const { colors, radius, font } = useKit();
|
|
172
|
+
const { colors, radius, font, labels } = useKit();
|
|
173
173
|
const reduce = useReduceMotion();
|
|
174
174
|
const ff = font.family ? { fontFamily: font.family } : null;
|
|
175
175
|
const S = FLOATING_INPUT_SIZES[size];
|
|
@@ -197,12 +197,12 @@ export const FloatingInput = forwardRef<ComponentRef<typeof TextInput>, Floating
|
|
|
197
197
|
const ok = !error && !!success;
|
|
198
198
|
const successText = typeof success === 'string' && ok ? success : undefined;
|
|
199
199
|
|
|
200
|
-
const float =
|
|
201
|
-
const glow =
|
|
202
|
-
const focus =
|
|
203
|
-
const shake =
|
|
204
|
-
const clear =
|
|
205
|
-
const check =
|
|
200
|
+
const [float] = useState(() => new Animated.Value(floating ? 1 : 0)); // native: label + affixes
|
|
201
|
+
const [glow] = useState(() => new Animated.Value(0)); // native: halo + indicator bar
|
|
202
|
+
const [focus] = useState(() => new Animated.Value(0)); // JS: border / label colour
|
|
203
|
+
const [shake] = useState(() => new Animated.Value(0)); // native
|
|
204
|
+
const [clear] = useState(() => new Animated.Value(clearable && text ? 1 : 0)); // native
|
|
205
|
+
const [check] = useState(() => new Animated.Value(ok ? 1 : 0)); // native
|
|
206
206
|
|
|
207
207
|
useEffect(() => {
|
|
208
208
|
if (reduce) float.setValue(floating ? 1 : 0);
|
|
@@ -400,7 +400,7 @@ export const FloatingInput = forwardRef<ComponentRef<typeof TextInput>, Floating
|
|
|
400
400
|
<Pressable
|
|
401
401
|
hitSlop={(44 - S.icon) / 2}
|
|
402
402
|
accessibilityRole="button"
|
|
403
|
-
accessibilityLabel={
|
|
403
|
+
accessibilityLabel={labels.clearField(label)}
|
|
404
404
|
onPress={() => {
|
|
405
405
|
setText('');
|
|
406
406
|
inputRef.current?.focus();
|
|
@@ -493,7 +493,7 @@ function FieldMessage({
|
|
|
493
493
|
reduce: boolean;
|
|
494
494
|
}) {
|
|
495
495
|
const { font } = useKit();
|
|
496
|
-
const enter =
|
|
496
|
+
const [enter] = useState(() => new Animated.Value(tone === 'helper' ? 1 : 0)); // native
|
|
497
497
|
useEffect(() => {
|
|
498
498
|
if (tone === 'helper') return;
|
|
499
499
|
if (reduce) Animated.timing(enter, { toValue: 1, duration: 150, useNativeDriver: true }).start();
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import React, { forwardRef, useEffect, useMemo,
|
|
1
|
+
import React, { forwardRef, useEffect, useMemo, useState, type ComponentRef } from 'react';
|
|
2
2
|
import { AccessibilityInfo, Animated, Pressable, StyleSheet, Text, View, type TextInput } from 'react-native';
|
|
3
3
|
import Svg, { Circle, Path } from 'react-native-svg';
|
|
4
4
|
|
|
@@ -21,24 +21,23 @@ export const DEFAULT_PASSWORD_REQUIREMENTS: PasswordRequirement[] = [
|
|
|
21
21
|
|
|
22
22
|
export interface PasswordInputProps extends Omit<FloatingInputProps, 'secureTextEntry' | 'right'> {
|
|
23
23
|
/** Show the 4-segment strength meter under the field. */
|
|
24
|
-
strength?: boolean;
|
|
24
|
+
strength?: boolean | undefined;
|
|
25
25
|
/** Replace the built-in scorer (return 0–4). */
|
|
26
|
-
score?: (password: string) => number;
|
|
26
|
+
score?: ((password: string) => number) | undefined;
|
|
27
27
|
/** Checklist under the field; each row ticks itself off when met. `true` uses DEFAULT_PASSWORD_REQUIREMENTS. */
|
|
28
|
-
requirements?: PasswordRequirement[] | boolean;
|
|
28
|
+
requirements?: PasswordRequirement[] | boolean | undefined;
|
|
29
29
|
/** Makes this a "confirm password" field: shows a match / mismatch message once the user types. */
|
|
30
|
-
confirmOf?: string;
|
|
30
|
+
confirmOf?: string | undefined;
|
|
31
31
|
/** Message when `confirmOf` matches (default 'Passwords match'). */
|
|
32
|
-
matchMessage?: string;
|
|
32
|
+
matchMessage?: string | undefined;
|
|
33
33
|
/** Message when `confirmOf` doesn't match (default "Passwords don't match"). */
|
|
34
|
-
mismatchMessage?: string;
|
|
34
|
+
mismatchMessage?: string | undefined;
|
|
35
35
|
}
|
|
36
36
|
|
|
37
37
|
// Controls stop growing at iOS's largest standard text size (xxxL ≈ 1.35×) so they keep their shape;
|
|
38
38
|
// content text scales all the way.
|
|
39
39
|
const FONT_CAP = 1.35;
|
|
40
40
|
|
|
41
|
-
const LEVEL_LABELS = ['Too short', 'Weak', 'Okay', 'Strong', 'Very strong'];
|
|
42
41
|
const ICON = { sm: 18, md: 22, lg: 24 };
|
|
43
42
|
|
|
44
43
|
export function scorePassword(pw: string) {
|
|
@@ -60,8 +59,8 @@ export const PasswordInput = forwardRef<ComponentRef<typeof TextInput>, Password
|
|
|
60
59
|
score = scorePassword,
|
|
61
60
|
requirements,
|
|
62
61
|
confirmOf,
|
|
63
|
-
matchMessage
|
|
64
|
-
mismatchMessage
|
|
62
|
+
matchMessage: matchMessageProp,
|
|
63
|
+
mismatchMessage: mismatchMessageProp,
|
|
65
64
|
value,
|
|
66
65
|
defaultValue,
|
|
67
66
|
onChangeText,
|
|
@@ -73,7 +72,9 @@ export const PasswordInput = forwardRef<ComponentRef<typeof TextInput>, Password
|
|
|
73
72
|
},
|
|
74
73
|
ref
|
|
75
74
|
) {
|
|
76
|
-
const { colors } = useKit();
|
|
75
|
+
const { colors, labels } = useKit();
|
|
76
|
+
const matchMessage = matchMessageProp ?? labels.passwordsMatch;
|
|
77
|
+
const mismatchMessage = mismatchMessageProp ?? labels.passwordsDontMatch;
|
|
77
78
|
const reduce = useReduceMotion();
|
|
78
79
|
const [hidden, setHidden] = useState(true);
|
|
79
80
|
const [inner, setInner] = useState(defaultValue ?? '');
|
|
@@ -87,13 +88,15 @@ export const PasswordInput = forwardRef<ComponentRef<typeof TextInput>, Password
|
|
|
87
88
|
const mismatch =
|
|
88
89
|
confirming && text.length > 0 && !matches && (text.length >= confirmOf.length || !confirmOf.startsWith(text));
|
|
89
90
|
|
|
90
|
-
const eye =
|
|
91
|
+
const [eye] = useState(() => new Animated.Value(hidden ? 0 : 1)); // native: 1 = visible
|
|
91
92
|
useEffect(() => {
|
|
92
93
|
if (reduce) Animated.timing(eye, { toValue: hidden ? 0 : 1, duration: 150, useNativeDriver: true }).start();
|
|
93
94
|
else Animated.spring(eye, { toValue: hidden ? 0 : 1, useNativeDriver: true, ...motion.snappy }).start();
|
|
94
95
|
}, [hidden, eye, reduce]);
|
|
95
96
|
|
|
96
97
|
const iconColor = iconColorProp ?? colors.mutedForeground;
|
|
98
|
+
const errorText = error ?? (mismatch ? mismatchMessage : undefined);
|
|
99
|
+
const successValue = success ?? (matches ? matchMessage : undefined);
|
|
97
100
|
const iconSize = ICON[size];
|
|
98
101
|
const fade = (on: 0 | 1) => ({
|
|
99
102
|
opacity: eye.interpolate({ inputRange: [0, 1], outputRange: on ? [0, 1] : [1, 0], extrapolate: 'clamp' }),
|
|
@@ -112,14 +115,15 @@ export const PasswordInput = forwardRef<ComponentRef<typeof TextInput>, Password
|
|
|
112
115
|
ref={ref}
|
|
113
116
|
{...props}
|
|
114
117
|
size={size}
|
|
115
|
-
|
|
118
|
+
// FloatingInput's optional props don't accept an explicit undefined (exactOptionalPropertyTypes).
|
|
119
|
+
{...(iconColorProp !== undefined ? { iconColor: iconColorProp } : null)}
|
|
116
120
|
value={text}
|
|
117
121
|
onChangeText={(next) => {
|
|
118
122
|
if (value === undefined) setInner(next);
|
|
119
123
|
onChangeText?.(next);
|
|
120
124
|
}}
|
|
121
|
-
|
|
122
|
-
|
|
125
|
+
{...(errorText !== undefined ? { error: errorText } : null)}
|
|
126
|
+
{...(successValue !== undefined ? { success: successValue } : null)}
|
|
123
127
|
secureTextEntry={hidden}
|
|
124
128
|
autoCapitalize="none"
|
|
125
129
|
autoCorrect={false}
|
|
@@ -128,7 +132,7 @@ export const PasswordInput = forwardRef<ComponentRef<typeof TextInput>, Password
|
|
|
128
132
|
hitSlop={(44 - iconSize) / 2}
|
|
129
133
|
onPress={() => setHidden((h) => !h)}
|
|
130
134
|
accessibilityRole="button"
|
|
131
|
-
accessibilityLabel={hidden ?
|
|
135
|
+
accessibilityLabel={hidden ? labels.showPassword : labels.hidePassword}
|
|
132
136
|
accessibilityState={{ checked: !hidden }}
|
|
133
137
|
style={{ width: iconSize, height: iconSize }}
|
|
134
138
|
>
|
|
@@ -161,11 +165,11 @@ const EYE_OFF =
|
|
|
161
165
|
|
|
162
166
|
/** Four segments that spring-fill left to right; the colour slides with the score. */
|
|
163
167
|
function Meter({ level, reduce }: { level: number; reduce: boolean }) {
|
|
164
|
-
const { colors, dark, font } = useKit();
|
|
168
|
+
const { colors, dark, font, labels } = useKit();
|
|
165
169
|
const palette = [colors.mutedForeground, colors.danger, colors.warning, colors.success, colors.success];
|
|
166
|
-
const fills =
|
|
167
|
-
const tone =
|
|
168
|
-
const enter =
|
|
170
|
+
const [fills] = useState(() => [0, 1, 2, 3].map(() => new Animated.Value(0))); // native: scaleX
|
|
171
|
+
const [tone] = useState(() => new Animated.Value(level)); // JS: colour
|
|
172
|
+
const [enter] = useState(() => new Animated.Value(0)); // native
|
|
169
173
|
|
|
170
174
|
useEffect(() => {
|
|
171
175
|
if (reduce) enter.setValue(1);
|
|
@@ -200,7 +204,7 @@ function Meter({ level, reduce }: { level: number; reduce: boolean }) {
|
|
|
200
204
|
},
|
|
201
205
|
]}
|
|
202
206
|
accessible
|
|
203
|
-
accessibilityLabel={
|
|
207
|
+
accessibilityLabel={labels.passwordStrength(labels.passwordLevels[level] ?? '')}
|
|
204
208
|
>
|
|
205
209
|
<View style={styles.bars}>
|
|
206
210
|
{fills.map((a, i) => (
|
|
@@ -216,7 +220,7 @@ function Meter({ level, reduce }: { level: number; reduce: boolean }) {
|
|
|
216
220
|
</View>
|
|
217
221
|
))}
|
|
218
222
|
</View>
|
|
219
|
-
<Text maxFontSizeMultiplier={FONT_CAP} style={[styles.level, font.family ? { fontFamily: font.family } : null, { color: palette[level] }]}>{
|
|
223
|
+
<Text maxFontSizeMultiplier={FONT_CAP} style={[styles.level, font.family ? { fontFamily: font.family } : null, { color: palette[level] }]}>{labels.passwordLevels[level]}</Text>
|
|
220
224
|
</Animated.View>
|
|
221
225
|
);
|
|
222
226
|
}
|
|
@@ -232,8 +236,8 @@ function Checklist({ rules, value, reduce }: { rules: PasswordRequirement[]; val
|
|
|
232
236
|
}
|
|
233
237
|
|
|
234
238
|
function Requirement({ label, met, reduce }: { label: string; met: boolean; reduce: boolean }) {
|
|
235
|
-
const { colors, dark, font } = useKit();
|
|
236
|
-
const tick =
|
|
239
|
+
const { colors, dark, font, labels } = useKit();
|
|
240
|
+
const [tick] = useState(() => new Animated.Value(met ? 1 : 0)); // native
|
|
237
241
|
useEffect(() => {
|
|
238
242
|
if (reduce) Animated.timing(tick, { toValue: met ? 1 : 0, duration: 150, useNativeDriver: true }).start();
|
|
239
243
|
else Animated.spring(tick, { toValue: met ? 1 : 0, useNativeDriver: true, ...motion.bouncy }).start();
|
|
@@ -243,7 +247,7 @@ function Requirement({ label, met, reduce }: { label: string; met: boolean; redu
|
|
|
243
247
|
<View
|
|
244
248
|
style={styles.rule}
|
|
245
249
|
accessible
|
|
246
|
-
accessibilityLabel={
|
|
250
|
+
accessibilityLabel={met ? labels.ruleMet(label) : labels.ruleUnmet(label)}
|
|
247
251
|
accessibilityState={{ checked: met }}
|
|
248
252
|
>
|
|
249
253
|
<View style={styles.ruleIcon}>
|