@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
- 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 ${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) => {
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
- }, accessibilityLabel: words.codeLabel, "aria-invalid": error !== null, inputMode: "numeric", autoComplete: "one-time-code", textContentType: "oneTimeCode", caretHidden: true, className: "absolute inset-0 rounded-control text-transparent" })] }), error ? (_jsx(Text, { 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: () => {
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
  }
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.119",
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",