@artsy/palette-mobile 14.0.40 → 14.0.41
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/Screen/Header.js +16 -6
- package/dist/elements/Screen/ScreenScrollContext.d.ts +3 -0
- package/dist/elements/Screen/ScreenScrollContext.js +9 -0
- package/dist/elements/Screen/StickySubHeader.d.ts +3 -0
- package/dist/elements/Screen/StickySubHeader.js +8 -14
- package/dist/elements/Screen/hooks/useListenForScreenScroll.js +5 -5
- package/dist/elements/Screen/hooks/useShowLargeTitle.d.ts +5 -0
- package/dist/elements/Screen/hooks/useShowLargeTitle.js +29 -0
- package/package.json +1 -1
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
2
|
import { MotiView } from "moti";
|
|
3
|
-
import
|
|
3
|
+
import { Dimensions } from "react-native";
|
|
4
|
+
import Animated, { Easing, FadeIn, FadeOut, useDerivedValue } from "react-native-reanimated";
|
|
4
5
|
import { useScreenScrollContext } from "./ScreenScrollContext";
|
|
6
|
+
import { BOTTOM_TABS_HEIGHT, STICKY_BAR_HEIGHT } from "./StickySubHeader";
|
|
5
7
|
import { NAVBAR_HEIGHT, ZINDEX } from "./constants";
|
|
6
8
|
import { DEFAULT_HIT_SLOP } from "../../constants";
|
|
7
9
|
import { ArrowLeftIcon } from "../../svgs/ArrowLeftIcon";
|
|
@@ -18,7 +20,17 @@ const Right = ({ hideRightElements, rightElements }) => {
|
|
|
18
20
|
return _jsx(_Fragment, { children: !hideRightElements && rightElements });
|
|
19
21
|
};
|
|
20
22
|
const Center = ({ animated, hideTitle, title }) => {
|
|
21
|
-
const { scrollYOffset = 0,
|
|
23
|
+
const { scrollYOffset = 0, currentScrollYAnimated, scrollViewDimensionsAnimated, } = useScreenScrollContext();
|
|
24
|
+
const { height: screenHeight } = Dimensions.get("window");
|
|
25
|
+
const scrollViewContentHeight = screenHeight - NAVBAR_HEIGHT - STICKY_BAR_HEIGHT - BOTTOM_TABS_HEIGHT;
|
|
26
|
+
// Show / hide the title to avoid rerenders, which retrigger the animation
|
|
27
|
+
const display = useDerivedValue(() => {
|
|
28
|
+
// The user is scrolling on a screen that is too small to show the small header
|
|
29
|
+
if (scrollViewDimensionsAnimated?.value < scrollViewContentHeight) {
|
|
30
|
+
return "none";
|
|
31
|
+
}
|
|
32
|
+
return currentScrollYAnimated.value < NAVBAR_HEIGHT + scrollYOffset ? "none" : "flex";
|
|
33
|
+
}, [currentScrollYAnimated, scrollYOffset]);
|
|
22
34
|
if (hideTitle) {
|
|
23
35
|
return null;
|
|
24
36
|
}
|
|
@@ -26,12 +38,10 @@ const Center = ({ animated, hideTitle, title }) => {
|
|
|
26
38
|
if (!animated) {
|
|
27
39
|
return titleTextElement;
|
|
28
40
|
}
|
|
29
|
-
// Show / hide the title to avoid rerenders, which retrigger the animation
|
|
30
|
-
const display = currentScrollY < NAVBAR_HEIGHT + scrollYOffset ? "none" : "flex";
|
|
31
41
|
return (_jsx(Animated.View, { entering: FadeIn.duration(400).easing(Easing.out(Easing.exp)), exiting: FadeOut.duration(400).easing(Easing.out(Easing.exp)), style: {
|
|
32
|
-
display,
|
|
42
|
+
display: display.value,
|
|
33
43
|
}, children: _jsx(MotiView, { animate: {
|
|
34
|
-
opacity: display === "flex" ? 1 : 0,
|
|
44
|
+
opacity: display.value === "flex" ? 1 : 0,
|
|
35
45
|
}, children: titleTextElement }) }));
|
|
36
46
|
};
|
|
37
47
|
const Left = ({ hideLeftElements, leftElements, onBack }) => {
|
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
/// <reference types="react" />
|
|
2
|
+
import { SharedValue } from "react-native-reanimated";
|
|
2
3
|
export interface ScreenScrollContextProps {
|
|
4
|
+
currentScrollYAnimated: SharedValue<number>;
|
|
3
5
|
currentScrollY: number;
|
|
4
6
|
updateCurrentScrollY: (scrollY: number) => void;
|
|
5
7
|
scrollYOffset?: number;
|
|
8
|
+
scrollViewDimensionsAnimated: SharedValue<number>;
|
|
6
9
|
updateScrollYOffset: (offset: number) => void;
|
|
7
10
|
}
|
|
8
11
|
export declare const ScreenScrollContextProvider: React.FC<React.PropsWithChildren<{}>>;
|
|
@@ -1,17 +1,26 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
2
|
import { useContext, createContext, useState } from "react";
|
|
3
|
+
import { useSharedValue } from "react-native-reanimated";
|
|
3
4
|
const ScreenScrollContext = createContext({
|
|
5
|
+
// Casting this value as ShareValue because we set it to useSharedValue(0) on Mount
|
|
6
|
+
currentScrollYAnimated: null,
|
|
4
7
|
currentScrollY: 0,
|
|
5
8
|
updateCurrentScrollY: () => { },
|
|
6
9
|
scrollYOffset: undefined,
|
|
10
|
+
// Casting this value as ShareValue because we set it to useSharedValue(0) on Mount
|
|
11
|
+
scrollViewDimensionsAnimated: null,
|
|
7
12
|
updateScrollYOffset: () => { },
|
|
8
13
|
});
|
|
9
14
|
export const ScreenScrollContextProvider = ({ children, }) => {
|
|
10
15
|
const [currentScrollY, setCurrentScrollY] = useState(0);
|
|
11
16
|
const [scrollYOffset, setScrollYOffset] = useState(undefined);
|
|
17
|
+
const currentScrollYAnimated = useSharedValue(0);
|
|
18
|
+
const scrollViewDimensionsAnimated = useSharedValue(0);
|
|
12
19
|
const providerValue = {
|
|
20
|
+
currentScrollYAnimated,
|
|
13
21
|
currentScrollY,
|
|
14
22
|
scrollYOffset,
|
|
23
|
+
scrollViewDimensionsAnimated,
|
|
15
24
|
updateCurrentScrollY: (scrollY) => {
|
|
16
25
|
setCurrentScrollY(scrollY);
|
|
17
26
|
},
|
|
@@ -9,4 +9,7 @@ export interface StickySubHeaderProps extends React.PropsWithChildren<{}> {
|
|
|
9
9
|
subTitle?: string;
|
|
10
10
|
Component?: React.ReactNode;
|
|
11
11
|
}
|
|
12
|
+
export declare const STICKY_BAR_HEIGHT = 42;
|
|
13
|
+
export declare const DEFAULT_SEPARATOR_COMPONENT: JSX.Element;
|
|
14
|
+
export declare const BOTTOM_TABS_HEIGHT = 65;
|
|
12
15
|
export declare const StickySubHeader: React.FC<StickySubHeaderProps>;
|
|
@@ -1,24 +1,18 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { useState } from "react";
|
|
3
|
-
import Animated, { useAnimatedStyle,
|
|
4
|
-
import {
|
|
5
|
-
import { NAVBAR_HEIGHT } from "./constants";
|
|
3
|
+
import Animated, { useAnimatedStyle, withTiming } from "react-native-reanimated";
|
|
4
|
+
import { useShowLargeTitle } from "./hooks/useShowLargeTitle";
|
|
6
5
|
import { useSpace } from "../../utils/hooks";
|
|
7
6
|
import { Flex } from "../Flex";
|
|
8
7
|
import { Separator } from "../Separator";
|
|
9
8
|
import { Text } from "../Text";
|
|
10
|
-
const STICKY_BAR_HEIGHT = 42;
|
|
11
|
-
const DEFAULT_SEPARATOR_COMPONENT = _jsx(Separator, { borderColor: "black5" });
|
|
9
|
+
export const STICKY_BAR_HEIGHT = 42;
|
|
10
|
+
export const DEFAULT_SEPARATOR_COMPONENT = _jsx(Separator, { borderColor: "black5" });
|
|
11
|
+
export const BOTTOM_TABS_HEIGHT = 65;
|
|
12
12
|
export const StickySubHeader = ({ title, largeTitle = false, separatorComponent = DEFAULT_SEPARATOR_COMPONENT, subTitle, children, Component, }) => {
|
|
13
|
-
const { currentScrollY, scrollYOffset = 0 } = useScreenScrollContext();
|
|
14
13
|
const space = useSpace();
|
|
15
14
|
const [stickyBarHeight, setStickyHeaderHeight] = useState(null);
|
|
16
|
-
const visible =
|
|
17
|
-
if (stickyBarHeight === null) {
|
|
18
|
-
return true;
|
|
19
|
-
}
|
|
20
|
-
return currentScrollY < NAVBAR_HEIGHT + scrollYOffset;
|
|
21
|
-
}, [currentScrollY, scrollYOffset, stickyBarHeight]);
|
|
15
|
+
const { visible } = useShowLargeTitle({ stickyBarHeight });
|
|
22
16
|
const handleLayout = (event) => {
|
|
23
17
|
setStickyHeaderHeight(event.nativeEvent.layout.height);
|
|
24
18
|
};
|
|
@@ -29,7 +23,7 @@ export const StickySubHeader = ({ title, largeTitle = false, separatorComponent
|
|
|
29
23
|
const animatedStyles = useAnimatedStyle(() => {
|
|
30
24
|
return {
|
|
31
25
|
height: withTiming(visible.value ? stickyBarHeight || STICKY_BAR_HEIGHT : 0, {
|
|
32
|
-
duration:
|
|
26
|
+
duration: 200,
|
|
33
27
|
}),
|
|
34
28
|
transform: [
|
|
35
29
|
{
|
|
@@ -39,6 +33,6 @@ export const StickySubHeader = ({ title, largeTitle = false, separatorComponent
|
|
|
39
33
|
},
|
|
40
34
|
],
|
|
41
35
|
};
|
|
42
|
-
});
|
|
36
|
+
}, [visible.value, stickyBarHeight]);
|
|
43
37
|
return (_jsxs(Flex, { children: [stickyBarHeight === null && (_jsx(Flex, { onLayout: (event) => handleLayout(event), position: "absolute", backgroundColor: "white100", zIndex: -1000, style: sharedStyles, children: _jsxs(Flex, { mb: 1, children: [_jsx(Text, { variant: largeTitle ? "xl" : "lg-display", color: "white100", children: title }), !!subTitle && (_jsx(Text, { variant: "xs", mt: 0.5, color: "white100", children: subTitle })), Component] }) })), _jsx(Animated.View, { style: [sharedStyles, animatedStyles], children: _jsxs(Flex, { style: { height: stickyBarHeight }, mb: 1, children: [_jsx(Text, { variant: largeTitle ? "xl" : "lg-display", children: title }), subTitle && (_jsx(Text, { variant: "xs", mt: 0.5, children: subTitle })), Component] }) }), children, children !== undefined && separatorComponent] }));
|
|
44
38
|
};
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import { useEffect } from "react";
|
|
2
|
-
import { useAnimatedScrollHandler
|
|
2
|
+
import { useAnimatedScrollHandler } from "react-native-reanimated";
|
|
3
3
|
import { useAnimatedHeaderScrolling } from "./useAnimatedHeaderScrolling";
|
|
4
4
|
import { useScreenScrollContext } from "../ScreenScrollContext";
|
|
5
5
|
export const useListenForScreenScroll = () => {
|
|
6
|
-
const { updateCurrentScrollY, scrollYOffset } = useScreenScrollContext();
|
|
7
|
-
const
|
|
8
|
-
const scrollY = useAnimatedHeaderScrolling(animatedScrollY, scrollYOffset);
|
|
6
|
+
const { updateCurrentScrollY, scrollYOffset, currentScrollYAnimated, scrollViewDimensionsAnimated, } = useScreenScrollContext();
|
|
7
|
+
const scrollY = useAnimatedHeaderScrolling(currentScrollYAnimated, scrollYOffset);
|
|
9
8
|
const scrollHandler = useAnimatedScrollHandler({
|
|
10
9
|
onScroll: (event) => {
|
|
11
|
-
|
|
10
|
+
currentScrollYAnimated.set(() => event.contentOffset.y);
|
|
11
|
+
scrollViewDimensionsAnimated.set(() => event.contentSize.height);
|
|
12
12
|
},
|
|
13
13
|
});
|
|
14
14
|
useEffect(() => {
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { Dimensions } from "react-native";
|
|
2
|
+
import { useDerivedValue } from "react-native-reanimated";
|
|
3
|
+
import { useScreenScrollContext } from "../ScreenScrollContext";
|
|
4
|
+
import { BOTTOM_TABS_HEIGHT, STICKY_BAR_HEIGHT } from "../StickySubHeader";
|
|
5
|
+
import { NAVBAR_HEIGHT } from "../constants";
|
|
6
|
+
export const useShowLargeTitle = ({ stickyBarHeight }) => {
|
|
7
|
+
const { currentScrollY, scrollYOffset = 0, currentScrollYAnimated, scrollViewDimensionsAnimated, } = useScreenScrollContext();
|
|
8
|
+
const { height: screenHeight } = Dimensions.get("window");
|
|
9
|
+
const scrollViewContentHeight = screenHeight - NAVBAR_HEIGHT - STICKY_BAR_HEIGHT - BOTTOM_TABS_HEIGHT;
|
|
10
|
+
const visible = useDerivedValue(() => {
|
|
11
|
+
// We show the big title if
|
|
12
|
+
if (
|
|
13
|
+
// We are still not yet done computing its height
|
|
14
|
+
stickyBarHeight === null ||
|
|
15
|
+
// The user didn't scroll yet
|
|
16
|
+
currentScrollYAnimated === null ||
|
|
17
|
+
// The user is scrolling on a screen that is too small to show the small header
|
|
18
|
+
scrollViewDimensionsAnimated?.value < scrollViewContentHeight) {
|
|
19
|
+
return true;
|
|
20
|
+
}
|
|
21
|
+
if (currentScrollYAnimated?.value < 0) {
|
|
22
|
+
return true;
|
|
23
|
+
}
|
|
24
|
+
return currentScrollYAnimated.value < NAVBAR_HEIGHT + scrollYOffset;
|
|
25
|
+
}, [currentScrollY, scrollYOffset, stickyBarHeight, currentScrollYAnimated]);
|
|
26
|
+
return {
|
|
27
|
+
visible,
|
|
28
|
+
};
|
|
29
|
+
};
|
package/package.json
CHANGED