@artsy/palette-mobile 14.0.3 → 14.0.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.
- package/dist/elements/Avatar/Avatar.js +8 -6
- package/dist/elements/ButtonNew/Button.js +5 -5
- package/dist/elements/ButtonNew/Button.tests.js +7 -7
- package/dist/elements/Dialog/Dialog.tests.js +13 -13
- package/dist/elements/Image/Image.js +2 -2
- package/dist/elements/Input/Input.d.ts +11 -0
- package/dist/elements/Input/Input.js +16 -11
- package/dist/elements/Input/Input.tests.js +28 -31
- package/dist/elements/Message/Message.tests.js +10 -11
- package/dist/elements/Pill/Pill.tests.js +5 -5
- package/dist/elements/ProgressBar/ProgressBar.js +2 -2
- package/dist/elements/Screen/hooks/useAnimatedHeaderScrolling.js +4 -4
- package/dist/elements/Screen/hooks/useListenForScreenScroll.js +1 -1
- package/dist/elements/Skeleton/Skeleton.js +5 -2
- package/dist/elements/ToolTip/ToolTip.tests.js +5 -4
- package/dist/elements/ToolTip/ToolTipFlyout.js +5 -5
- package/dist/setupJest.d.ts +1 -1
- package/dist/setupJest.js +1 -3
- package/package.json +2 -2
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
-
import { useState } from "react";
|
|
2
|
+
import { useEffect, useState } from "react";
|
|
3
3
|
import { Image } from "react-native";
|
|
4
4
|
import Animated, { useAnimatedStyle, useSharedValue, withTiming, Easing, withDelay, } from "react-native-reanimated";
|
|
5
5
|
import { useColor } from "../../utils/hooks";
|
|
@@ -30,13 +30,15 @@ export const Avatar = ({ src, initials, size = DEFAULT_SIZE }) => {
|
|
|
30
30
|
const color = useColor();
|
|
31
31
|
const [loading, setLoading] = useState(true);
|
|
32
32
|
const opacity = useSharedValue(0);
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
33
|
+
useEffect(() => {
|
|
34
|
+
opacity.set(() => withDelay(100, withTiming(1, {
|
|
35
|
+
duration: 200,
|
|
36
|
+
easing: Easing.sin,
|
|
37
|
+
})));
|
|
38
|
+
}, [loading]);
|
|
37
39
|
const style = useAnimatedStyle(() => {
|
|
38
40
|
return {
|
|
39
|
-
opacity: loading ? 0 : opacity.
|
|
41
|
+
opacity: loading ? 0 : opacity.get(),
|
|
40
42
|
};
|
|
41
43
|
}, [loading]);
|
|
42
44
|
const { diameter, textSize } = VARIANTS[size];
|
|
@@ -19,7 +19,7 @@ export const Button = ({ children, disabled: disabledProp, haptic, icon, iconPos
|
|
|
19
19
|
useAnimatedReaction(() => {
|
|
20
20
|
return pressedV.value;
|
|
21
21
|
}, (pressedVal) => {
|
|
22
|
-
return
|
|
22
|
+
return pressAnimationProgress.set(() => withTiming(pressedVal, {
|
|
23
23
|
duration: ANIMATION_DURATION,
|
|
24
24
|
}));
|
|
25
25
|
});
|
|
@@ -59,8 +59,8 @@ export const Button = ({ children, disabled: disabledProp, haptic, icon, iconPos
|
|
|
59
59
|
};
|
|
60
60
|
}
|
|
61
61
|
return {
|
|
62
|
-
backgroundColor: interpolateColor(pressAnimationProgress.
|
|
63
|
-
borderColor: interpolateColor(pressAnimationProgress.
|
|
62
|
+
backgroundColor: interpolateColor(pressAnimationProgress.get(), [0, 1], [colors.active.bg, colors.pressed.bg]),
|
|
63
|
+
borderColor: interpolateColor(pressAnimationProgress.get(), [0, 1], [colors.active.border, colors.pressed.border]),
|
|
64
64
|
};
|
|
65
65
|
});
|
|
66
66
|
const textAnim = useAnimatedStyle(() => {
|
|
@@ -69,8 +69,8 @@ export const Button = ({ children, disabled: disabledProp, haptic, icon, iconPos
|
|
|
69
69
|
return { color: "rgba(0, 0, 0, 0)" };
|
|
70
70
|
}
|
|
71
71
|
return {
|
|
72
|
-
color: interpolateColor(pressAnimationProgress.
|
|
73
|
-
textDecorationLine: pressAnimationProgress.
|
|
72
|
+
color: interpolateColor(pressAnimationProgress.get(), [0, 1], [colors.active.text, colors.pressed.text]),
|
|
73
|
+
textDecorationLine: pressAnimationProgress.get() > 0 ? "underline" : "none",
|
|
74
74
|
};
|
|
75
75
|
});
|
|
76
76
|
return (_jsx(Pressable, { disabled: disabled, onPressIn: () => {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
-
import { fireEvent } from "@testing-library/react-native";
|
|
2
|
+
import { fireEvent, screen } from "@testing-library/react-native";
|
|
3
3
|
import { Button } from "./Button";
|
|
4
4
|
import { renderWithWrappers } from "../../utils/tests/renderWithWrappers";
|
|
5
5
|
import { Spinner } from "../Spinner";
|
|
@@ -10,20 +10,20 @@ describe("Button", () => {
|
|
|
10
10
|
});
|
|
11
11
|
it("invokes the onClick callback", () => {
|
|
12
12
|
const onPress = jest.fn();
|
|
13
|
-
|
|
14
|
-
fireEvent.press(getByTestId("the-button"));
|
|
13
|
+
renderWithWrappers(_jsx(Button, { testID: "the-button", onPress: onPress, children: "wow" }));
|
|
14
|
+
fireEvent.press(screen.getByTestId("the-button"));
|
|
15
15
|
expect(onPress).toHaveBeenCalled();
|
|
16
16
|
});
|
|
17
17
|
it("does not invoke the onClick callback if loading is true", () => {
|
|
18
18
|
const onPress = jest.fn();
|
|
19
|
-
|
|
20
|
-
fireEvent.press(getByTestId("the-button"));
|
|
19
|
+
renderWithWrappers(_jsx(Button, { testID: "the-button", onPress: onPress, loading: true, children: "wow" }));
|
|
20
|
+
fireEvent.press(screen.getByTestId("the-button"));
|
|
21
21
|
expect(onPress).not.toHaveBeenCalled();
|
|
22
22
|
});
|
|
23
23
|
it("does not invoke the onClick callback if disabled is true", () => {
|
|
24
24
|
const onPress = jest.fn();
|
|
25
|
-
|
|
26
|
-
fireEvent.press(getByTestId("the-button"));
|
|
25
|
+
renderWithWrappers(_jsx(Button, { testID: "the-button", onPress: onPress, disabled: true, children: "wow" }));
|
|
26
|
+
fireEvent.press(screen.getByTestId("the-button"));
|
|
27
27
|
expect(onPress).not.toHaveBeenCalled();
|
|
28
28
|
});
|
|
29
29
|
});
|
|
@@ -1,54 +1,54 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
-
import { fireEvent } from "@testing-library/react-native";
|
|
2
|
+
import { fireEvent, screen } from "@testing-library/react-native";
|
|
3
3
|
import { Dialog } from "./Dialog";
|
|
4
4
|
import { renderWithWrappers } from "../../utils/tests/renderWithWrappers";
|
|
5
5
|
describe("Dialog", () => {
|
|
6
6
|
it("renders without error", () => {
|
|
7
|
-
|
|
7
|
+
renderWithWrappers(_jsx(Dialog, { title: "title", isVisible: true, primaryCta: {
|
|
8
8
|
text: "Primary Action Button",
|
|
9
9
|
onPress: jest.fn(),
|
|
10
10
|
} }));
|
|
11
|
-
expect(getByText("title")).
|
|
11
|
+
expect(screen.getByText("title")).toBeOnTheScreen();
|
|
12
12
|
});
|
|
13
13
|
it("should render details if it is passed", () => {
|
|
14
|
-
|
|
14
|
+
renderWithWrappers(_jsx(Dialog, { title: "title", detail: "Some unique detail", isVisible: true, primaryCta: {
|
|
15
15
|
text: "Primary Action Button",
|
|
16
16
|
onPress: jest.fn(),
|
|
17
17
|
} }));
|
|
18
|
-
expect(getByText("Some unique detail")).
|
|
18
|
+
expect(screen.getByText("Some unique detail")).toBeOnTheScreen();
|
|
19
19
|
});
|
|
20
20
|
it("should render the primary action button", () => {
|
|
21
21
|
const primaryActionMock = jest.fn();
|
|
22
|
-
|
|
22
|
+
renderWithWrappers(_jsx(Dialog, { title: "title", isVisible: true, primaryCta: {
|
|
23
23
|
text: "Primary Action Button",
|
|
24
24
|
onPress: primaryActionMock,
|
|
25
25
|
} }));
|
|
26
|
-
const primaryButton = getByTestId("dialog-primary-action-button");
|
|
26
|
+
const primaryButton = screen.getByTestId("dialog-primary-action-button");
|
|
27
27
|
fireEvent.press(primaryButton);
|
|
28
28
|
expect(primaryActionMock).toHaveBeenCalled();
|
|
29
|
-
expect(getByText("Primary Action Button")).
|
|
29
|
+
expect(screen.getByText("Primary Action Button")).toBeOnTheScreen();
|
|
30
30
|
});
|
|
31
31
|
it("should render the secondary action button if it is passed", () => {
|
|
32
32
|
const secondaryActionMock = jest.fn();
|
|
33
|
-
|
|
33
|
+
renderWithWrappers(_jsx(Dialog, { title: "title", isVisible: true, primaryCta: {
|
|
34
34
|
text: "Primary Action Button",
|
|
35
35
|
onPress: jest.fn(),
|
|
36
36
|
}, secondaryCta: {
|
|
37
37
|
text: "Secondary Action Button",
|
|
38
38
|
onPress: secondaryActionMock,
|
|
39
39
|
} }));
|
|
40
|
-
const secondaryButton = getByTestId("dialog-secondary-action-button");
|
|
40
|
+
const secondaryButton = screen.getByTestId("dialog-secondary-action-button");
|
|
41
41
|
fireEvent.press(secondaryButton);
|
|
42
42
|
expect(secondaryActionMock).toHaveBeenCalled();
|
|
43
|
-
expect(getByText("Secondary Action Button")).
|
|
43
|
+
expect(screen.getByText("Secondary Action Button")).toBeOnTheScreen();
|
|
44
44
|
});
|
|
45
45
|
it("should call onBackgroundPress when backdrop is pressed", () => {
|
|
46
46
|
const onBackgroundPressMock = jest.fn();
|
|
47
|
-
|
|
47
|
+
renderWithWrappers(_jsx(Dialog, { title: "title", isVisible: true, onBackgroundPress: onBackgroundPressMock, primaryCta: {
|
|
48
48
|
text: "Primary Action Button",
|
|
49
49
|
onPress: jest.fn(),
|
|
50
50
|
} }));
|
|
51
|
-
fireEvent.press(getByTestId("dialog-backdrop"));
|
|
51
|
+
fireEvent.press(screen.getByTestId("dialog-backdrop"));
|
|
52
52
|
expect(onBackgroundPressMock).toHaveBeenCalled();
|
|
53
53
|
});
|
|
54
54
|
});
|
|
@@ -15,12 +15,12 @@ export const Image = memo(({ aspectRatio, width, height, performResize = true, s
|
|
|
15
15
|
const color = useColor();
|
|
16
16
|
const animatedStyles = useAnimatedStyle(() => {
|
|
17
17
|
return {
|
|
18
|
-
opacity: withTiming(loading.
|
|
18
|
+
opacity: withTiming(loading.get() ? 0 : 1, { duration: 200, easing: Easing.sin }),
|
|
19
19
|
};
|
|
20
20
|
}, []);
|
|
21
21
|
const onAnimationEnd = useCallback(() => {
|
|
22
22
|
"worklet";
|
|
23
|
-
loading.
|
|
23
|
+
loading.set(() => false);
|
|
24
24
|
// No need to get the js thread involved here
|
|
25
25
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
26
26
|
}, []);
|
|
@@ -11,6 +11,10 @@ export interface InputProps extends Omit<TextInputProps, "placeholder" | "onChan
|
|
|
11
11
|
* These lead to some issues when the parent component wants further control of the value
|
|
12
12
|
*/
|
|
13
13
|
disabled?: boolean;
|
|
14
|
+
/**
|
|
15
|
+
* Enables the clear button
|
|
16
|
+
* @warning This prop only works if `value` is specified
|
|
17
|
+
*/
|
|
14
18
|
enableClearButton?: boolean;
|
|
15
19
|
error?: string;
|
|
16
20
|
fixedRightPlaceholder?: string;
|
|
@@ -60,6 +64,13 @@ export interface InputProps extends Omit<TextInputProps, "placeholder" | "onChan
|
|
|
60
64
|
* <Input mask="999-99-9999 999-99-9999 999-99-9999" />
|
|
61
65
|
*/
|
|
62
66
|
mask?: string | string[] | undefined;
|
|
67
|
+
/**
|
|
68
|
+
* @warning This prop affects the performance of the input
|
|
69
|
+
* and should be avoided if possible.
|
|
70
|
+
* Use `defaultValue` instead.
|
|
71
|
+
* See: https://github.com/facebook/react-native-website/pull/4247
|
|
72
|
+
*/
|
|
73
|
+
value?: string | undefined;
|
|
63
74
|
}
|
|
64
75
|
export declare const HORIZONTAL_PADDING = 15;
|
|
65
76
|
export declare const INPUT_BORDER_RADIUS = 4;
|
|
@@ -148,14 +148,17 @@ export const Input = forwardRef(({ addClearListener = false, defaultValue, disab
|
|
|
148
148
|
fontFamily: fontFamily,
|
|
149
149
|
};
|
|
150
150
|
}, [fontFamily, space]);
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
151
|
+
useEffect(() => {
|
|
152
|
+
const inputState = getInputState({
|
|
153
|
+
isFocused: !!focused,
|
|
154
|
+
value: value,
|
|
155
|
+
});
|
|
156
|
+
animatedState.set(() => inputState);
|
|
157
|
+
}, [value, focused, animatedState]);
|
|
155
158
|
const textInputAnimatedStyles = useAnimatedStyle(() => {
|
|
156
159
|
return {
|
|
157
|
-
borderColor: withTiming(INPUT_VARIANTS[variant][animatedState.
|
|
158
|
-
color: withTiming(INPUT_VARIANTS[variant][animatedState.
|
|
160
|
+
borderColor: withTiming(INPUT_VARIANTS[variant][animatedState.get()].inputBorderColor),
|
|
161
|
+
color: withTiming(INPUT_VARIANTS[variant][animatedState.get()].inputTextColor),
|
|
159
162
|
};
|
|
160
163
|
});
|
|
161
164
|
const labelAnimatedStyles = useAnimatedStyle(() => {
|
|
@@ -165,15 +168,15 @@ export const Input = forwardRef(({ addClearListener = false, defaultValue, disab
|
|
|
165
168
|
? textInputPaddingLeft - 3
|
|
166
169
|
: HORIZONTAL_PADDING;
|
|
167
170
|
return {
|
|
168
|
-
color: withTiming(INPUT_VARIANTS[variant][animatedState.
|
|
169
|
-
top: withTiming(INPUT_VARIANTS[variant][animatedState.
|
|
170
|
-
fontSize: withTiming(INPUT_VARIANTS[variant][animatedState.
|
|
171
|
+
color: withTiming(INPUT_VARIANTS[variant][animatedState.get()].labelColor),
|
|
172
|
+
top: withTiming(INPUT_VARIANTS[variant][animatedState.get()].labelTop),
|
|
173
|
+
fontSize: withTiming(INPUT_VARIANTS[variant][animatedState.get()].labelFontSize),
|
|
171
174
|
marginLeft: withTiming(marginLeft),
|
|
172
175
|
};
|
|
173
176
|
});
|
|
174
177
|
const selectComponentStyles = useAnimatedStyle(() => {
|
|
175
178
|
return {
|
|
176
|
-
borderColor: withTiming(INPUT_VARIANTS[variant][animatedState.
|
|
179
|
+
borderColor: withTiming(INPUT_VARIANTS[variant][animatedState.get()].inputBorderColor),
|
|
177
180
|
};
|
|
178
181
|
});
|
|
179
182
|
const handleFocus = (e) => {
|
|
@@ -349,7 +352,9 @@ export const Input = forwardRef(({ addClearListener = false, defaultValue, disab
|
|
|
349
352
|
...styles,
|
|
350
353
|
}, children: placeholderString }))) }));
|
|
351
354
|
}, [placeholder, styles]);
|
|
352
|
-
return (_jsxs(Flex, { flexGrow: 1, children: [renderAndroidPlaceholderMeasuringHack(), renderHint(), renderAnimatedTitle(), _jsx(AnimatedStyledInput
|
|
355
|
+
return (_jsxs(Flex, { flexGrow: 1, children: [renderAndroidPlaceholderMeasuringHack(), renderHint(), renderAnimatedTitle(), _jsx(AnimatedStyledInput
|
|
356
|
+
// Only use a controlled input if specified
|
|
357
|
+
, { ...((propValue !== undefined && propValue !== null) || mask ? { value } : {}), onChangeText: handleChangeText, style: [styles, textInputAnimatedStyles], onFocus: handleFocus, onBlur: handleBlur, onLayout: (event) => {
|
|
353
358
|
setInputWidth(event.nativeEvent.layout.width);
|
|
354
359
|
}, scrollEnabled: props.multiline, editable: !disabled, textAlignVertical: props.multiline ? "top" : "center", ref: inputRef, placeholderTextColor: color("black60"), placeholder: getPlaceholder(), secureTextEntry: !showPassword, ...props }), renderRightComponent(), renderLeftComponent(), renderBottomComponent()] }));
|
|
355
360
|
});
|
|
@@ -1,50 +1,47 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
-
import { fireEvent } from "@testing-library/react-native";
|
|
2
|
+
import { fireEvent, screen } from "@testing-library/react-native";
|
|
3
3
|
import { Input } from "./Input";
|
|
4
4
|
import { renderWithWrappers } from "../../utils/tests/renderWithWrappers";
|
|
5
5
|
describe("Input", () => {
|
|
6
6
|
const testID = "input";
|
|
7
7
|
it("renders an instance of native TextInput", () => {
|
|
8
|
-
|
|
9
|
-
expect(getByTestId(testID).type).toEqual("TextInput");
|
|
8
|
+
renderWithWrappers(_jsx(Input, { testID: testID }));
|
|
9
|
+
expect(screen.getByTestId(testID).type).toEqual("TextInput");
|
|
10
10
|
});
|
|
11
11
|
it("uses correct font family", () => {
|
|
12
|
-
|
|
13
|
-
expect(
|
|
12
|
+
renderWithWrappers(_jsx(Input, { testID: testID, placeholder: "input" }));
|
|
13
|
+
expect(screen.getByPlaceholderText("input")).toHaveStyle({ fontFamily: "Unica77LL-Regular" });
|
|
14
14
|
});
|
|
15
15
|
it("mutates given text as value", () => {
|
|
16
|
-
|
|
17
|
-
fireEvent.changeText(getByTestId(testID), "mockStr");
|
|
18
|
-
getByDisplayValue("mockStr");
|
|
16
|
+
renderWithWrappers(_jsx(Input, { testID: testID }));
|
|
17
|
+
fireEvent.changeText(screen.getByTestId(testID), "mockStr");
|
|
18
|
+
screen.getByDisplayValue("mockStr");
|
|
19
19
|
});
|
|
20
20
|
it("Shows an error message when input has an error", () => {
|
|
21
|
-
|
|
22
|
-
getByText("input has an error");
|
|
21
|
+
renderWithWrappers(_jsx(Input, { value: "", error: "input has an error" }));
|
|
22
|
+
screen.getByText("input has an error");
|
|
23
23
|
});
|
|
24
|
-
it("should render the clear button when input is not empty and pressing it should clear the input", () => {
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
fireEvent(
|
|
29
|
-
|
|
30
|
-
getByLabelText("Clear input button");
|
|
31
|
-
fireEvent.press(getByLabelText("Clear input button"));
|
|
32
|
-
expect(queryByDisplayValue("Banksy")).toBeFalsy();
|
|
24
|
+
it("should render the clear button when input is not empty and pressing it should clear the input", async () => {
|
|
25
|
+
renderWithWrappers(_jsx(Input, { testID: testID, placeholder: "USD", enableClearButton: true }));
|
|
26
|
+
fireEvent(screen.getByTestId(testID), "onChangeText", "Banksy");
|
|
27
|
+
await screen.findByLabelText("Clear input button");
|
|
28
|
+
fireEvent.press(screen.getByLabelText("Clear input button"));
|
|
29
|
+
expect(screen.queryByDisplayValue("Banksy")).toBeFalsy();
|
|
33
30
|
});
|
|
34
31
|
it("should show the correct show/hide password icon", () => {
|
|
35
|
-
|
|
36
|
-
getByPlaceholderText("password");
|
|
37
|
-
getByLabelText("show password button");
|
|
38
|
-
fireEvent(getByPlaceholderText("password"), "onChangeText", "123456");
|
|
39
|
-
fireEvent.press(getByLabelText("show password button"));
|
|
40
|
-
expect(queryByLabelText("show password button")).toBeFalsy();
|
|
41
|
-
getByLabelText("hide password button");
|
|
42
|
-
fireEvent.press(getByLabelText("hide password button"));
|
|
43
|
-
expect(queryByLabelText("hide password button")).toBeFalsy();
|
|
44
|
-
getByLabelText("show password button");
|
|
32
|
+
renderWithWrappers(_jsx(Input, { placeholder: "password", secureTextEntry: true }));
|
|
33
|
+
screen.getByPlaceholderText("password");
|
|
34
|
+
screen.getByLabelText("show password button");
|
|
35
|
+
fireEvent(screen.getByPlaceholderText("password"), "onChangeText", "123456");
|
|
36
|
+
fireEvent.press(screen.getByLabelText("show password button"));
|
|
37
|
+
expect(screen.queryByLabelText("show password button")).toBeFalsy();
|
|
38
|
+
screen.getByLabelText("hide password button");
|
|
39
|
+
fireEvent.press(screen.getByLabelText("hide password button"));
|
|
40
|
+
expect(screen.queryByLabelText("hide password button")).toBeFalsy();
|
|
41
|
+
screen.getByLabelText("show password button");
|
|
45
42
|
});
|
|
46
43
|
it("enables scrolling when multiline is true", () => {
|
|
47
|
-
|
|
48
|
-
expect(getByTestId(testID).props.scrollEnabled).toBe(true);
|
|
44
|
+
renderWithWrappers(_jsx(Input, { testID: testID, multiline: true }));
|
|
45
|
+
expect(screen.getByTestId(testID).props.scrollEnabled).toBe(true);
|
|
49
46
|
});
|
|
50
47
|
});
|
|
@@ -1,26 +1,25 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
-
import { fireEvent } from "@testing-library/react-native";
|
|
2
|
+
import { fireEvent, screen } from "@testing-library/react-native";
|
|
3
3
|
import { Message } from "./Message";
|
|
4
4
|
import { renderWithWrappers } from "../../utils/tests/renderWithWrappers";
|
|
5
5
|
describe("Message", () => {
|
|
6
6
|
it("it renders", () => {
|
|
7
|
-
|
|
8
|
-
expect(
|
|
9
|
-
expect(
|
|
10
|
-
expect(MessageComponent.getByText("text")).toBeDefined();
|
|
7
|
+
renderWithWrappers(_jsx(Message, { variant: "default", title: "title", text: "text" }));
|
|
8
|
+
expect(screen.getByText("title")).toBeOnTheScreen();
|
|
9
|
+
expect(screen.getByText("text")).toBeOnTheScreen();
|
|
11
10
|
});
|
|
12
11
|
it("does not show close button when !showCloseButton", () => {
|
|
13
|
-
|
|
14
|
-
expect((
|
|
12
|
+
renderWithWrappers(_jsx(Message, { variant: "default", title: "title", text: "text" }));
|
|
13
|
+
expect(screen.queryByTestId("Message-close-button")).not.toBeOnTheScreen();
|
|
15
14
|
});
|
|
16
15
|
it("shows close button when showCloseButton", () => {
|
|
17
|
-
|
|
18
|
-
expect(getByTestId("Message-close-button")).
|
|
16
|
+
renderWithWrappers(_jsx(Message, { variant: "default", title: "title", text: "text", showCloseButton: true }));
|
|
17
|
+
expect(screen.getByTestId("Message-close-button")).toBeOnTheScreen();
|
|
19
18
|
});
|
|
20
19
|
it("fires onClose press event", () => {
|
|
21
20
|
const onClose = jest.fn();
|
|
22
|
-
|
|
23
|
-
fireEvent.press(getByTestId("Message-close-button"));
|
|
21
|
+
renderWithWrappers(_jsx(Message, { variant: "default", onClose: onClose, title: "title", text: "text", showCloseButton: true }));
|
|
22
|
+
fireEvent.press(screen.getByTestId("Message-close-button"));
|
|
24
23
|
expect(onClose).toHaveBeenCalled();
|
|
25
24
|
});
|
|
26
25
|
});
|
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
-
import { fireEvent, render } from "@testing-library/react-native";
|
|
2
|
+
import { fireEvent, render, screen } from "@testing-library/react-native";
|
|
3
3
|
import { Pill } from "./Pill";
|
|
4
4
|
import { Theme } from "../../Theme";
|
|
5
5
|
describe("Pill", () => {
|
|
6
6
|
it("invokes the onClick callback", () => {
|
|
7
7
|
const onPress = jest.fn();
|
|
8
|
-
|
|
9
|
-
fireEvent.press(getByText("wow"));
|
|
8
|
+
render(_jsx(Theme, { children: _jsx(Pill, { onPress: onPress, children: "wow" }) }));
|
|
9
|
+
fireEvent.press(screen.getByText("wow"));
|
|
10
10
|
expect(onPress).toHaveBeenCalled();
|
|
11
11
|
});
|
|
12
12
|
it("should not be pressable if disabled is passed", () => {
|
|
13
13
|
const onPress = jest.fn();
|
|
14
|
-
|
|
15
|
-
fireEvent.press(getByText("Press me"));
|
|
14
|
+
render(_jsx(Theme, { children: _jsx(Pill, { disabled: true, onPress: onPress, children: "Press me" }) }));
|
|
15
|
+
fireEvent.press(screen.getByText("Press me"));
|
|
16
16
|
expect(onPress).not.toHaveBeenCalled();
|
|
17
17
|
});
|
|
18
18
|
});
|
|
@@ -11,11 +11,11 @@ export const ProgressBar = ({ animationDuration = 200, backgroundColor = "black3
|
|
|
11
11
|
const width = useSharedValue(0);
|
|
12
12
|
const progress = clamp(unclampedProgress, 0, 100);
|
|
13
13
|
const progressAnim = useAnimatedStyle(() => {
|
|
14
|
-
return { width: `${width.
|
|
14
|
+
return { width: `${width.get()}%` };
|
|
15
15
|
});
|
|
16
16
|
const [onCompletionCalled, setOnCompletionCalled] = useState(false);
|
|
17
17
|
useEffect(() => {
|
|
18
|
-
width.
|
|
18
|
+
width.set(() => withTiming(progress, { duration: animationDuration }));
|
|
19
19
|
if (progress === 100 && !onCompletionCalled) {
|
|
20
20
|
onCompletion?.();
|
|
21
21
|
setOnCompletionCalled(true);
|
|
@@ -3,7 +3,7 @@ import { runOnJS, useAnimatedReaction, useSharedValue } from "react-native-reani
|
|
|
3
3
|
import { NAVBAR_HEIGHT } from "../constants";
|
|
4
4
|
export const useAnimatedHeaderScrolling = (scrollY, scrollYOffset = 0) => {
|
|
5
5
|
const listenForScroll = useSharedValue(true);
|
|
6
|
-
const [currScrollY, setCurrScrollY] = useState(scrollY.
|
|
6
|
+
const [currScrollY, setCurrScrollY] = useState(scrollY.get());
|
|
7
7
|
const HEADER_HEIGHT = useMemo(() => NAVBAR_HEIGHT + scrollYOffset, [scrollYOffset]);
|
|
8
8
|
// Needed to run on JS thread
|
|
9
9
|
const update = (y) => {
|
|
@@ -11,14 +11,14 @@ export const useAnimatedHeaderScrolling = (scrollY, scrollYOffset = 0) => {
|
|
|
11
11
|
};
|
|
12
12
|
useEffect(() => {
|
|
13
13
|
const timer = setTimeout(() => {
|
|
14
|
-
listenForScroll.
|
|
14
|
+
listenForScroll.set(() => false);
|
|
15
15
|
}, 1000);
|
|
16
16
|
return () => {
|
|
17
17
|
clearTimeout(timer);
|
|
18
18
|
};
|
|
19
|
-
}, [listenForScroll]);
|
|
19
|
+
}, [listenForScroll.get()]);
|
|
20
20
|
useAnimatedReaction(() => {
|
|
21
|
-
return [scrollY.
|
|
21
|
+
return [scrollY.get(), listenForScroll.get()];
|
|
22
22
|
}, ([animatedScrollY, isListeningForScroll], previousScroll) => {
|
|
23
23
|
const [prevScrollY] = previousScroll ?? [0, false];
|
|
24
24
|
// Hacky way to avoid some weird header behavior.
|
|
@@ -8,7 +8,7 @@ export const useListenForScreenScroll = () => {
|
|
|
8
8
|
const scrollY = useAnimatedHeaderScrolling(animatedScrollY, scrollYOffset);
|
|
9
9
|
const scrollHandler = useAnimatedScrollHandler({
|
|
10
10
|
onScroll: (event) => {
|
|
11
|
-
animatedScrollY.
|
|
11
|
+
animatedScrollY.set(() => event.contentOffset.y);
|
|
12
12
|
},
|
|
13
13
|
});
|
|
14
14
|
useEffect(() => {
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { useEffect } from "react";
|
|
2
3
|
import Animated, { Easing, useAnimatedStyle, useSharedValue, withRepeat, withTiming, } from "react-native-reanimated";
|
|
3
4
|
import { useColor } from "../../utils/hooks";
|
|
4
5
|
import { Flex } from "../Flex";
|
|
@@ -15,9 +16,11 @@ import { Text } from "../Text";
|
|
|
15
16
|
*/
|
|
16
17
|
export const Skeleton = ({ children }) => {
|
|
17
18
|
const opacity = useSharedValue(0.5);
|
|
18
|
-
|
|
19
|
+
useEffect(() => {
|
|
20
|
+
opacity.set(() => withRepeat(withTiming(1, { duration: 1000, easing: Easing.ease }), -1, true));
|
|
21
|
+
}, [opacity]);
|
|
19
22
|
const fadeLoopAnim = useAnimatedStyle(() => {
|
|
20
|
-
return { opacity: opacity.
|
|
23
|
+
return { opacity: opacity.get() };
|
|
21
24
|
}, []);
|
|
22
25
|
return _jsx(Animated.View, { style: fadeLoopAnim, children: children });
|
|
23
26
|
};
|
|
@@ -1,15 +1,16 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { screen } from "@testing-library/react-native";
|
|
2
3
|
import { ToolTip } from "./ToolTip";
|
|
3
4
|
import { ScreenDimensionsProvider } from "../../utils/hooks";
|
|
4
5
|
import { renderWithWrappers } from "../../utils/tests/renderWithWrappers";
|
|
5
6
|
import { Text } from "../Text";
|
|
6
7
|
describe("ToolTip", () => {
|
|
7
8
|
it("shows the flyout when enabled", () => {
|
|
8
|
-
|
|
9
|
-
expect(
|
|
9
|
+
renderWithWrappers(_jsx(ScreenDimensionsProvider, { children: _jsx(ToolTip, { enabled: true, testID: "flyout", initialToolTipText: "Words", children: _jsx(Text, { children: "Text" }) }) }));
|
|
10
|
+
expect(screen.getByTestId("flyout")).toBeOnTheScreen();
|
|
10
11
|
});
|
|
11
12
|
it("Does not show the flyout when disabled", () => {
|
|
12
|
-
|
|
13
|
-
expect(queryByTestId("flyout")).
|
|
13
|
+
renderWithWrappers(_jsx(ScreenDimensionsProvider, { children: _jsx(ToolTip, { enabled: false, testID: "flyout", initialToolTipText: "Words", children: _jsx(Text, { children: "Text" }) }) }));
|
|
14
|
+
expect(screen.queryByTestId("flyout")).not.toBeOnTheScreen();
|
|
14
15
|
});
|
|
15
16
|
});
|
|
@@ -10,23 +10,23 @@ export const ToolTipFlyout = ({ containerStyle, tapToDismiss, height, width, onC
|
|
|
10
10
|
const boxDimensions = useSharedValue(initialBoxDimensions);
|
|
11
11
|
const animationStyle = useAnimatedStyle(() => {
|
|
12
12
|
return {
|
|
13
|
-
height: withTiming(boxDimensions.
|
|
13
|
+
height: withTiming(boxDimensions.get().height, {
|
|
14
14
|
duration: 500,
|
|
15
15
|
}),
|
|
16
|
-
width: withTiming(boxDimensions.
|
|
16
|
+
width: withTiming(boxDimensions.get().width, {
|
|
17
17
|
duration: 500,
|
|
18
18
|
}),
|
|
19
19
|
};
|
|
20
20
|
});
|
|
21
21
|
useEffect(() => {
|
|
22
22
|
if (text) {
|
|
23
|
-
boxDimensions.
|
|
23
|
+
boxDimensions.set(() => ({
|
|
24
24
|
height,
|
|
25
25
|
width,
|
|
26
|
-
};
|
|
26
|
+
}));
|
|
27
27
|
}
|
|
28
28
|
else {
|
|
29
|
-
boxDimensions.
|
|
29
|
+
boxDimensions.set(() => initialBoxDimensions);
|
|
30
30
|
}
|
|
31
31
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
32
32
|
}, [text, height, width]);
|
package/dist/setupJest.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
import "@testing-library/react-native/extend-expect";
|
package/dist/setupJest.js
CHANGED
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
// @ts-expect-error
|
|
2
2
|
global.__TEST__ = true;
|
|
3
|
+
import "@testing-library/react-native/extend-expect";
|
|
3
4
|
import mockSafeAreaContext from "react-native-safe-area-context/jest/mock";
|
|
4
5
|
jest.mock("react-native-safe-area-context", () => mockSafeAreaContext);
|
|
5
6
|
jest.mock("react-native/Libraries/Animated/NativeAnimatedHelper");
|
|
6
7
|
require("react-native-reanimated").setUpTests();
|
|
7
|
-
// @ts-expect-error
|
|
8
|
-
global.__reanimatedWorkletInit = () => { };
|
|
9
|
-
jest.mock("react-native-reanimated", () => require("react-native-reanimated/mock"));
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@artsy/palette-mobile",
|
|
3
|
-
"version": "14.0.
|
|
3
|
+
"version": "14.0.4",
|
|
4
4
|
"description": "Artsy's design system for React Native",
|
|
5
5
|
"scripts": {
|
|
6
6
|
"android": "RCT_METRO_PORT=8082 react-native run-android --port 8082 --terminal terminal",
|
|
@@ -104,7 +104,7 @@
|
|
|
104
104
|
"eslint-plugin-react": "7.32.2",
|
|
105
105
|
"eslint-plugin-react-hooks": "^4.6.0",
|
|
106
106
|
"eslint-plugin-storybook": "0.6.10",
|
|
107
|
-
"eslint-plugin-testing-library": "
|
|
107
|
+
"eslint-plugin-testing-library": "6.4.0",
|
|
108
108
|
"husky": "^8.0.3",
|
|
109
109
|
"jest": "29.6.3",
|
|
110
110
|
"jest-environment-jsdom": "29.4.2",
|