@entropy-softworks/ui 2026.9.2 → 2026.9.4
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.
|
@@ -19,11 +19,17 @@ import React from "react";
|
|
|
19
19
|
* takes width the window knows nothing about — sizing off the window overflowed
|
|
20
20
|
* the card it sat in.
|
|
21
21
|
*
|
|
22
|
-
* #
|
|
22
|
+
* # How the keys read
|
|
23
23
|
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
24
|
+
* A hairline ring at rest and nothing else: no fill, mono digits, the same
|
|
25
|
+
* quiet treatment the rest of the product uses. The ring is what makes a target
|
|
26
|
+
* a target — an earlier pass filled the keys as well, and that was too heavy
|
|
27
|
+
* beside everything around it.
|
|
28
|
+
*
|
|
29
|
+
* The press is where the weight goes instead: the ring brightens, a fill fades
|
|
30
|
+
* in under it, and the key dips in scale. Three layered responses because the
|
|
31
|
+
* resting state is deliberately understated, and "did that register?" is the
|
|
32
|
+
* entire question somebody entering a PIN is asking.
|
|
27
33
|
*/
|
|
28
34
|
export interface PinPadProps {
|
|
29
35
|
length?: number;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pin-pad.d.ts","sourceRoot":"","sources":["../../src/components/pin-pad.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAmD,MAAM,OAAO,CAAC;AAOxE
|
|
1
|
+
{"version":3,"file":"pin-pad.d.ts","sourceRoot":"","sources":["../../src/components/pin-pad.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAmD,MAAM,OAAO,CAAC;AAOxE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,MAAM,WAAW,WAAW;IAC1B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IAClC,QAAQ,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IACjC,yEAAyE;IACzE,WAAW,CAAC,EAAE,MAAM,IAAI,CAAC;IACzB,wCAAwC;IACxC,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAC3B,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB;;;;OAIG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAWD,wBAAgB,MAAM,CAAC,EACrB,MAAU,EACV,UAAU,EACV,QAAQ,EACR,WAAW,EACX,QAAQ,EACR,KAAK,EACL,OAAc,GACf,EAAE,WAAW,qBA2Jb;AA4DD,eAAe,MAAM,CAAC"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import React, { useCallback, useEffect, useRef, useState } from "react";
|
|
2
|
-
import { Platform, Pressable, Text, View } from "react-native";
|
|
2
|
+
import { Platform, Pressable, StyleSheet, Text, View } from "react-native";
|
|
3
3
|
import Animated, { useAnimatedStyle, useSharedValue, withTiming } from "react-native-reanimated";
|
|
4
4
|
import * as Haptics from "expo-haptics";
|
|
5
5
|
import { useColorScheme } from "nativewind";
|
|
@@ -29,7 +29,10 @@ export function PinPad({ length = 6, onComplete, onChange, onBiometric, resetKey
|
|
|
29
29
|
const width = available || ASSUMED_WIDTH;
|
|
30
30
|
const keySize = Math.max(MIN_KEY, Math.min(MAX_KEY, Math.floor((width - 2 * GAP) / 3)));
|
|
31
31
|
const padWidth = keySize * 3 + GAP * 2;
|
|
32
|
-
|
|
32
|
+
// Dots at 0.22 of a key rather than 0.17. They are the only readout of how
|
|
33
|
+
// much of the PIN has landed, and at the smaller ratio they were a row of
|
|
34
|
+
// specks beneath a keypad that dwarfed them.
|
|
35
|
+
const dotSize = Math.round(keySize * 0.22);
|
|
33
36
|
const [pin, setPin] = useState("");
|
|
34
37
|
// Source of truth for the latest digits — lets callbacks fire OUTSIDE the
|
|
35
38
|
// setPin updater (calling a parent setState inside an updater triggers
|
|
@@ -130,20 +133,25 @@ export function PinPad({ length = 6, onComplete, onChange, onBiometric, resetKey
|
|
|
130
133
|
</View>);
|
|
131
134
|
}
|
|
132
135
|
function Key({ label, icon, size, onPress, accessibilityLabel, }) {
|
|
133
|
-
//
|
|
134
|
-
//
|
|
135
|
-
//
|
|
136
|
+
// The resting key is a ring and a digit, so the press has to carry all the
|
|
137
|
+
// feedback: scale dips, and the fill fades up from nothing underneath. Driven
|
|
138
|
+
// from one shared value so the two cannot fall out of step.
|
|
136
139
|
const pressed = useSharedValue(0);
|
|
137
140
|
const pressStyle = useAnimatedStyle(() => ({
|
|
138
141
|
transform: [{ scale: 1 - pressed.value * 0.08 }],
|
|
139
142
|
}));
|
|
143
|
+
const fillStyle = useAnimatedStyle(() => ({ opacity: pressed.value }));
|
|
140
144
|
return (<Animated.View style={pressStyle}>
|
|
141
145
|
<Pressable onPress={onPress} onPressIn={() => {
|
|
142
146
|
pressed.value = withTiming(1, { duration: 60 });
|
|
143
147
|
}} onPressOut={() => {
|
|
144
148
|
pressed.value = withTiming(0, { duration: 160 });
|
|
145
|
-
}} style={{ width: size, height: size, borderRadius: size / 2 }} className="items-center justify-center border border-border
|
|
146
|
-
{
|
|
149
|
+
}} style={{ width: size, height: size, borderRadius: size / 2 }} className="items-center justify-center overflow-hidden border border-border dark:border-neutral-700" accessibilityRole="button" accessibilityLabel={accessibilityLabel ?? label ?? "key"}>
|
|
150
|
+
{/* The pressed fill, behind the digit. A sibling with animated opacity
|
|
151
|
+
rather than an animated backgroundColor: colour has to come from the
|
|
152
|
+
theme's classes, and those cannot be interpolated. */}
|
|
153
|
+
<Animated.View pointerEvents="none" style={[fillStyle, StyleSheet.absoluteFillObject]} className="bg-secondary dark:bg-neutral-800"/>
|
|
154
|
+
{icon ?? (<Text className="font-mono text-foreground dark:text-white" style={{ fontSize: Math.round(size * 0.36) }}>
|
|
147
155
|
{label}
|
|
148
156
|
</Text>)}
|
|
149
157
|
</Pressable>
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pin-pad.jsx","sourceRoot":"","sources":["../../src/components/pin-pad.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AACxE,OAAO,EAA0B,QAAQ,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"pin-pad.jsx","sourceRoot":"","sources":["../../src/components/pin-pad.tsx"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import React, { useCallback, useEffect, useRef, useState } from "react";
|
|
2
|
-
import { type LayoutChangeEvent, Platform, Pressable, Text, View } from "react-native";
|
|
2
|
+
import { type LayoutChangeEvent, Platform, Pressable, StyleSheet, Text, View } from "react-native";
|
|
3
3
|
import Animated, { useAnimatedStyle, useSharedValue, withTiming } from "react-native-reanimated";
|
|
4
4
|
import * as Haptics from "expo-haptics";
|
|
5
5
|
import { useColorScheme } from "nativewind";
|
|
@@ -25,11 +25,17 @@ import { Delete, Fingerprint } from "lucide-react-native";
|
|
|
25
25
|
* takes width the window knows nothing about — sizing off the window overflowed
|
|
26
26
|
* the card it sat in.
|
|
27
27
|
*
|
|
28
|
-
* #
|
|
28
|
+
* # How the keys read
|
|
29
29
|
*
|
|
30
|
-
*
|
|
31
|
-
*
|
|
32
|
-
*
|
|
30
|
+
* A hairline ring at rest and nothing else: no fill, mono digits, the same
|
|
31
|
+
* quiet treatment the rest of the product uses. The ring is what makes a target
|
|
32
|
+
* a target — an earlier pass filled the keys as well, and that was too heavy
|
|
33
|
+
* beside everything around it.
|
|
34
|
+
*
|
|
35
|
+
* The press is where the weight goes instead: the ring brightens, a fill fades
|
|
36
|
+
* in under it, and the key dips in scale. Three layered responses because the
|
|
37
|
+
* resting state is deliberately understated, and "did that register?" is the
|
|
38
|
+
* entire question somebody entering a PIN is asking.
|
|
33
39
|
*/
|
|
34
40
|
export interface PinPadProps {
|
|
35
41
|
length?: number;
|
|
@@ -84,7 +90,10 @@ export function PinPad({
|
|
|
84
90
|
const width = available || ASSUMED_WIDTH;
|
|
85
91
|
const keySize = Math.max(MIN_KEY, Math.min(MAX_KEY, Math.floor((width - 2 * GAP) / 3)));
|
|
86
92
|
const padWidth = keySize * 3 + GAP * 2;
|
|
87
|
-
|
|
93
|
+
// Dots at 0.22 of a key rather than 0.17. They are the only readout of how
|
|
94
|
+
// much of the PIN has landed, and at the smaller ratio they were a row of
|
|
95
|
+
// specks beneath a keypad that dwarfed them.
|
|
96
|
+
const dotSize = Math.round(keySize * 0.22);
|
|
88
97
|
|
|
89
98
|
const [pin, setPin] = useState("");
|
|
90
99
|
// Source of truth for the latest digits — lets callbacks fire OUTSIDE the
|
|
@@ -232,13 +241,14 @@ function Key({
|
|
|
232
241
|
onPress: () => void;
|
|
233
242
|
accessibilityLabel?: string;
|
|
234
243
|
}) {
|
|
235
|
-
//
|
|
236
|
-
//
|
|
237
|
-
//
|
|
244
|
+
// The resting key is a ring and a digit, so the press has to carry all the
|
|
245
|
+
// feedback: scale dips, and the fill fades up from nothing underneath. Driven
|
|
246
|
+
// from one shared value so the two cannot fall out of step.
|
|
238
247
|
const pressed = useSharedValue(0);
|
|
239
248
|
const pressStyle = useAnimatedStyle(() => ({
|
|
240
249
|
transform: [{ scale: 1 - pressed.value * 0.08 }],
|
|
241
250
|
}));
|
|
251
|
+
const fillStyle = useAnimatedStyle(() => ({ opacity: pressed.value }));
|
|
242
252
|
|
|
243
253
|
return (
|
|
244
254
|
<Animated.View style={pressStyle}>
|
|
@@ -251,14 +261,22 @@ function Key({
|
|
|
251
261
|
pressed.value = withTiming(0, { duration: 160 });
|
|
252
262
|
}}
|
|
253
263
|
style={{ width: size, height: size, borderRadius: size / 2 }}
|
|
254
|
-
className="items-center justify-center border border-border
|
|
264
|
+
className="items-center justify-center overflow-hidden border border-border dark:border-neutral-700"
|
|
255
265
|
accessibilityRole="button"
|
|
256
266
|
accessibilityLabel={accessibilityLabel ?? label ?? "key"}
|
|
257
267
|
>
|
|
268
|
+
{/* The pressed fill, behind the digit. A sibling with animated opacity
|
|
269
|
+
rather than an animated backgroundColor: colour has to come from the
|
|
270
|
+
theme's classes, and those cannot be interpolated. */}
|
|
271
|
+
<Animated.View
|
|
272
|
+
pointerEvents="none"
|
|
273
|
+
style={[fillStyle, StyleSheet.absoluteFillObject]}
|
|
274
|
+
className="bg-secondary dark:bg-neutral-800"
|
|
275
|
+
/>
|
|
258
276
|
{icon ?? (
|
|
259
277
|
<Text
|
|
260
|
-
className="font-
|
|
261
|
-
style={{ fontSize: Math.round(size * 0.
|
|
278
|
+
className="font-mono text-foreground dark:text-white"
|
|
279
|
+
style={{ fontSize: Math.round(size * 0.36) }}
|
|
262
280
|
>
|
|
263
281
|
{label}
|
|
264
282
|
</Text>
|