@joinskips/brand 5.0.0-develop.118 → 5.0.0-develop.119

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.
@@ -62,6 +62,9 @@ export declare function CodeStep({ words, length, noMatch, ranOut, resendAfterMs
62
62
  onResend: () => void;
63
63
  onChangeEmail: () => void;
64
64
  }): import("react").JSX.Element;
65
+ export declare const DOT_REST_OPACITY = 0.35;
66
+ export declare const DOT_RISE = 3;
67
+ export declare const DOT_STILL_OPACITY = 0.6;
65
68
  /** Skip writing a reply: three dots rising in turn in Skip's bubble beside Skip's mark, announced as a status. */
66
69
  export declare function SkipTyping({ label, skipMark }: {
67
70
  label: string;
@@ -1,6 +1,6 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
2
  import { useEffect, useRef, useState } from 'react';
3
- import { ActivityIndicator, Animated, Image, Pressable, Text, TextInput, View } from 'react-native';
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";
6
6
  import { useColor } from "./parts.js";
@@ -74,17 +74,38 @@ export function CodeStep({ words, length, noMatch, ranOut, resendAfterMs = RESEN
74
74
  setCode(digits);
75
75
  if (completesCode(digits, code, length))
76
76
  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, onPress: () => {
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: () => {
78
78
  onSubmit(code);
79
79
  } })] })] }));
80
80
  }
81
81
  const DOTS = [0, 1, 2];
82
82
  const DOT_SIZE = 6;
83
+ // A dot at rest is faint, rises this far at the top of its turn, and holds at the still strength for a visitor who
84
+ // asks for less motion.
85
+ export const DOT_REST_OPACITY = 0.35;
86
+ export const DOT_RISE = 3;
87
+ export const DOT_STILL_OPACITY = 0.6;
88
+ // Null until the device has answered, so the dots never start before a visitor who wants them still is known.
89
+ function useReducedMotion() {
90
+ const [reduced, setReduced] = useState(null);
91
+ useEffect(() => {
92
+ void AccessibilityInfo.isReduceMotionEnabled().then(setReduced);
93
+ const change = AccessibilityInfo.addEventListener('reduceMotionChanged', setReduced);
94
+ return () => {
95
+ change.remove();
96
+ };
97
+ }, []);
98
+ return reduced;
99
+ }
83
100
  /** Skip writing a reply: three dots rising in turn in Skip's bubble beside Skip's mark, announced as a status. */
84
101
  export function SkipTyping({ label, skipMark }) {
85
102
  const dotColor = useColor('ink-secondary');
103
+ const reduced = useReducedMotion();
104
+ const still = reduced === true;
86
105
  const rise = useRef(DOTS.map(() => new Animated.Value(0))).current;
87
106
  useEffect(() => {
107
+ if (reduced !== false)
108
+ return undefined;
88
109
  const step = DOT_CYCLE_MS / (2 * DOTS.length);
89
110
  const loop = Animated.loop(Animated.stagger(step, rise.map((value) => Animated.sequence([
90
111
  Animated.timing(value, { toValue: 1, duration: step, useNativeDriver: true }),
@@ -94,12 +115,17 @@ export function SkipTyping({ label, skipMark }) {
94
115
  return () => {
95
116
  loop.stop();
96
117
  };
97
- }, [rise]);
118
+ }, [rise, reduced]);
98
119
  return (_jsxs(View, { className: "mt-3 flex-row items-end gap-2", children: [_jsx(Image, { source: skipMark, "aria-hidden": true, style: { width: 32, height: 32 }, className: "rounded-control" }), _jsx(View, { role: "status", accessibilityLabel: label, className: "flex-row items-center gap-1 rounded-[20px] rounded-bl-[7px] border border-line-subtle bg-surface px-4 py-4", children: rise.map((value, dot) => (_jsx(Animated.View, { style: {
99
120
  width: DOT_SIZE,
100
121
  height: DOT_SIZE,
101
122
  borderRadius: DOT_SIZE / 2,
102
123
  backgroundColor: dotColor,
103
- transform: [{ translateY: value.interpolate({ inputRange: [0, 1], outputRange: [0, -DOT_SIZE] }) }],
124
+ ...(still
125
+ ? { opacity: DOT_STILL_OPACITY }
126
+ : {
127
+ opacity: value.interpolate({ inputRange: [0, 1], outputRange: [DOT_REST_OPACITY, 1] }),
128
+ transform: [{ translateY: value.interpolate({ inputRange: [0, 1], outputRange: [0, -DOT_RISE] }) }],
129
+ }),
104
130
  } }, DOTS[dot]))) })] }));
105
131
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@joinskips/brand",
3
- "version": "5.0.0-develop.118",
3
+ "version": "5.0.0-develop.119",
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",
@@ -20,10 +20,10 @@
20
20
  "validator": "^13.15.35"
21
21
  },
22
22
  "peerDependencies": {
23
- "react": "^19.3.0",
23
+ "react": "^19.0.0",
24
24
  "react-native": ">=0.81.0",
25
- "react-native-web": "~0.21.4",
26
- "tailwindcss": "^4.3.3",
25
+ "react-native-web": "~0.21.0",
26
+ "tailwindcss": "^4.0.0",
27
27
  "uniwind": "1.13.2"
28
28
  },
29
29
  "peerDependenciesMeta": {