@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.
@@ -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 Animated, { Easing, FadeIn, FadeOut } from "react-native-reanimated";
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, currentScrollY = 0 } = useScreenScrollContext();
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, useDerivedValue, withTiming } from "react-native-reanimated";
4
- import { useScreenScrollContext } from "./ScreenScrollContext";
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 = useDerivedValue(() => {
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: 100,
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, useSharedValue } from "react-native-reanimated";
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 animatedScrollY = useSharedValue(0);
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
- animatedScrollY.set(() => event.contentOffset.y);
10
+ currentScrollYAnimated.set(() => event.contentOffset.y);
11
+ scrollViewDimensionsAnimated.set(() => event.contentSize.height);
12
12
  },
13
13
  });
14
14
  useEffect(() => {
@@ -0,0 +1,5 @@
1
+ export declare const useShowLargeTitle: ({ stickyBarHeight }: {
2
+ stickyBarHeight: number | null;
3
+ }) => {
4
+ visible: import("react-native-reanimated").DerivedValue<boolean>;
5
+ };
@@ -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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@artsy/palette-mobile",
3
- "version": "14.0.40",
3
+ "version": "14.0.41",
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",