@ecohouse/ui 0.1.62 → 0.1.64
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/dist/index.cjs +21 -8
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +21 -8
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/components/Avatar/Avatar.tsx +18 -7
- package/src/components/DatePicker/DatePicker.stories.tsx +12 -0
- package/src/components/DatePicker/DatePicker.tsx +7 -6
- package/src/components/VerificationCodeInput/VerificationCodeInput.test.ts +14 -0
- package/src/components/VerificationCodeInput/VerificationCodeInput.utils.ts +6 -1
package/package.json
CHANGED
|
@@ -87,6 +87,17 @@ const triggerWebBlurStyle: ViewStyle =
|
|
|
87
87
|
} as ViewStyle)
|
|
88
88
|
: {};
|
|
89
89
|
|
|
90
|
+
// Fades the light/dark switch (e.g. a header changing variant on scroll) instead of snapping.
|
|
91
|
+
const variantWebTransitionStyle: ViewStyle =
|
|
92
|
+
Platform.OS === "web"
|
|
93
|
+
? ({
|
|
94
|
+
transitionProperty:
|
|
95
|
+
"background-color, border-color, box-shadow, backdrop-filter, -webkit-backdrop-filter",
|
|
96
|
+
transitionDuration: "200ms",
|
|
97
|
+
transitionTimingFunction: "ease",
|
|
98
|
+
} as ViewStyle)
|
|
99
|
+
: {};
|
|
100
|
+
|
|
90
101
|
const menuWebBlurStyle: ViewStyle =
|
|
91
102
|
Platform.OS === "web"
|
|
92
103
|
? ({
|
|
@@ -219,6 +230,7 @@ export const Avatar = forwardRef<ComponentRef<typeof View>, AvatarProps>(functio
|
|
|
219
230
|
}
|
|
220
231
|
style={[
|
|
221
232
|
styles.root,
|
|
233
|
+
variantWebTransitionStyle,
|
|
222
234
|
isLightVariant ? styles.rootLight : styles.rootDark,
|
|
223
235
|
isLightVariant && triggerWebBlurStyle,
|
|
224
236
|
disabled && styles.disabled,
|
|
@@ -275,6 +287,7 @@ export const Avatar = forwardRef<ComponentRef<typeof View>, AvatarProps>(functio
|
|
|
275
287
|
<View
|
|
276
288
|
style={[
|
|
277
289
|
styles.menu,
|
|
290
|
+
variantWebTransitionStyle,
|
|
278
291
|
isLightVariant ? styles.menuLight : styles.menuDark,
|
|
279
292
|
isLightVariant && menuWebBlurStyle,
|
|
280
293
|
menuWidth != null && { right: undefined, width: menuWidth },
|
|
@@ -292,13 +305,8 @@ export const Avatar = forwardRef<ComponentRef<typeof View>, AvatarProps>(functio
|
|
|
292
305
|
hoverColor={item.hoverColor ?? (isLightVariant ? colors.whiteAlpha7 : undefined)}
|
|
293
306
|
labelStyle={item.labelStyle}
|
|
294
307
|
onPress={() => handleItemPress(item)}
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
? item.backgroundColor
|
|
298
|
-
? styles.emphasizedMenuItem
|
|
299
|
-
: styles.menuItem
|
|
300
|
-
: undefined
|
|
301
|
-
}
|
|
308
|
+
// Same size in both variants so the menu keeps its height when the variant changes.
|
|
309
|
+
style={item.backgroundColor ? styles.emphasizedMenuItem : styles.menuItem}
|
|
302
310
|
/>
|
|
303
311
|
);
|
|
304
312
|
})}
|
|
@@ -409,6 +417,9 @@ const styles = StyleSheet.create({
|
|
|
409
417
|
overflow: "hidden",
|
|
410
418
|
},
|
|
411
419
|
menuDark: {
|
|
420
|
+
// Matches menuLight's border so switching variants does not shift the menu by 2px.
|
|
421
|
+
borderWidth: 1,
|
|
422
|
+
borderColor: "transparent",
|
|
412
423
|
backgroundColor: colors.grey700,
|
|
413
424
|
...Platform.select({
|
|
414
425
|
web: {
|
|
@@ -76,6 +76,18 @@ const bookingRange = {
|
|
|
76
76
|
const formatBookingDate = (date: Date) =>
|
|
77
77
|
`${String(date.getDate()).padStart(2, "0")}/${String(date.getMonth() + 1).padStart(2, "0")}/${date.getFullYear()}`;
|
|
78
78
|
|
|
79
|
+
/** Unavailable days: dimmed number on a filled circle, not selectable. */
|
|
80
|
+
export const RangeWithUnavailableDates: Story = {
|
|
81
|
+
args: {
|
|
82
|
+
range: true,
|
|
83
|
+
placeholder: "Select dates",
|
|
84
|
+
defaultValue: { start: new Date(2026, 5, 15), end: new Date(2026, 5, 24) },
|
|
85
|
+
unavailableDates: [new Date(2026, 5, 8), new Date(2026, 5, 9)],
|
|
86
|
+
blockUnavailableDates: true,
|
|
87
|
+
defaultOpen: true,
|
|
88
|
+
},
|
|
89
|
+
};
|
|
90
|
+
|
|
79
91
|
export const RangeHorizontal: Story = {
|
|
80
92
|
args: {
|
|
81
93
|
range: true,
|
|
@@ -695,7 +695,7 @@ export const DatePicker = forwardRef<ComponentRef<typeof View>, DatePickerProps>
|
|
|
695
695
|
style={[
|
|
696
696
|
styles.dayCircle,
|
|
697
697
|
isSelectedEndpoint && styles.dayCircleSelected,
|
|
698
|
-
dayUnavailable && styles.
|
|
698
|
+
dayUnavailable && styles.dayCircleUnavailable,
|
|
699
699
|
isHovered && styles.dayCircleHovered,
|
|
700
700
|
]}
|
|
701
701
|
>
|
|
@@ -703,7 +703,7 @@ export const DatePicker = forwardRef<ComponentRef<typeof View>, DatePickerProps>
|
|
|
703
703
|
style={[
|
|
704
704
|
styles.dayText,
|
|
705
705
|
{ color: dayTextColor },
|
|
706
|
-
dayUnavailable && styles.
|
|
706
|
+
dayUnavailable && styles.dayTextUnavailable,
|
|
707
707
|
]}
|
|
708
708
|
>
|
|
709
709
|
{day.getDate()}
|
|
@@ -1012,13 +1012,14 @@ const styles = StyleSheet.create({
|
|
|
1012
1012
|
borderRadius: 22,
|
|
1013
1013
|
overflow: "hidden",
|
|
1014
1014
|
},
|
|
1015
|
-
|
|
1016
|
-
|
|
1015
|
+
/** Unavailable day: filled circle a step lighter than the calendar, dimmed number. */
|
|
1016
|
+
dayCircleUnavailable: {
|
|
1017
|
+
backgroundColor: colors.grey600,
|
|
1017
1018
|
borderRadius: 22,
|
|
1018
1019
|
overflow: "hidden",
|
|
1019
1020
|
},
|
|
1020
|
-
|
|
1021
|
-
|
|
1021
|
+
dayTextUnavailable: {
|
|
1022
|
+
color: colors.grey200,
|
|
1022
1023
|
},
|
|
1023
1024
|
dayCircleHovered: {
|
|
1024
1025
|
backgroundColor: colors.grey600,
|
|
@@ -32,6 +32,20 @@ describe("updateVerificationCells", () => {
|
|
|
32
32
|
});
|
|
33
33
|
});
|
|
34
34
|
|
|
35
|
+
it("lays a whole pasted code out from the start when a later cell has focus", () => {
|
|
36
|
+
expect(updateVerificationCells(toVerificationCells("", 6), 4, "123456", 6)).toEqual({
|
|
37
|
+
cells: ["1", "2", "3", "4", "5", "6"],
|
|
38
|
+
nextFocus: 5,
|
|
39
|
+
});
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
it("still fills forward when the pasted digits fit from the focused cell", () => {
|
|
43
|
+
expect(updateVerificationCells(toVerificationCells("12", 6), 2, "3456", 6)).toEqual({
|
|
44
|
+
cells: ["1", "2", "3", "4", "5", "6"],
|
|
45
|
+
nextFocus: 5,
|
|
46
|
+
});
|
|
47
|
+
});
|
|
48
|
+
|
|
35
49
|
it("replaces a selected digit without growing the code", () => {
|
|
36
50
|
expect(updateVerificationCells(toVerificationCells("123456", 6), 2, "9", 6)).toEqual({
|
|
37
51
|
cells: ["1", "2", "9", "4", "5", "6"],
|
|
@@ -51,11 +51,16 @@ export function updateVerificationCells(
|
|
|
51
51
|
length: number,
|
|
52
52
|
): VerificationCellsUpdate {
|
|
53
53
|
const safeLength = Math.max(1, length);
|
|
54
|
-
const
|
|
54
|
+
const focusedIndex = Math.min(Math.max(0, index), safeLength - 1);
|
|
55
55
|
const cells = Array.from({ length: safeLength }, (_, cellIndex) => {
|
|
56
56
|
const cell = currentCells[cellIndex] ?? "";
|
|
57
57
|
return /^\d$/.test(cell) ? cell : "";
|
|
58
58
|
});
|
|
59
|
+
// A paste that does not fit from the focused cell (typically a whole code pasted while a
|
|
60
|
+
// later cell has focus) is laid out from the first cell instead of being cut to the tail.
|
|
61
|
+
const pastedDigits = input.replace(/\D/g, "");
|
|
62
|
+
const safeIndex =
|
|
63
|
+
pastedDigits.length > 1 && pastedDigits.length > safeLength - focusedIndex ? 0 : focusedIndex;
|
|
59
64
|
const insertedDigits = normalizeVerificationCode(input, safeLength - safeIndex);
|
|
60
65
|
|
|
61
66
|
if (!insertedDigits) {
|