@fountain-ui/core 2.0.0-beta.10 → 2.0.0-beta.11
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/build/commonjs/Tabs/TabIndicator.js +1 -5
- package/build/commonjs/Tabs/TabIndicator.js.map +1 -1
- package/build/commonjs/Tabs/Tabs.js +46 -48
- package/build/commonjs/Tabs/Tabs.js.map +1 -1
- package/build/commonjs/Tabs/useTabCoordinates.js +44 -0
- package/build/commonjs/Tabs/useTabCoordinates.js.map +1 -0
- package/build/commonjs/Tabs/useTabsWidth.js +26 -0
- package/build/commonjs/Tabs/useTabsWidth.js.map +1 -0
- package/build/commonjs/hooks/useCollapsibleAppBar.js +31 -15
- package/build/commonjs/hooks/useCollapsibleAppBar.js.map +1 -1
- package/build/commonjs/hooks/useFadeInAppBar.js +26 -8
- package/build/commonjs/hooks/useFadeInAppBar.js.map +1 -1
- package/build/commonjs/internal/hooks/index.js +0 -8
- package/build/commonjs/internal/hooks/index.js.map +1 -1
- package/build/module/Tabs/TabIndicator.js +2 -6
- package/build/module/Tabs/TabIndicator.js.map +1 -1
- package/build/module/Tabs/Tabs.js +39 -39
- package/build/module/Tabs/Tabs.js.map +1 -1
- package/build/module/Tabs/useTabCoordinates.js +30 -0
- package/build/module/Tabs/useTabCoordinates.js.map +1 -0
- package/build/module/Tabs/useTabsWidth.js +18 -0
- package/build/module/Tabs/useTabsWidth.js.map +1 -0
- package/build/module/hooks/useCollapsibleAppBar.js +31 -15
- package/build/module/hooks/useCollapsibleAppBar.js.map +1 -1
- package/build/module/hooks/useFadeInAppBar.js +26 -8
- package/build/module/hooks/useFadeInAppBar.js.map +1 -1
- package/build/module/internal/hooks/index.js +0 -1
- package/build/module/internal/hooks/index.js.map +1 -1
- package/build/typescript/Tabs/useTabCoordinates.d.ts +7 -0
- package/build/typescript/Tabs/useTabsWidth.d.ts +2 -0
- package/build/typescript/internal/hooks/index.d.ts +0 -1
- package/package.json +2 -2
- package/src/Tabs/TabIndicator.tsx +3 -7
- package/src/Tabs/Tabs.tsx +37 -39
- package/src/Tabs/useTabCoordinates.ts +36 -0
- package/src/Tabs/useTabsWidth.ts +20 -0
- package/src/hooks/useCollapsibleAppBar.ts +22 -11
- package/src/hooks/useFadeInAppBar.ts +23 -8
- package/src/internal/hooks/index.ts +0 -1
- package/build/commonjs/internal/hooks/useWidth.js +0 -29
- package/build/commonjs/internal/hooks/useWidth.js.map +0 -1
- package/build/module/internal/hooks/useWidth.js +0 -15
- package/build/module/internal/hooks/useWidth.js.map +0 -1
- package/build/typescript/internal/hooks/useWidth.d.ts +0 -2
- package/src/internal/hooks/useWidth.ts +0 -17
|
@@ -1,13 +1,12 @@
|
|
|
1
1
|
function _extends() { _extends = Object.assign ? Object.assign.bind() : function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
|
|
2
2
|
|
|
3
|
-
import React from 'react';
|
|
3
|
+
import React, { cloneElement, useEffect, useMemo, useRef } from 'react';
|
|
4
4
|
import { ScrollView, View } from 'react-native';
|
|
5
5
|
import { Easing, useSharedValue, withTiming } from 'react-native-reanimated';
|
|
6
|
-
import { isEveryDefined } from '@fountain-ui/utils';
|
|
7
6
|
import { css, useTheme } from '../styles';
|
|
8
|
-
import { useWidth } from '../internal/hooks';
|
|
9
|
-
import { defaultCoordinate } from './TabCoordinate';
|
|
10
7
|
import TabIndicator from './TabIndicator';
|
|
8
|
+
import useTabsWidth from './useTabsWidth';
|
|
9
|
+
import useTabCoordinates from './useTabCoordinates';
|
|
11
10
|
|
|
12
11
|
const useStyles = function () {
|
|
13
12
|
const theme = useTheme();
|
|
@@ -25,6 +24,10 @@ const useStyles = function () {
|
|
|
25
24
|
};
|
|
26
25
|
};
|
|
27
26
|
|
|
27
|
+
const ANIMATION_CONFIG = {
|
|
28
|
+
duration: 200,
|
|
29
|
+
easing: Easing.out(Easing.exp)
|
|
30
|
+
};
|
|
28
31
|
export default function Tabs(props) {
|
|
29
32
|
const {
|
|
30
33
|
children,
|
|
@@ -40,53 +43,50 @@ export default function Tabs(props) {
|
|
|
40
43
|
...otherProps
|
|
41
44
|
} = props;
|
|
42
45
|
const styles = useStyles();
|
|
43
|
-
const [containerWidth, handleLayout] =
|
|
44
|
-
const scrollViewRef =
|
|
45
|
-
const
|
|
46
|
-
|
|
46
|
+
const [containerWidth, handleLayout] = useTabsWidth();
|
|
47
|
+
const scrollViewRef = useRef(null);
|
|
48
|
+
const {
|
|
49
|
+
coordinates,
|
|
50
|
+
updateCoordinate
|
|
51
|
+
} = useTabCoordinates(children);
|
|
47
52
|
const internalScrollValue = useSharedValue(0);
|
|
48
|
-
const scrollValue = scrollValueProp
|
|
49
|
-
const isReadyToRenderIndicator =
|
|
50
|
-
|
|
53
|
+
const scrollValue = scrollValueProp ?? internalScrollValue;
|
|
54
|
+
const isReadyToRenderIndicator = coordinates.length > 0;
|
|
55
|
+
useEffect(() => {
|
|
51
56
|
const animateTab = index => {
|
|
52
|
-
|
|
53
|
-
duration: 200,
|
|
54
|
-
easing: Easing.out(Easing.exp)
|
|
55
|
-
});
|
|
57
|
+
scrollValue.value = withTiming(index, ANIMATION_CONFIG);
|
|
56
58
|
};
|
|
57
59
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
+
animateTab(indexProp);
|
|
61
|
+
}, [indexProp, scrollValue]);
|
|
62
|
+
const scrollPosition = useMemo(() => {
|
|
63
|
+
const coordinate = coordinates[indexProp - 1];
|
|
64
|
+
|
|
65
|
+
if (coordinate) {
|
|
66
|
+
const tabWidth = coordinate.x2 - coordinate.x1;
|
|
67
|
+
return Math.floor(coordinate.x1 + tabWidth / 2);
|
|
60
68
|
}
|
|
61
|
-
}, [indexProp, scrollValueProp, internalScrollValue]);
|
|
62
|
-
React.useEffect(() => {
|
|
63
|
-
const snapTab = index => {
|
|
64
|
-
const scrollView = scrollViewRef.current;
|
|
65
|
-
const coordinate = coordinates[index - 1] || defaultCoordinate;
|
|
66
69
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
x,
|
|
72
|
-
y: 0,
|
|
73
|
-
animated: true
|
|
74
|
-
});
|
|
75
|
-
}
|
|
76
|
-
};
|
|
70
|
+
return 0;
|
|
71
|
+
}, [indexProp, coordinates]);
|
|
72
|
+
useEffect(() => {
|
|
73
|
+
const scrollView = scrollViewRef.current;
|
|
77
74
|
|
|
78
|
-
|
|
79
|
-
|
|
75
|
+
if (scrollView && scrollPosition > 0) {
|
|
76
|
+
scrollView.scrollTo({
|
|
77
|
+
x: scrollPosition,
|
|
78
|
+
y: 0,
|
|
79
|
+
animated: true
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
}, [scrollPosition, containerWidth]);
|
|
80
83
|
const tabElements = React.Children.map(children, (child, index) => {
|
|
81
84
|
const onLayout = event => {
|
|
82
85
|
const {
|
|
83
86
|
x,
|
|
84
87
|
width
|
|
85
88
|
} = event.nativeEvent.layout;
|
|
86
|
-
|
|
87
|
-
x1: x,
|
|
88
|
-
x2: x + width
|
|
89
|
-
}, ...prev.slice(index + 1)]);
|
|
89
|
+
updateCoordinate(index, x, width);
|
|
90
90
|
};
|
|
91
91
|
|
|
92
92
|
const onMouseDown = e => {
|
|
@@ -106,7 +106,7 @@ export default function Tabs(props) {
|
|
|
106
106
|
const selected = index === indexProp;
|
|
107
107
|
const enableIndicatorPlaceholder = disableIndicator ? false : isReadyToRenderIndicator ? false : selected; //@ts-ignore
|
|
108
108
|
|
|
109
|
-
return /*#__PURE__*/
|
|
109
|
+
return /*#__PURE__*/cloneElement(child, {
|
|
110
110
|
enableIndicator: enableIndicatorPlaceholder,
|
|
111
111
|
onLayout,
|
|
112
112
|
onPress,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["React","ScrollView","View","Easing","useSharedValue","withTiming","isEveryDefined","css","useTheme","useWidth","defaultCoordinate","TabIndicator","useStyles","theme","root","fixedRoot","flexDirection","fixedTab","flex","scrollableContainer","paddingHorizontal","spacing","Tabs","props","children","index","indexProp","disableIndicator","keyboardDismissMode","keyboardShouldPersistTaps","onChange","scrollable","scrollValue","scrollValueProp","style","variant","otherProps","styles","containerWidth","handleLayout","scrollViewRef","useRef","tabCount","Children","count","coordinates","setCoordinates","useState","Array","internalScrollValue","isReadyToRenderIndicator","useEffect","animateTab","value","duration","easing","out","exp","undefined","snapTab","scrollView","current","coordinate","tabWidth","x2","x1","x","scrollTo","y","animated","tabElements","map","child","onLayout","event","width","nativeEvent","layout","prev","slice","onMouseDown","e","preventDefault","onPress","selected","enableIndicatorPlaceholder","cloneElement","enableIndicator","indicator"],"sources":["Tabs.tsx"],"sourcesContent":["import React from 'react';\nimport { GestureResponderEvent, LayoutChangeEvent, ScrollView, View } from 'react-native';\nimport { Easing, useSharedValue, withTiming } from 'react-native-reanimated';\nimport { NamedStylesStringUnion, UseStyles } from '@fountain-ui/styles';\nimport { isEveryDefined } from '@fountain-ui/utils';\nimport { css, useTheme } from '../styles';\nimport { useWidth } from '../internal/hooks';\nimport type TabsProps from './TabsProps';\nimport TabCoordinate, { defaultCoordinate } from './TabCoordinate';\nimport TabIndicator from './TabIndicator';\n\ntype TabsStyleKeys =\n | 'root'\n | 'fixedRoot'\n | 'fixedTab'\n | 'scrollableContainer';\n\ntype TabsStyles = NamedStylesStringUnion<TabsStyleKeys>;\n\nconst useStyles: UseStyles<TabsStyles> = function (): TabsStyles {\n const theme = useTheme();\n\n return {\n root: {},\n fixedRoot: {\n flexDirection: 'row',\n },\n fixedTab: {\n flex: 1,\n },\n scrollableContainer: {\n paddingHorizontal: theme.spacing(1),\n },\n };\n};\n\nexport default function Tabs(props: TabsProps) {\n const {\n children,\n index: indexProp,\n disableIndicator = false,\n keyboardDismissMode = 'none',\n keyboardShouldPersistTaps = 'never',\n onChange,\n scrollable = false,\n scrollValue: scrollValueProp,\n style,\n variant = 'primary',\n ...otherProps\n } = props;\n\n const styles = useStyles();\n\n const [containerWidth, handleLayout] = useWidth();\n\n const scrollViewRef = React.useRef<ScrollView | null>(null);\n\n const tabCount = React.Children.count(children);\n const [coordinates, setCoordinates] = React.useState<TabCoordinate[]>(() => new Array(tabCount));\n\n const internalScrollValue = useSharedValue(0);\n const scrollValue = scrollValueProp || internalScrollValue;\n\n const isReadyToRenderIndicator = isEveryDefined(coordinates);\n\n React.useEffect(() => {\n const animateTab = (index: number) => {\n internalScrollValue.value = withTiming(index, {\n duration: 200,\n easing: Easing.out(Easing.exp),\n });\n };\n\n if (scrollValueProp === undefined) {\n animateTab(indexProp);\n }\n }, [indexProp, scrollValueProp, internalScrollValue]);\n\n React.useEffect(() => {\n const snapTab = (index: number) => {\n const scrollView = scrollViewRef.current;\n const coordinate: TabCoordinate = coordinates[index - 1] || defaultCoordinate;\n\n if (scrollView) {\n const tabWidth = coordinate.x2 - coordinate.x1;\n const x = coordinate.x1 + tabWidth / 2;\n\n scrollView.scrollTo({ x, y: 0, animated: true });\n }\n };\n\n snapTab(indexProp);\n }, [indexProp, containerWidth, coordinates]);\n\n const tabElements = React.Children.map(children, (child, index) => {\n const onLayout = (event: LayoutChangeEvent) => {\n const { x, width } = event.nativeEvent.layout;\n\n setCoordinates(prev => ([\n ...prev.slice(0, index),\n { x1: x, x2: x + width },\n ...prev.slice(index + 1),\n ]));\n };\n\n const onMouseDown = (e: GestureResponderEvent) => {\n if (keyboardShouldPersistTaps === 'always') {\n e.preventDefault();\n }\n };\n\n const onPress = () => {\n onChange?.(index);\n // @ts-ignore\n child.props.onPress?.();\n };\n\n const selected = index === indexProp;\n const enableIndicatorPlaceholder = disableIndicator\n ? false\n : (isReadyToRenderIndicator ? false : selected);\n\n //@ts-ignore\n return React.cloneElement(child, {\n enableIndicator: enableIndicatorPlaceholder,\n onLayout,\n onPress,\n onMouseDown,\n variant,\n selected,\n style: scrollable ? undefined : styles.fixedTab,\n });\n });\n\n const indicator = (\n <TabIndicator\n coordinates={coordinates}\n disabled={disableIndicator}\n scrollable={scrollable}\n scrollValue={scrollValue}\n />\n );\n\n return (\n <View\n onLayout={handleLayout}\n style={css([\n styles.root,\n scrollable ? undefined : styles.fixedRoot,\n style,\n ])}\n {...otherProps}\n >\n {scrollable ? (\n <ScrollView\n automaticallyAdjustContentInsets={false}\n bounces={false}\n contentContainerStyle={styles.scrollableContainer}\n directionalLockEnabled={true}\n horizontal={true}\n ref={scrollViewRef}\n scrollsToTop={false}\n showsHorizontalScrollIndicator={false}\n showsVerticalScrollIndicator={false}\n keyboardDismissMode={keyboardDismissMode}\n keyboardShouldPersistTaps={keyboardShouldPersistTaps}\n >\n {tabElements}\n {indicator}\n </ScrollView>\n ) : (\n <>\n {tabElements}\n {indicator}\n </>\n )}\n </View>\n );\n};\n"],"mappings":";;AAAA,OAAOA,KAAP,MAAkB,OAAlB;AACA,SAAmDC,UAAnD,EAA+DC,IAA/D,QAA2E,cAA3E;AACA,SAASC,MAAT,EAAiBC,cAAjB,EAAiCC,UAAjC,QAAmD,yBAAnD;AAEA,SAASC,cAAT,QAA+B,oBAA/B;AACA,SAASC,GAAT,EAAcC,QAAd,QAA8B,WAA9B;AACA,SAASC,QAAT,QAAyB,mBAAzB;AAEA,SAAwBC,iBAAxB,QAAiD,iBAAjD;AACA,OAAOC,YAAP,MAAyB,gBAAzB;;AAUA,MAAMC,SAAgC,GAAG,YAAwB;EAC7D,MAAMC,KAAK,GAAGL,QAAQ,EAAtB;EAEA,OAAO;IACHM,IAAI,EAAE,EADH;IAEHC,SAAS,EAAE;MACPC,aAAa,EAAE;IADR,CAFR;IAKHC,QAAQ,EAAE;MACNC,IAAI,EAAE;IADA,CALP;IAQHC,mBAAmB,EAAE;MACjBC,iBAAiB,EAAEP,KAAK,CAACQ,OAAN,CAAc,CAAd;IADF;EARlB,CAAP;AAYH,CAfD;;AAiBA,eAAe,SAASC,IAAT,CAAcC,KAAd,EAAgC;EAC3C,MAAM;IACFC,QADE;IAEFC,KAAK,EAAEC,SAFL;IAGFC,gBAAgB,GAAG,KAHjB;IAIFC,mBAAmB,GAAG,MAJpB;IAKFC,yBAAyB,GAAG,OAL1B;IAMFC,QANE;IAOFC,UAAU,GAAG,KAPX;IAQFC,WAAW,EAAEC,eARX;IASFC,KATE;IAUFC,OAAO,GAAG,SAVR;IAWF,GAAGC;EAXD,IAYFb,KAZJ;EAcA,MAAMc,MAAM,GAAGzB,SAAS,EAAxB;EAEA,MAAM,CAAC0B,cAAD,EAAiBC,YAAjB,IAAiC9B,QAAQ,EAA/C;EAEA,MAAM+B,aAAa,GAAGxC,KAAK,CAACyC,MAAN,CAAgC,IAAhC,CAAtB;EAEA,MAAMC,QAAQ,GAAG1C,KAAK,CAAC2C,QAAN,CAAeC,KAAf,CAAqBpB,QAArB,CAAjB;EACA,MAAM,CAACqB,WAAD,EAAcC,cAAd,IAAgC9C,KAAK,CAAC+C,QAAN,CAAgC,MAAM,IAAIC,KAAJ,CAAUN,QAAV,CAAtC,CAAtC;EAEA,MAAMO,mBAAmB,GAAG7C,cAAc,CAAC,CAAD,CAA1C;EACA,MAAM4B,WAAW,GAAGC,eAAe,IAAIgB,mBAAvC;EAEA,MAAMC,wBAAwB,GAAG5C,cAAc,CAACuC,WAAD,CAA/C;EAEA7C,KAAK,CAACmD,SAAN,CAAgB,MAAM;IAClB,MAAMC,UAAU,GAAI3B,KAAD,IAAmB;MAClCwB,mBAAmB,CAACI,KAApB,GAA4BhD,UAAU,CAACoB,KAAD,EAAQ;QAC1C6B,QAAQ,EAAE,GADgC;QAE1CC,MAAM,EAAEpD,MAAM,CAACqD,GAAP,CAAWrD,MAAM,CAACsD,GAAlB;MAFkC,CAAR,CAAtC;IAIH,CALD;;IAOA,IAAIxB,eAAe,KAAKyB,SAAxB,EAAmC;MAC/BN,UAAU,CAAC1B,SAAD,CAAV;IACH;EACJ,CAXD,EAWG,CAACA,SAAD,EAAYO,eAAZ,EAA6BgB,mBAA7B,CAXH;EAaAjD,KAAK,CAACmD,SAAN,CAAgB,MAAM;IAClB,MAAMQ,OAAO,GAAIlC,KAAD,IAAmB;MAC/B,MAAMmC,UAAU,GAAGpB,aAAa,CAACqB,OAAjC;MACA,MAAMC,UAAyB,GAAGjB,WAAW,CAACpB,KAAK,GAAG,CAAT,CAAX,IAA0Bf,iBAA5D;;MAEA,IAAIkD,UAAJ,EAAgB;QACZ,MAAMG,QAAQ,GAAGD,UAAU,CAACE,EAAX,GAAgBF,UAAU,CAACG,EAA5C;QACA,MAAMC,CAAC,GAAGJ,UAAU,CAACG,EAAX,GAAgBF,QAAQ,GAAG,CAArC;QAEAH,UAAU,CAACO,QAAX,CAAoB;UAAED,CAAF;UAAKE,CAAC,EAAE,CAAR;UAAWC,QAAQ,EAAE;QAArB,CAApB;MACH;IACJ,CAVD;;IAYAV,OAAO,CAACjC,SAAD,CAAP;EACH,CAdD,EAcG,CAACA,SAAD,EAAYY,cAAZ,EAA4BO,WAA5B,CAdH;EAgBA,MAAMyB,WAAW,GAAGtE,KAAK,CAAC2C,QAAN,CAAe4B,GAAf,CAAmB/C,QAAnB,EAA6B,CAACgD,KAAD,EAAQ/C,KAAR,KAAkB;IAC/D,MAAMgD,QAAQ,GAAIC,KAAD,IAA8B;MAC3C,MAAM;QAAER,CAAF;QAAKS;MAAL,IAAeD,KAAK,CAACE,WAAN,CAAkBC,MAAvC;MAEA/B,cAAc,CAACgC,IAAI,IAAK,CACpB,GAAGA,IAAI,CAACC,KAAL,CAAW,CAAX,EAActD,KAAd,CADiB,EAEpB;QAAEwC,EAAE,EAAEC,CAAN;QAASF,EAAE,EAAEE,CAAC,GAAGS;MAAjB,CAFoB,EAGpB,GAAGG,IAAI,CAACC,KAAL,CAAWtD,KAAK,GAAG,CAAnB,CAHiB,CAAV,CAAd;IAKH,CARD;;IAUA,MAAMuD,WAAW,GAAIC,CAAD,IAA8B;MAC9C,IAAIpD,yBAAyB,KAAK,QAAlC,EAA4C;QACxCoD,CAAC,CAACC,cAAF;MACH;IACJ,CAJD;;IAMA,MAAMC,OAAO,GAAG,MAAM;MAAA;;MAClBrD,QAAQ,SAAR,IAAAA,QAAQ,WAAR,YAAAA,QAAQ,CAAGL,KAAH,CAAR,CADkB,CAElB;;MACA,wCAAA+C,KAAK,CAACjD,KAAN,EAAY4D,OAAZ;IACH,CAJD;;IAMA,MAAMC,QAAQ,GAAG3D,KAAK,KAAKC,SAA3B;IACA,MAAM2D,0BAA0B,GAAG1D,gBAAgB,GAC7C,KAD6C,GAE5CuB,wBAAwB,GAAG,KAAH,GAAWkC,QAF1C,CAxB+D,CA4B/D;;IACA,oBAAOpF,KAAK,CAACsF,YAAN,CAAmBd,KAAnB,EAA0B;MAC7Be,eAAe,EAAEF,0BADY;MAE7BZ,QAF6B;MAG7BU,OAH6B;MAI7BH,WAJ6B;MAK7B7C,OAL6B;MAM7BiD,QAN6B;MAO7BlD,KAAK,EAAEH,UAAU,GAAG2B,SAAH,GAAerB,MAAM,CAACpB;IAPV,CAA1B,CAAP;EASH,CAtCmB,CAApB;EAwCA,MAAMuE,SAAS,gBACX,oBAAC,YAAD;IACI,WAAW,EAAE3C,WADjB;IAEI,QAAQ,EAAElB,gBAFd;IAGI,UAAU,EAAEI,UAHhB;IAII,WAAW,EAAEC;EAJjB,EADJ;EASA,oBACI,oBAAC,IAAD;IACI,QAAQ,EAAEO,YADd;IAEI,KAAK,EAAEhC,GAAG,CAAC,CACP8B,MAAM,CAACvB,IADA,EAEPiB,UAAU,GAAG2B,SAAH,GAAerB,MAAM,CAACtB,SAFzB,EAGPmB,KAHO,CAAD;EAFd,GAOQE,UAPR,GASKL,UAAU,gBACP,oBAAC,UAAD;IACI,gCAAgC,EAAE,KADtC;IAEI,OAAO,EAAE,KAFb;IAGI,qBAAqB,EAAEM,MAAM,CAAClB,mBAHlC;IAII,sBAAsB,EAAE,IAJ5B;IAKI,UAAU,EAAE,IALhB;IAMI,GAAG,EAAEqB,aANT;IAOI,YAAY,EAAE,KAPlB;IAQI,8BAA8B,EAAE,KARpC;IASI,4BAA4B,EAAE,KATlC;IAUI,mBAAmB,EAAEZ,mBAVzB;IAWI,yBAAyB,EAAEC;EAX/B,GAaKyC,WAbL,EAcKkB,SAdL,CADO,gBAkBP,0CACKlB,WADL,EAEKkB,SAFL,CA3BR,CADJ;AAmCH;AAAA"}
|
|
1
|
+
{"version":3,"names":["React","cloneElement","useEffect","useMemo","useRef","ScrollView","View","Easing","useSharedValue","withTiming","css","useTheme","TabIndicator","useTabsWidth","useTabCoordinates","useStyles","theme","root","fixedRoot","flexDirection","fixedTab","flex","scrollableContainer","paddingHorizontal","spacing","ANIMATION_CONFIG","duration","easing","out","exp","Tabs","props","children","index","indexProp","disableIndicator","keyboardDismissMode","keyboardShouldPersistTaps","onChange","scrollable","scrollValue","scrollValueProp","style","variant","otherProps","styles","containerWidth","handleLayout","scrollViewRef","coordinates","updateCoordinate","internalScrollValue","isReadyToRenderIndicator","length","animateTab","value","scrollPosition","coordinate","tabWidth","x2","x1","Math","floor","scrollView","current","scrollTo","x","y","animated","tabElements","Children","map","child","onLayout","event","width","nativeEvent","layout","onMouseDown","e","preventDefault","onPress","selected","enableIndicatorPlaceholder","enableIndicator","undefined","indicator"],"sources":["Tabs.tsx"],"sourcesContent":["import React, { cloneElement, useEffect, useMemo, useRef } from 'react';\nimport { GestureResponderEvent, LayoutChangeEvent, ScrollView, View } from 'react-native';\nimport type { WithTimingConfig } from 'react-native-reanimated';\nimport { Easing, useSharedValue, withTiming } from 'react-native-reanimated';\nimport { NamedStylesStringUnion, UseStyles } from '@fountain-ui/styles';\nimport { css, useTheme } from '../styles';\nimport type TabsProps from './TabsProps';\nimport TabIndicator from './TabIndicator';\nimport useTabsWidth from './useTabsWidth';\nimport useTabCoordinates from './useTabCoordinates';\n\ntype TabsStyleKeys =\n | 'root'\n | 'fixedRoot'\n | 'fixedTab'\n | 'scrollableContainer';\n\ntype TabsStyles = NamedStylesStringUnion<TabsStyleKeys>;\n\nconst useStyles: UseStyles<TabsStyles> = function (): TabsStyles {\n const theme = useTheme();\n\n return {\n root: {},\n fixedRoot: {\n flexDirection: 'row',\n },\n fixedTab: {\n flex: 1,\n },\n scrollableContainer: {\n paddingHorizontal: theme.spacing(1),\n },\n };\n};\n\nconst ANIMATION_CONFIG: Readonly<WithTimingConfig> = {\n duration: 200,\n easing: Easing.out(Easing.exp),\n};\n\nexport default function Tabs(props: TabsProps) {\n const {\n children,\n index: indexProp,\n disableIndicator = false,\n keyboardDismissMode = 'none',\n keyboardShouldPersistTaps = 'never',\n onChange,\n scrollable = false,\n scrollValue: scrollValueProp,\n style,\n variant = 'primary',\n ...otherProps\n } = props;\n\n const styles = useStyles();\n\n const [containerWidth, handleLayout] = useTabsWidth();\n\n const scrollViewRef = useRef<ScrollView | null>(null);\n\n const { coordinates, updateCoordinate } = useTabCoordinates(children);\n\n const internalScrollValue = useSharedValue(0);\n const scrollValue = scrollValueProp ?? internalScrollValue;\n\n const isReadyToRenderIndicator = coordinates.length > 0;\n\n useEffect(() => {\n const animateTab = (index: number) => {\n scrollValue.value = withTiming(index, ANIMATION_CONFIG);\n };\n\n animateTab(indexProp);\n }, [indexProp, scrollValue]);\n\n const scrollPosition = useMemo<number>(() => {\n const coordinate = coordinates[indexProp - 1];\n\n if (coordinate) {\n const tabWidth = coordinate.x2 - coordinate.x1;\n return Math.floor(coordinate.x1 + tabWidth / 2);\n }\n\n return 0;\n }, [indexProp, coordinates]);\n\n useEffect(() => {\n const scrollView = scrollViewRef.current;\n\n if (scrollView && scrollPosition > 0) {\n scrollView.scrollTo({ x: scrollPosition, y: 0, animated: true });\n }\n }, [scrollPosition, containerWidth]);\n\n const tabElements = React.Children.map(children, (child, index) => {\n const onLayout = (event: LayoutChangeEvent) => {\n const { x, width } = event.nativeEvent.layout;\n\n updateCoordinate(index, x, width);\n };\n\n const onMouseDown = (e: GestureResponderEvent) => {\n if (keyboardShouldPersistTaps === 'always') {\n e.preventDefault();\n }\n };\n\n const onPress = () => {\n onChange?.(index);\n // @ts-ignore\n child.props.onPress?.();\n };\n\n const selected = index === indexProp;\n const enableIndicatorPlaceholder = disableIndicator\n ? false\n : (isReadyToRenderIndicator ? false : selected);\n\n //@ts-ignore\n return cloneElement(child, {\n enableIndicator: enableIndicatorPlaceholder,\n onLayout,\n onPress,\n onMouseDown,\n variant,\n selected,\n style: scrollable ? undefined : styles.fixedTab,\n });\n });\n\n const indicator = (\n <TabIndicator\n coordinates={coordinates}\n disabled={disableIndicator}\n scrollable={scrollable}\n scrollValue={scrollValue}\n />\n );\n\n return (\n <View\n onLayout={handleLayout}\n style={css([\n styles.root,\n scrollable ? undefined : styles.fixedRoot,\n style,\n ])}\n {...otherProps}\n >\n {scrollable ? (\n <ScrollView\n automaticallyAdjustContentInsets={false}\n bounces={false}\n contentContainerStyle={styles.scrollableContainer}\n directionalLockEnabled={true}\n horizontal={true}\n ref={scrollViewRef}\n scrollsToTop={false}\n showsHorizontalScrollIndicator={false}\n showsVerticalScrollIndicator={false}\n keyboardDismissMode={keyboardDismissMode}\n keyboardShouldPersistTaps={keyboardShouldPersistTaps}\n >\n {tabElements}\n {indicator}\n </ScrollView>\n ) : (\n <React.Fragment>\n {tabElements}\n {indicator}\n </React.Fragment>\n )}\n </View>\n );\n};\n"],"mappings":"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"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import React, { useRef, useState } from 'react';
|
|
2
|
+
import { isEveryDefined } from '@fountain-ui/utils';
|
|
3
|
+
export default function useTabCoordinates(tabElements) {
|
|
4
|
+
const incompleteCoordinatesRef = useRef([]);
|
|
5
|
+
const [completeCoordinates, setCompleteCoordinates] = useState([]);
|
|
6
|
+
|
|
7
|
+
const isAllCoordinatesDefined = coordinates => {
|
|
8
|
+
const numberOfTab = React.Children.count(tabElements);
|
|
9
|
+
const numberOfCoordinates = coordinates.length;
|
|
10
|
+
const everyCoordinatesDefined = isEveryDefined(coordinates);
|
|
11
|
+
return numberOfTab === numberOfCoordinates && everyCoordinatesDefined;
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
const updateCoordinate = (index, x, width) => {
|
|
15
|
+
incompleteCoordinatesRef.current[index] = {
|
|
16
|
+
x1: x,
|
|
17
|
+
x2: x + width
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
if (isAllCoordinatesDefined(incompleteCoordinatesRef.current)) {
|
|
21
|
+
setCompleteCoordinates(incompleteCoordinatesRef.current);
|
|
22
|
+
}
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
return {
|
|
26
|
+
coordinates: completeCoordinates,
|
|
27
|
+
updateCoordinate
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
//# sourceMappingURL=useTabCoordinates.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["React","useRef","useState","isEveryDefined","useTabCoordinates","tabElements","incompleteCoordinatesRef","completeCoordinates","setCompleteCoordinates","isAllCoordinatesDefined","coordinates","numberOfTab","Children","count","numberOfCoordinates","length","everyCoordinatesDefined","updateCoordinate","index","x","width","current","x1","x2"],"sources":["useTabCoordinates.ts"],"sourcesContent":["import React, { useRef, useState } from 'react';\nimport { isEveryDefined } from '@fountain-ui/utils';\nimport TabCoordinate from './TabCoordinate';\n\nexport interface UseTabCoordinates {\n coordinates: TabCoordinate[];\n updateCoordinate: (index: number, x: number, width: number) => void;\n}\n\nexport default function useTabCoordinates(tabElements: React.ReactNode): UseTabCoordinates {\n const incompleteCoordinatesRef = useRef<TabCoordinate[]>([]);\n\n const [completeCoordinates, setCompleteCoordinates] = useState<TabCoordinate[]>([]);\n\n const isAllCoordinatesDefined = (coordinates: TabCoordinate[]): boolean => {\n const numberOfTab = React.Children.count(tabElements);\n const numberOfCoordinates = coordinates.length;\n\n const everyCoordinatesDefined = isEveryDefined(coordinates);\n\n return numberOfTab === numberOfCoordinates && everyCoordinatesDefined;\n };\n\n const updateCoordinate = (index: number, x: number, width: number) => {\n incompleteCoordinatesRef.current[index] = { x1: x, x2: x + width };\n\n if (isAllCoordinatesDefined(incompleteCoordinatesRef.current)) {\n setCompleteCoordinates(incompleteCoordinatesRef.current);\n }\n };\n\n return {\n coordinates: completeCoordinates,\n updateCoordinate,\n };\n}\n"],"mappings":"AAAA,OAAOA,KAAP,IAAgBC,MAAhB,EAAwBC,QAAxB,QAAwC,OAAxC;AACA,SAASC,cAAT,QAA+B,oBAA/B;AAQA,eAAe,SAASC,iBAAT,CAA2BC,WAA3B,EAA4E;EACvF,MAAMC,wBAAwB,GAAGL,MAAM,CAAkB,EAAlB,CAAvC;EAEA,MAAM,CAACM,mBAAD,EAAsBC,sBAAtB,IAAgDN,QAAQ,CAAkB,EAAlB,CAA9D;;EAEA,MAAMO,uBAAuB,GAAIC,WAAD,IAA2C;IACvE,MAAMC,WAAW,GAAGX,KAAK,CAACY,QAAN,CAAeC,KAAf,CAAqBR,WAArB,CAApB;IACA,MAAMS,mBAAmB,GAAGJ,WAAW,CAACK,MAAxC;IAEA,MAAMC,uBAAuB,GAAGb,cAAc,CAACO,WAAD,CAA9C;IAEA,OAAOC,WAAW,KAAKG,mBAAhB,IAAuCE,uBAA9C;EACH,CAPD;;EASA,MAAMC,gBAAgB,GAAG,CAACC,KAAD,EAAgBC,CAAhB,EAA2BC,KAA3B,KAA6C;IAClEd,wBAAwB,CAACe,OAAzB,CAAiCH,KAAjC,IAA0C;MAAEI,EAAE,EAAEH,CAAN;MAASI,EAAE,EAAEJ,CAAC,GAAGC;IAAjB,CAA1C;;IAEA,IAAIX,uBAAuB,CAACH,wBAAwB,CAACe,OAA1B,CAA3B,EAA+D;MAC3Db,sBAAsB,CAACF,wBAAwB,CAACe,OAA1B,CAAtB;IACH;EACJ,CAND;;EAQA,OAAO;IACHX,WAAW,EAAEH,mBADV;IAEHU;EAFG,CAAP;AAIH"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { useCallback, useState } from 'react';
|
|
2
|
+
import { Dimensions } from 'react-native';
|
|
3
|
+
|
|
4
|
+
const assumeInitialWidth = () => Dimensions.get('window').width;
|
|
5
|
+
|
|
6
|
+
const isIntegerPartEquals = (a, b) => Math.round(a) === Math.round(b);
|
|
7
|
+
|
|
8
|
+
const isIntegerPartDifferent = (a, b) => !isIntegerPartEquals(a, b);
|
|
9
|
+
|
|
10
|
+
export default function useTabsWidth() {
|
|
11
|
+
const [width, setWidth] = useState(assumeInitialWidth);
|
|
12
|
+
const onLayout = useCallback(e => {
|
|
13
|
+
const newWidth = e.nativeEvent.layout.width;
|
|
14
|
+
setWidth(prevWidth => isIntegerPartDifferent(prevWidth, newWidth) ? newWidth : prevWidth);
|
|
15
|
+
}, []);
|
|
16
|
+
return [width, onLayout];
|
|
17
|
+
}
|
|
18
|
+
//# sourceMappingURL=useTabsWidth.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["useCallback","useState","Dimensions","assumeInitialWidth","get","width","isIntegerPartEquals","a","b","Math","round","isIntegerPartDifferent","useTabsWidth","setWidth","onLayout","e","newWidth","nativeEvent","layout","prevWidth"],"sources":["useTabsWidth.ts"],"sourcesContent":["import { useCallback, useState } from 'react';\nimport { Dimensions, LayoutChangeEvent, ViewProps } from 'react-native';\n\nconst assumeInitialWidth = (): number => Dimensions.get('window').width;\n\nconst isIntegerPartEquals = (a: number, b: number) => Math.round(a) === Math.round(b);\n\nconst isIntegerPartDifferent = (a: number, b: number) => !isIntegerPartEquals(a, b);\n\nexport default function useTabsWidth(): [number, ViewProps['onLayout']] {\n const [width, setWidth] = useState(assumeInitialWidth);\n\n const onLayout = useCallback((e: LayoutChangeEvent) => {\n const newWidth = e.nativeEvent.layout.width;\n\n setWidth((prevWidth) => isIntegerPartDifferent(prevWidth, newWidth) ? newWidth : prevWidth);\n }, []);\n\n return [width, onLayout];\n}\n"],"mappings":"AAAA,SAASA,WAAT,EAAsBC,QAAtB,QAAsC,OAAtC;AACA,SAASC,UAAT,QAAyD,cAAzD;;AAEA,MAAMC,kBAAkB,GAAG,MAAcD,UAAU,CAACE,GAAX,CAAe,QAAf,EAAyBC,KAAlE;;AAEA,MAAMC,mBAAmB,GAAG,CAACC,CAAD,EAAYC,CAAZ,KAA0BC,IAAI,CAACC,KAAL,CAAWH,CAAX,MAAkBE,IAAI,CAACC,KAAL,CAAWF,CAAX,CAAxE;;AAEA,MAAMG,sBAAsB,GAAG,CAACJ,CAAD,EAAYC,CAAZ,KAA0B,CAACF,mBAAmB,CAACC,CAAD,EAAIC,CAAJ,CAA7E;;AAEA,eAAe,SAASI,YAAT,GAAyD;EACpE,MAAM,CAACP,KAAD,EAAQQ,QAAR,IAAoBZ,QAAQ,CAACE,kBAAD,CAAlC;EAEA,MAAMW,QAAQ,GAAGd,WAAW,CAAEe,CAAD,IAA0B;IACnD,MAAMC,QAAQ,GAAGD,CAAC,CAACE,WAAF,CAAcC,MAAd,CAAqBb,KAAtC;IAEAQ,QAAQ,CAAEM,SAAD,IAAeR,sBAAsB,CAACQ,SAAD,EAAYH,QAAZ,CAAtB,GAA8CA,QAA9C,GAAyDG,SAAzE,CAAR;EACH,CAJ2B,EAIzB,EAJyB,CAA5B;EAMA,OAAO,CAACd,KAAD,EAAQS,QAAR,CAAP;AACH"}
|
|
@@ -28,21 +28,37 @@ export default function useCollapsibleAppBar() {
|
|
|
28
28
|
const overlapped = useSharedValue(false);
|
|
29
29
|
const elevationStyle = useElevationStyle(4);
|
|
30
30
|
const animatedStyle = useAnimatedStyle(() => {
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
31
|
+
if (Platform.OS === 'web') {
|
|
32
|
+
return {
|
|
33
|
+
transform: [{
|
|
34
|
+
translateY: translateY.value
|
|
35
|
+
}],
|
|
36
|
+
boxShadow: overlapped.value ? elevationStyle === null || elevationStyle === void 0 ? void 0 : elevationStyle.boxShadow : 0
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
if (Platform.OS === 'android') {
|
|
41
|
+
return {
|
|
42
|
+
transform: [{
|
|
43
|
+
translateY: translateY.value
|
|
44
|
+
}],
|
|
45
|
+
elevation: overlapped.value ? elevationStyle === null || elevationStyle === void 0 ? void 0 : elevationStyle.elevation : 0
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
if (Platform.OS === 'ios') {
|
|
50
|
+
return {
|
|
51
|
+
transform: [{
|
|
52
|
+
translateY: translateY.value
|
|
53
|
+
}],
|
|
54
|
+
shadowColor: elevationStyle === null || elevationStyle === void 0 ? void 0 : elevationStyle.shadowColor,
|
|
55
|
+
shadowOffset: elevationStyle === null || elevationStyle === void 0 ? void 0 : elevationStyle.shadowOffset,
|
|
56
|
+
shadowRadius: elevationStyle === null || elevationStyle === void 0 ? void 0 : elevationStyle.shadowRadius,
|
|
57
|
+
shadowOpacity: overlapped.value ? elevationStyle === null || elevationStyle === void 0 ? void 0 : elevationStyle.shadowOpacity : 0
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
return {};
|
|
46
62
|
});
|
|
47
63
|
const indexRef = React.useRef(0);
|
|
48
64
|
const offsetsRef = React.useRef([]);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["React","Keyboard","Platform","runOnJS","useAnimatedScrollHandler","useAnimatedStyle","useDerivedValue","useSharedValue","withTiming","useSafeAreaInsets","useHeight","useElevationStyle","useAppbarStyles","defaultOptions","keyboardDismissMode","ANIMATION_DURATION_MILLIS","SUPPORTS_DRAG_DETECTION","OS","useCollapsibleAppBar","userOptions","styles","safeAreaInsets","appBarHeight","onAppBarLayout","collapsibleToolbarHeight","onCollapsibleToolbarLayout","maxTranslateY","translateY","lastTranslateY","lastOffsetY","overlapped","elevationStyle","animatedStyle","transform","value","boxShadow","elevation","shadowColor","shadowOffset","shadowRadius","shadowOpacity","indexRef","useRef","offsetsRef","onScrollViewChanged","nextIndex","prevIndex","current","savedOffsetY","duration","scrollHandler","onBeginDrag","dismiss","onMomentumBegin","onScroll","event","offsetY","contentOffset","y","ty","maxTy","dy","Math","min","max","onEndDrag","onMomentumEnd","threshold","nextTranslateY","hasCollapsible","appBarStyle","paddingTop","top","floating","undefined","scrollContentInsets"],"sources":["useCollapsibleAppBar.ts"],"sourcesContent":["import React from 'react';\nimport { Falsy, Keyboard, Platform, RegisteredStyle, ScrollViewProps, ViewProps, ViewStyle } from 'react-native';\nimport {\n runOnJS,\n useAnimatedScrollHandler,\n useAnimatedStyle,\n useDerivedValue,\n useSharedValue,\n withTiming,\n} from 'react-native-reanimated';\nimport { useSafeAreaInsets } from 'react-native-safe-area-context';\nimport { useHeight } from '../internal/hooks';\nimport useElevationStyle from './useElevationStyle';\nimport useAppbarStyles from './useAppbarStyles';\n\ntype WebOnlyStyle = { boxShadow: any };\n\ntype ViewStyleProp = Array<ViewStyle | RegisteredStyle<ViewStyle> | WebOnlyStyle | Falsy>;\n\ntype OnScroll = ScrollViewProps['onScroll'];\n\ntype OnLayoutCallback = ViewProps['onLayout'];\n\nexport interface ContentInsets {\n top?: number;\n bottom?: number;\n left?: number;\n right?: number;\n}\n\nexport interface Options {\n keyboardDismissMode?: 'none' | 'on-drag';\n}\n\nexport interface CollapsibleAppBar {\n appBarStyle: ViewStyleProp;\n onAppBarLayout: OnLayoutCallback;\n onCollapsibleToolbarLayout: OnLayoutCallback;\n onScroll: OnScroll;\n onScrollViewChanged: (index: number) => void;\n scrollContentInsets: ContentInsets;\n}\n\nconst defaultOptions: Required<Options> = {\n keyboardDismissMode: 'none',\n};\n\nconst ANIMATION_DURATION_MILLIS = 100;\n\nconst SUPPORTS_DRAG_DETECTION = Platform.OS !== 'web';\n\nexport default function useCollapsibleAppBar(userOptions: Options = defaultOptions): CollapsibleAppBar {\n const { keyboardDismissMode }: Required<Options> = {\n ...defaultOptions,\n ...userOptions,\n };\n\n const styles = useAppbarStyles();\n\n const safeAreaInsets = useSafeAreaInsets();\n\n const [appBarHeight, onAppBarLayout] = useHeight();\n const [collapsibleToolbarHeight, onCollapsibleToolbarLayout] = useHeight();\n\n const maxTranslateY = useDerivedValue(() => -collapsibleToolbarHeight);\n\n const translateY = useSharedValue<number>(0);\n const lastTranslateY = useSharedValue<number>(0);\n const lastOffsetY = useSharedValue<number>(0);\n const overlapped = useSharedValue<boolean>(false);\n\n const elevationStyle = useElevationStyle(4);\n const animatedStyle = useAnimatedStyle(() => {\n return Platform.OS === 'web' ? ({\n transform: [{ translateY: translateY.value }],\n boxShadow: overlapped.value ? elevationStyle?.boxShadow : 0,\n }) : ({\n transform: [{ translateY: translateY.value }],\n elevation: overlapped.value ? elevationStyle?.elevation : 0,\n shadowColor: elevationStyle?.shadowColor,\n shadowOffset: elevationStyle?.shadowOffset,\n shadowRadius: elevationStyle?.shadowRadius,\n shadowOpacity: overlapped.value ? elevationStyle?.shadowOpacity : 0,\n });\n });\n\n const indexRef = React.useRef<number>(0);\n const offsetsRef = React.useRef<Array<number>>([]);\n\n const onScrollViewChanged = (nextIndex: number) => {\n const prevIndex = indexRef.current;\n if (prevIndex === nextIndex) {\n return;\n }\n\n offsetsRef.current[prevIndex] = lastOffsetY.value;\n\n const savedOffsetY = offsetsRef.current[nextIndex] ?? 0;\n lastOffsetY.value = savedOffsetY;\n\n indexRef.current = nextIndex;\n\n // Determine whether to overlap every time index is changed.\n overlapped.value = savedOffsetY > 0;\n\n // If next ScrollView's offset is too short, expand app bar.\n if (translateY.value < 0 && savedOffsetY < appBarHeight) {\n translateY.value = withTiming(0, {\n duration: ANIMATION_DURATION_MILLIS,\n });\n }\n };\n\n const scrollHandler = useAnimatedScrollHandler({\n onBeginDrag: () => {\n if (keyboardDismissMode === 'on-drag') {\n runOnJS(Keyboard.dismiss)();\n }\n lastTranslateY.value = translateY.value;\n },\n onMomentumBegin: () => {\n lastTranslateY.value = translateY.value;\n },\n onScroll: (event) => {\n const offsetY = event.contentOffset.y;\n\n const ty = translateY.value;\n const maxTy = maxTranslateY.value;\n\n if (SUPPORTS_DRAG_DETECTION) {\n const dy = offsetY - lastOffsetY.value;\n\n translateY.value = offsetY <= 0 ? 0 : Math.min(Math.max(lastTranslateY.value - dy, maxTy), 0);\n\n overlapped.value = offsetY + translateY.value > 0;\n } else {\n if (offsetY > -maxTy) {\n if (ty === 0) {\n translateY.value = withTiming(Math.min(Math.max(-offsetY, maxTy), 0), {\n duration: ANIMATION_DURATION_MILLIS,\n });\n }\n } else {\n if (ty === maxTy) {\n translateY.value = withTiming(0, {\n duration: ANIMATION_DURATION_MILLIS,\n });\n }\n }\n\n overlapped.value = offsetY > 0;\n\n lastOffsetY.value = offsetY;\n }\n },\n onEndDrag: (event) => {\n lastOffsetY.value = event.contentOffset.y;\n },\n onMomentumEnd: (event) => {\n const offsetY = event.contentOffset.y;\n\n lastOffsetY.value = offsetY;\n\n const ty = translateY.value;\n const maxTy = maxTranslateY.value;\n\n // If toolbar is already positioned on edge, do nothing.\n if (ty <= maxTy || ty >= 0) {\n return;\n }\n\n const threshold = maxTy * 0.5;\n\n const nextTranslateY = (ty > threshold || offsetY < appBarHeight) ? 0 : maxTy;\n\n overlapped.value = offsetY + nextTranslateY > 0;\n\n translateY.value = withTiming(nextTranslateY, {\n duration: ANIMATION_DURATION_MILLIS,\n });\n },\n });\n\n const hasCollapsible = collapsibleToolbarHeight > 0;\n\n const appBarStyle = [\n animatedStyle,\n { paddingTop: safeAreaInsets.top },\n hasCollapsible ? styles.floating : undefined,\n ];\n\n return {\n appBarStyle,\n onAppBarLayout,\n onCollapsibleToolbarLayout,\n onScroll: scrollHandler,\n onScrollViewChanged,\n scrollContentInsets: { top: hasCollapsible ? appBarHeight : 0 },\n };\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"names":["React","Keyboard","Platform","runOnJS","useAnimatedScrollHandler","useAnimatedStyle","useDerivedValue","useSharedValue","withTiming","useSafeAreaInsets","useHeight","useElevationStyle","useAppbarStyles","defaultOptions","keyboardDismissMode","ANIMATION_DURATION_MILLIS","SUPPORTS_DRAG_DETECTION","OS","useCollapsibleAppBar","userOptions","styles","safeAreaInsets","appBarHeight","onAppBarLayout","collapsibleToolbarHeight","onCollapsibleToolbarLayout","maxTranslateY","translateY","lastTranslateY","lastOffsetY","overlapped","elevationStyle","animatedStyle","transform","value","boxShadow","elevation","shadowColor","shadowOffset","shadowRadius","shadowOpacity","indexRef","useRef","offsetsRef","onScrollViewChanged","nextIndex","prevIndex","current","savedOffsetY","duration","scrollHandler","onBeginDrag","dismiss","onMomentumBegin","onScroll","event","offsetY","contentOffset","y","ty","maxTy","dy","Math","min","max","onEndDrag","onMomentumEnd","threshold","nextTranslateY","hasCollapsible","appBarStyle","paddingTop","top","floating","undefined","scrollContentInsets"],"sources":["useCollapsibleAppBar.ts"],"sourcesContent":["import React from 'react';\nimport { Falsy, Keyboard, Platform, RegisteredStyle, ScrollViewProps, ViewProps, ViewStyle } from 'react-native';\nimport {\n runOnJS,\n useAnimatedScrollHandler,\n useAnimatedStyle,\n useDerivedValue,\n useSharedValue,\n withTiming,\n} from 'react-native-reanimated';\nimport { useSafeAreaInsets } from 'react-native-safe-area-context';\nimport { useHeight } from '../internal/hooks';\nimport useElevationStyle from './useElevationStyle';\nimport useAppbarStyles from './useAppbarStyles';\n\ntype WebOnlyStyle = { boxShadow: any };\n\ntype ViewStyleProp = Array<ViewStyle | RegisteredStyle<ViewStyle> | WebOnlyStyle | Falsy>;\n\ntype OnScroll = ScrollViewProps['onScroll'];\n\ntype OnLayoutCallback = ViewProps['onLayout'];\n\nexport interface ContentInsets {\n top?: number;\n bottom?: number;\n left?: number;\n right?: number;\n}\n\nexport interface Options {\n keyboardDismissMode?: 'none' | 'on-drag';\n}\n\nexport interface CollapsibleAppBar {\n appBarStyle: ViewStyleProp;\n onAppBarLayout: OnLayoutCallback;\n onCollapsibleToolbarLayout: OnLayoutCallback;\n onScroll: OnScroll;\n onScrollViewChanged: (index: number) => void;\n scrollContentInsets: ContentInsets;\n}\n\nconst defaultOptions: Required<Options> = {\n keyboardDismissMode: 'none',\n};\n\nconst ANIMATION_DURATION_MILLIS = 100;\n\nconst SUPPORTS_DRAG_DETECTION = Platform.OS !== 'web';\n\nexport default function useCollapsibleAppBar(userOptions: Options = defaultOptions): CollapsibleAppBar {\n const { keyboardDismissMode }: Required<Options> = {\n ...defaultOptions,\n ...userOptions,\n };\n\n const styles = useAppbarStyles();\n\n const safeAreaInsets = useSafeAreaInsets();\n\n const [appBarHeight, onAppBarLayout] = useHeight();\n const [collapsibleToolbarHeight, onCollapsibleToolbarLayout] = useHeight();\n\n const maxTranslateY = useDerivedValue(() => -collapsibleToolbarHeight);\n\n const translateY = useSharedValue<number>(0);\n const lastTranslateY = useSharedValue<number>(0);\n const lastOffsetY = useSharedValue<number>(0);\n const overlapped = useSharedValue<boolean>(false);\n\n const elevationStyle = useElevationStyle(4);\n const animatedStyle = useAnimatedStyle(() => {\n if (Platform.OS === 'web') {\n return {\n transform: [{ translateY: translateY.value }],\n boxShadow: overlapped.value ? elevationStyle?.boxShadow : 0,\n };\n }\n if (Platform.OS === 'android') {\n return {\n transform: [{ translateY: translateY.value }],\n elevation: overlapped.value ? elevationStyle?.elevation : 0,\n };\n }\n if (Platform.OS === 'ios') {\n return {\n transform: [{ translateY: translateY.value }],\n shadowColor: elevationStyle?.shadowColor,\n shadowOffset: elevationStyle?.shadowOffset,\n shadowRadius: elevationStyle?.shadowRadius,\n shadowOpacity: overlapped.value ? elevationStyle?.shadowOpacity : 0,\n };\n }\n return {};\n });\n\n const indexRef = React.useRef<number>(0);\n const offsetsRef = React.useRef<Array<number>>([]);\n\n const onScrollViewChanged = (nextIndex: number) => {\n const prevIndex = indexRef.current;\n if (prevIndex === nextIndex) {\n return;\n }\n\n offsetsRef.current[prevIndex] = lastOffsetY.value;\n\n const savedOffsetY = offsetsRef.current[nextIndex] ?? 0;\n lastOffsetY.value = savedOffsetY;\n\n indexRef.current = nextIndex;\n\n // Determine whether to overlap every time index is changed.\n overlapped.value = savedOffsetY > 0;\n\n // If next ScrollView's offset is too short, expand app bar.\n if (translateY.value < 0 && savedOffsetY < appBarHeight) {\n translateY.value = withTiming(0, {\n duration: ANIMATION_DURATION_MILLIS,\n });\n }\n };\n\n const scrollHandler = useAnimatedScrollHandler({\n onBeginDrag: () => {\n if (keyboardDismissMode === 'on-drag') {\n runOnJS(Keyboard.dismiss)();\n }\n lastTranslateY.value = translateY.value;\n },\n onMomentumBegin: () => {\n lastTranslateY.value = translateY.value;\n },\n onScroll: (event) => {\n const offsetY = event.contentOffset.y;\n\n const ty = translateY.value;\n const maxTy = maxTranslateY.value;\n\n if (SUPPORTS_DRAG_DETECTION) {\n const dy = offsetY - lastOffsetY.value;\n\n translateY.value = offsetY <= 0 ? 0 : Math.min(Math.max(lastTranslateY.value - dy, maxTy), 0);\n\n overlapped.value = offsetY + translateY.value > 0;\n } else {\n if (offsetY > -maxTy) {\n if (ty === 0) {\n translateY.value = withTiming(Math.min(Math.max(-offsetY, maxTy), 0), {\n duration: ANIMATION_DURATION_MILLIS,\n });\n }\n } else {\n if (ty === maxTy) {\n translateY.value = withTiming(0, {\n duration: ANIMATION_DURATION_MILLIS,\n });\n }\n }\n\n overlapped.value = offsetY > 0;\n\n lastOffsetY.value = offsetY;\n }\n },\n onEndDrag: (event) => {\n lastOffsetY.value = event.contentOffset.y;\n },\n onMomentumEnd: (event) => {\n const offsetY = event.contentOffset.y;\n\n lastOffsetY.value = offsetY;\n\n const ty = translateY.value;\n const maxTy = maxTranslateY.value;\n\n // If toolbar is already positioned on edge, do nothing.\n if (ty <= maxTy || ty >= 0) {\n return;\n }\n\n const threshold = maxTy * 0.5;\n\n const nextTranslateY = (ty > threshold || offsetY < appBarHeight) ? 0 : maxTy;\n\n overlapped.value = offsetY + nextTranslateY > 0;\n\n translateY.value = withTiming(nextTranslateY, {\n duration: ANIMATION_DURATION_MILLIS,\n });\n },\n });\n\n const hasCollapsible = collapsibleToolbarHeight > 0;\n\n const appBarStyle = [\n animatedStyle,\n { paddingTop: safeAreaInsets.top },\n hasCollapsible ? styles.floating : undefined,\n ];\n\n return {\n appBarStyle,\n onAppBarLayout,\n onCollapsibleToolbarLayout,\n onScroll: scrollHandler,\n onScrollViewChanged,\n scrollContentInsets: { top: hasCollapsible ? appBarHeight : 0 },\n };\n};\n"],"mappings":"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"}
|
|
@@ -40,14 +40,32 @@ export default function useFadeInAppBar() {
|
|
|
40
40
|
const normalized = useSharedValue(0);
|
|
41
41
|
const backgroundColor = theme.palette.background.default;
|
|
42
42
|
const [r, g, b] = React.useMemo(() => rgb(backgroundColor), [backgroundColor]);
|
|
43
|
-
const animatedAppBarStyle = useAnimatedStyle(() =>
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
43
|
+
const animatedAppBarStyle = useAnimatedStyle(() => {
|
|
44
|
+
if (Platform.OS === 'web') {
|
|
45
|
+
return {
|
|
46
|
+
backgroundColor: `rgba(${r}, ${g}, ${b}, ${normalized.value})`
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
if (Platform.OS === 'android') {
|
|
51
|
+
return {
|
|
52
|
+
backgroundColor: `rgba(${r}, ${g}, ${b}, ${normalized.value})`,
|
|
53
|
+
elevation: normalized.value >= 1 ? 6 : 0
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
if (Platform.OS === 'ios') {
|
|
58
|
+
return {
|
|
59
|
+
backgroundColor: `rgba(${r}, ${g}, ${b}, ${normalized.value})`,
|
|
60
|
+
shadowColor: '#000',
|
|
61
|
+
shadowOffset,
|
|
62
|
+
shadowRadius: 4.65,
|
|
63
|
+
shadowOpacity: normalized.value >= 1 ? 0.25 : 0
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
return {};
|
|
68
|
+
});
|
|
51
69
|
const animatedTitleStyle = useAnimatedStyle(() => ({
|
|
52
70
|
opacity: normalized.value
|
|
53
71
|
}));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["React","Keyboard","Platform","runOnJS","useAnimatedScrollHandler","useAnimatedStyle","useSharedValue","useSafeAreaInsets","rgb","useHeight","useTheme","useAppbarStyles","defaultOptions","fadeInBeginY","endY","appBarHeight","fadeInEndY","floating","keyboardDismissMode","shadowOffset","OS","width","height","undefined","useFadeInAppBar","userOptions","theme","styles","safeAreaInsets","onAppBarLayout","fromOffsetY","toOffsetY","useMemo","beginY","dy","lastOffsetY","normalized","backgroundColor","palette","background","default","r","g","b","animatedAppBarStyle","value","elevation","shadowColor","shadowRadius","shadowOpacity","animatedTitleStyle","opacity","scrollHandler","onBeginDrag","dismiss","onScroll","event","offsetY","contentOffset","y","distance","Math","max","localOffsetY","min","onEndDrag","onMomentumEnd","appBarStyle","paddingTop","top","titleStyle"],"sources":["useFadeInAppBar.ts"],"sourcesContent":["import React from 'react';\nimport { Falsy, Keyboard, Platform, RegisteredStyle, ScrollViewProps, ViewProps, ViewStyle } from 'react-native';\nimport type { SharedValue } from 'react-native-reanimated';\nimport { runOnJS, useAnimatedScrollHandler, useAnimatedStyle, useSharedValue } from 'react-native-reanimated';\nimport { useSafeAreaInsets } from 'react-native-safe-area-context';\nimport { rgb } from '@fountain-ui/utils';\nimport { useHeight } from '../internal/hooks';\nimport { useTheme } from '../styles';\nimport useAppbarStyles from './useAppbarStyles';\n\ntype ViewStyleProp = Array<ViewStyle | RegisteredStyle<ViewStyle> | Falsy>;\n\ntype OnScroll = ScrollViewProps['onScroll'];\n\ntype OnLayoutCallback = ViewProps['onLayout'];\n\nexport interface Options {\n fadeInBeginY?: number | ((endY: number, appBarHeight: number) => number);\n fadeInEndY?: number | ((appBarHeight: number) => number);\n floating?: boolean;\n keyboardDismissMode?: 'none' | 'on-drag';\n}\n\nexport interface FadeInAppBar {\n appBarStyle: ViewStyleProp;\n titleStyle: ViewStyleProp;\n onAppBarLayout: OnLayoutCallback;\n onScroll: OnScroll;\n dy: SharedValue<number>;\n normalized: SharedValue<number>;\n}\n\nconst defaultOptions: Required<Options> = {\n fadeInBeginY: (endY, appBarHeight) => endY - appBarHeight,\n fadeInEndY: (appBarHeight) => appBarHeight,\n floating: true,\n keyboardDismissMode: 'none',\n};\n\nconst shadowOffset = Platform.OS === 'ios' ? { width: 0, height: 3 } : undefined;\n\nexport default function useFadeInAppBar(userOptions: Options = defaultOptions): FadeInAppBar {\n const {\n fadeInBeginY,\n fadeInEndY,\n floating,\n keyboardDismissMode,\n }: Required<Options> = {\n ...defaultOptions,\n ...userOptions,\n };\n\n const theme = useTheme();\n\n const styles = useAppbarStyles();\n\n const safeAreaInsets = useSafeAreaInsets();\n\n const [appBarHeight, onAppBarLayout] = useHeight();\n\n const [fromOffsetY, toOffsetY] = React.useMemo(() => {\n const endY = typeof fadeInEndY === 'function'\n ? fadeInEndY(appBarHeight)\n : fadeInEndY;\n\n const beginY = typeof fadeInBeginY === 'function'\n ? fadeInBeginY(endY, appBarHeight)\n : fadeInBeginY;\n\n return [beginY, endY];\n }, [fadeInBeginY, fadeInBeginY, appBarHeight]);\n\n const dy = useSharedValue<number>(0);\n const lastOffsetY = useSharedValue<number>(0);\n const normalized = useSharedValue<number>(0);\n\n const backgroundColor = theme.palette.background.default;\n const [r, g, b] = React.useMemo(() => rgb(backgroundColor), [backgroundColor]);\n\n const animatedAppBarStyle = useAnimatedStyle(() => ({\n backgroundColor: `rgba(${r}, ${g}, ${b}, ${normalized.value})`,\n
|
|
1
|
+
{"version":3,"names":["React","Keyboard","Platform","runOnJS","useAnimatedScrollHandler","useAnimatedStyle","useSharedValue","useSafeAreaInsets","rgb","useHeight","useTheme","useAppbarStyles","defaultOptions","fadeInBeginY","endY","appBarHeight","fadeInEndY","floating","keyboardDismissMode","shadowOffset","OS","width","height","undefined","useFadeInAppBar","userOptions","theme","styles","safeAreaInsets","onAppBarLayout","fromOffsetY","toOffsetY","useMemo","beginY","dy","lastOffsetY","normalized","backgroundColor","palette","background","default","r","g","b","animatedAppBarStyle","value","elevation","shadowColor","shadowRadius","shadowOpacity","animatedTitleStyle","opacity","scrollHandler","onBeginDrag","dismiss","onScroll","event","offsetY","contentOffset","y","distance","Math","max","localOffsetY","min","onEndDrag","onMomentumEnd","appBarStyle","paddingTop","top","titleStyle"],"sources":["useFadeInAppBar.ts"],"sourcesContent":["import React from 'react';\nimport { Falsy, Keyboard, Platform, RegisteredStyle, ScrollViewProps, ViewProps, ViewStyle } from 'react-native';\nimport type { SharedValue } from 'react-native-reanimated';\nimport { runOnJS, useAnimatedScrollHandler, useAnimatedStyle, useSharedValue } from 'react-native-reanimated';\nimport { useSafeAreaInsets } from 'react-native-safe-area-context';\nimport { rgb } from '@fountain-ui/utils';\nimport { useHeight } from '../internal/hooks';\nimport { useTheme } from '../styles';\nimport useAppbarStyles from './useAppbarStyles';\n\ntype ViewStyleProp = Array<ViewStyle | RegisteredStyle<ViewStyle> | Falsy>;\n\ntype OnScroll = ScrollViewProps['onScroll'];\n\ntype OnLayoutCallback = ViewProps['onLayout'];\n\nexport interface Options {\n fadeInBeginY?: number | ((endY: number, appBarHeight: number) => number);\n fadeInEndY?: number | ((appBarHeight: number) => number);\n floating?: boolean;\n keyboardDismissMode?: 'none' | 'on-drag';\n}\n\nexport interface FadeInAppBar {\n appBarStyle: ViewStyleProp;\n titleStyle: ViewStyleProp;\n onAppBarLayout: OnLayoutCallback;\n onScroll: OnScroll;\n dy: SharedValue<number>;\n normalized: SharedValue<number>;\n}\n\nconst defaultOptions: Required<Options> = {\n fadeInBeginY: (endY, appBarHeight) => endY - appBarHeight,\n fadeInEndY: (appBarHeight) => appBarHeight,\n floating: true,\n keyboardDismissMode: 'none',\n};\n\nconst shadowOffset = Platform.OS === 'ios' ? { width: 0, height: 3 } : undefined;\n\nexport default function useFadeInAppBar(userOptions: Options = defaultOptions): FadeInAppBar {\n const {\n fadeInBeginY,\n fadeInEndY,\n floating,\n keyboardDismissMode,\n }: Required<Options> = {\n ...defaultOptions,\n ...userOptions,\n };\n\n const theme = useTheme();\n\n const styles = useAppbarStyles();\n\n const safeAreaInsets = useSafeAreaInsets();\n\n const [appBarHeight, onAppBarLayout] = useHeight();\n\n const [fromOffsetY, toOffsetY] = React.useMemo(() => {\n const endY = typeof fadeInEndY === 'function'\n ? fadeInEndY(appBarHeight)\n : fadeInEndY;\n\n const beginY = typeof fadeInBeginY === 'function'\n ? fadeInBeginY(endY, appBarHeight)\n : fadeInBeginY;\n\n return [beginY, endY];\n }, [fadeInBeginY, fadeInBeginY, appBarHeight]);\n\n const dy = useSharedValue<number>(0);\n const lastOffsetY = useSharedValue<number>(0);\n const normalized = useSharedValue<number>(0);\n\n const backgroundColor = theme.palette.background.default;\n const [r, g, b] = React.useMemo(() => rgb(backgroundColor), [backgroundColor]);\n\n const animatedAppBarStyle = useAnimatedStyle(() => {\n if (Platform.OS === 'web') {\n return {\n backgroundColor: `rgba(${r}, ${g}, ${b}, ${normalized.value})`,\n };\n }\n if (Platform.OS === 'android') {\n return {\n backgroundColor: `rgba(${r}, ${g}, ${b}, ${normalized.value})`,\n elevation: normalized.value >= 1 ? 6 : 0,\n };\n }\n if (Platform.OS === 'ios') {\n return {\n backgroundColor: `rgba(${r}, ${g}, ${b}, ${normalized.value})`,\n shadowColor: '#000',\n shadowOffset,\n shadowRadius: 4.65,\n shadowOpacity: normalized.value >= 1 ? 0.25 : 0,\n };\n }\n return {};\n });\n\n const animatedTitleStyle = useAnimatedStyle(() => ({\n opacity: normalized.value,\n }));\n\n const scrollHandler = useAnimatedScrollHandler({\n onBeginDrag: () => {\n if (keyboardDismissMode === 'on-drag') {\n runOnJS(Keyboard.dismiss)();\n }\n },\n onScroll: (event) => {\n const offsetY = event.contentOffset.y;\n\n const distance = Math.max(toOffsetY - fromOffsetY, 1);\n const localOffsetY = offsetY - fromOffsetY;\n\n dy.value = offsetY - lastOffsetY.value;\n\n normalized.value = Math.min(Math.max(localOffsetY / distance, 0), 1);\n },\n onEndDrag: (event) => {\n lastOffsetY.value = event.contentOffset.y;\n },\n onMomentumEnd: (event) => {\n lastOffsetY.value = event.contentOffset.y;\n },\n });\n\n const appBarStyle = [\n animatedAppBarStyle,\n { paddingTop: safeAreaInsets.top },\n floating ? styles.floating : undefined,\n ];\n\n return {\n appBarStyle,\n titleStyle: [animatedTitleStyle],\n onAppBarLayout,\n onScroll: scrollHandler,\n dy,\n normalized,\n };\n};\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["default","useHeight"
|
|
1
|
+
{"version":3,"names":["default","useHeight"],"sources":["index.ts"],"sourcesContent":["export { default as useHeight } from './useHeight';\n"],"mappings":"AAAA,SAASA,OAAO,IAAIC,SAApB,QAAqC,aAArC"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import TabCoordinate from './TabCoordinate';
|
|
3
|
+
export interface UseTabCoordinates {
|
|
4
|
+
coordinates: TabCoordinate[];
|
|
5
|
+
updateCoordinate: (index: number, x: number, width: number) => void;
|
|
6
|
+
}
|
|
7
|
+
export default function useTabCoordinates(tabElements: React.ReactNode): UseTabCoordinates;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fountain-ui/core",
|
|
3
|
-
"version": "2.0.0-beta.
|
|
3
|
+
"version": "2.0.0-beta.11",
|
|
4
4
|
"author": "Fountain-UI Team",
|
|
5
5
|
"description": "React components that implement Tappytoon's Fountain Design.",
|
|
6
6
|
"license": "MIT",
|
|
@@ -67,5 +67,5 @@
|
|
|
67
67
|
"publishConfig": {
|
|
68
68
|
"access": "public"
|
|
69
69
|
},
|
|
70
|
-
"gitHead": "
|
|
70
|
+
"gitHead": "3de48896d62f1ba687558ea11b5f527cb91b5da6"
|
|
71
71
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import Animated, { useAnimatedStyle
|
|
2
|
+
import Animated, { useAnimatedStyle } from 'react-native-reanimated';
|
|
3
3
|
import { NamedStylesStringUnion, UseStyles } from '@fountain-ui/styles';
|
|
4
4
|
import { useTheme } from '../styles';
|
|
5
5
|
import type TabIndicatorProps from './TabIndicatorProps';
|
|
@@ -35,8 +35,9 @@ export default function TabIndicator(props: TabIndicatorProps) {
|
|
|
35
35
|
|
|
36
36
|
const styles = useStyles();
|
|
37
37
|
|
|
38
|
-
const
|
|
38
|
+
const animatedStyle = useAnimatedStyle(() => {
|
|
39
39
|
const rawScrollValue = scrollValue.value;
|
|
40
|
+
|
|
40
41
|
const index = Math.floor(rawScrollValue);
|
|
41
42
|
const offset = rawScrollValue % 1;
|
|
42
43
|
|
|
@@ -55,11 +56,6 @@ export default function TabIndicator(props: TabIndicatorProps) {
|
|
|
55
56
|
};
|
|
56
57
|
});
|
|
57
58
|
|
|
58
|
-
const animatedStyle = useAnimatedStyle(() => ({
|
|
59
|
-
left: layout.value.left,
|
|
60
|
-
width: layout.value.width,
|
|
61
|
-
}));
|
|
62
|
-
|
|
63
59
|
return (
|
|
64
60
|
<Animated.View
|
|
65
61
|
style={[
|