@joinskips/brand 5.0.0-develop.119 → 5.0.0-develop.121
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.
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
-
import { useEffect, useRef, useState } from 'react';
|
|
2
|
+
import { useEffect, useId, useRef, useState } from 'react';
|
|
3
3
|
import { AccessibilityInfo, ActivityIndicator, Animated, Image, Pressable, Text, TextInput, View } from 'react-native';
|
|
4
4
|
import { DOT_CYCLE_MS } from "../skipTyping.js";
|
|
5
5
|
import { codeDigits, completesCode, EMAIL_MAX_LENGTH, givenEmail, givenName, NAME_MAX_LENGTH, RESEND_AFTER_MS, resendClock, } from "../welcome.js";
|
|
@@ -23,10 +23,16 @@ export function Choices({ items, question, sending, holding = false, failed, wor
|
|
|
23
23
|
onChoose(item);
|
|
24
24
|
} }, item.value))) }), failed ? (_jsx(Text, { role: "alert", className: "font-ui text-sm text-error-ink", children: words.choiceNotSent })) : null] }));
|
|
25
25
|
}
|
|
26
|
+
// The error under a field, as the field's description. React Native's types leave aria-describedby out, and
|
|
27
|
+
// react-native-web reads it.
|
|
28
|
+
function describedBy(errorId) {
|
|
29
|
+
return errorId === undefined ? {} : { 'aria-describedby': errorId };
|
|
30
|
+
}
|
|
26
31
|
// One thing asked of a new visitor: a field in focus and its button. What is typed is checked here and handed on.
|
|
27
32
|
function StepField({ label, error, submitLabel, input, usable, onSubmit, initial = '', aside }) {
|
|
28
33
|
const [typed, setTyped] = useState(initial);
|
|
29
34
|
const [refused, setRefused] = useState(false);
|
|
35
|
+
const errorId = useId();
|
|
30
36
|
const placeholder = useColor('ink-placeholder');
|
|
31
37
|
const submit = () => {
|
|
32
38
|
const value = usable(typed);
|
|
@@ -34,7 +40,7 @@ function StepField({ label, error, submitLabel, input, usable, onSubmit, initial
|
|
|
34
40
|
if (value !== null)
|
|
35
41
|
onSubmit(value);
|
|
36
42
|
};
|
|
37
|
-
return (_jsxs(View, { className: "w-full max-w-[360px] gap-2 self-center", children: [aside ? (_jsx(View, { className: "self-center", children: _jsx(Pill, { label: aside.label, look: "flat", onPress: aside.onPress }) })) : null, _jsx(Text, { className: "font-ui text-sm font-medium text-ink", children: label }), _jsx(TextInput, { autoFocus: true, value: typed, onChangeText: setTyped, onSubmitEditing: submit, accessibilityLabel: label, "aria-invalid": refused, placeholderTextColor: placeholder, className: `h-control rounded-control border bg-surface px-3 font-ui text-md text-ink ${refused ? 'border-error-ink' : 'border-line-control'}`, ...input }), refused ? (_jsx(Text, { role: "alert", className: "font-ui text-sm text-error-ink", children: error })) : null, _jsx(View, { className: "self-center", children: _jsx(Pill, { label: submitLabel, onPress: submit }) })] }));
|
|
43
|
+
return (_jsxs(View, { className: "w-full max-w-[360px] gap-2 self-center", children: [aside ? (_jsx(View, { className: "self-center", children: _jsx(Pill, { label: aside.label, look: "flat", onPress: aside.onPress }) })) : null, _jsx(Text, { className: "font-ui text-sm font-medium text-ink", children: label }), _jsx(TextInput, { autoFocus: true, value: typed, onChangeText: setTyped, onSubmitEditing: submit, accessibilityLabel: label, "aria-invalid": refused, ...describedBy(refused ? errorId : undefined), placeholderTextColor: placeholder, className: `h-control rounded-control border bg-surface px-3 font-ui text-md text-ink ${refused ? 'border-error-ink' : 'border-line-control'}`, ...input }), refused ? (_jsx(Text, { nativeID: errorId, role: "alert", className: "font-ui text-sm text-error-ink", children: error })) : null, _jsx(View, { className: "self-center", children: _jsx(Pill, { label: submitLabel, onPress: submit }) })] }));
|
|
38
44
|
}
|
|
39
45
|
/** The email asked for after Continue here, and again for a visitor changing it. */
|
|
40
46
|
export function EmailStep({ words, onSubmit, initial, }) {
|
|
@@ -68,13 +74,24 @@ function NewCode({ waitMs, words, onResend }) {
|
|
|
68
74
|
*/
|
|
69
75
|
export function CodeStep({ words, length, noMatch, ranOut, resendAfterMs = RESEND_AFTER_MS, onSubmit, onResend, onChangeEmail, }) {
|
|
70
76
|
const [code, setCode] = useState('');
|
|
77
|
+
const [focused, setFocused] = useState(false);
|
|
78
|
+
const errorId = useId();
|
|
71
79
|
const error = ranOut ? words.codeRanOut : noMatch ? words.codeNoMatch : null;
|
|
72
|
-
|
|
80
|
+
// The box the next digit goes in, or the last once the code is whole.
|
|
81
|
+
const nextBox = Math.min(code.length, length - 1);
|
|
82
|
+
return (_jsxs(View, { className: "w-full max-w-[360px] items-center gap-3 self-center", children: [_jsx(Text, { className: "font-ui text-sm font-medium text-ink", children: words.codeLabel }), _jsxs(View, { className: "relative", children: [_jsx(View, { "aria-hidden": true, className: "flex-row gap-2", children: Array.from({ length }, (_, box) => (_jsx(View, { className: `h-control w-11 items-center justify-center rounded-control border ${focused && box === nextBox ? 'border-focus' : error ? 'border-error-ink' : 'border-line-control'}`, children: _jsx(Text, { className: "font-ui text-xl font-medium text-ink", children: code[box] ?? '' }) }, box))) }), _jsx(TextInput, { autoFocus: true, value: code, onChangeText: (typed) => {
|
|
73
83
|
const digits = codeDigits(typed, length);
|
|
74
84
|
setCode(digits);
|
|
75
85
|
if (completesCode(digits, code, length))
|
|
76
86
|
onSubmit(digits);
|
|
77
|
-
},
|
|
87
|
+
}, onFocus: () => {
|
|
88
|
+
setFocused(true);
|
|
89
|
+
}, onBlur: () => {
|
|
90
|
+
setFocused(false);
|
|
91
|
+
}, accessibilityLabel: words.codeLabel, "aria-invalid": error !== null, ...describedBy(error === null ? undefined : errorId), inputMode: "numeric", autoComplete: "one-time-code", textContentType: "oneTimeCode", caretHidden: true,
|
|
92
|
+
// Unseen, not just clear: the boxes draw the digits and the focus, and a checker would read clear text as
|
|
93
|
+
// text with no contrast.
|
|
94
|
+
className: "absolute inset-0 opacity-0" })] }), error ? (_jsx(Text, { nativeID: errorId, role: "alert", className: "text-center font-ui text-sm text-error-ink", children: error })) : null, _jsxs(View, { className: "flex-row flex-wrap items-center justify-center gap-2", children: [_jsx(Pill, { label: words.changeEmail, look: "flat", onPress: onChangeEmail }), _jsx(NewCode, { waitMs: resendAfterMs, words: words, onResend: onResend }), _jsx(Pill, { label: words.codeSubmit, disabled: code.length < length, onPress: () => {
|
|
78
95
|
onSubmit(code);
|
|
79
96
|
} })] })] }));
|
|
80
97
|
}
|
|
Binary file
|
package/manifest.json
CHANGED
|
@@ -409,6 +409,10 @@
|
|
|
409
409
|
"sha256": "6606d135bbbd06103bacef4cb89bf4019e53e092dcd19b51278edcbab1786b9d",
|
|
410
410
|
"bytes": 130031
|
|
411
411
|
},
|
|
412
|
+
"logos/png-2048/skips-wordmark-dark-2048.png": {
|
|
413
|
+
"sha256": "286ed3c2b3d37b8559ab773a692eca07d04d843ae093820c94ce5bdadff78713",
|
|
414
|
+
"bytes": 46330
|
|
415
|
+
},
|
|
412
416
|
"logos/png-2048/skips-wordmark-light-2048.png": {
|
|
413
417
|
"sha256": "61da312bae3aec7dddef398494fa98d13de940c81b3ecdb038c6904d26d85506",
|
|
414
418
|
"bytes": 59707
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@joinskips/brand",
|
|
3
|
-
"version": "5.0.0-develop.
|
|
3
|
+
"version": "5.0.0-develop.121",
|
|
4
4
|
"description": "Skips design tokens, Onest, logos, favicons, interface icons, member pictures and app icons.",
|
|
5
5
|
"license": "UNLICENSED",
|
|
6
6
|
"homepage": "https://brand.joinskips.com",
|