@fountain-ui/core 2.0.0-beta.13 → 2.0.0-beta.14

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.
Files changed (47) hide show
  1. package/build/commonjs/Tab/Tab.js +9 -5
  2. package/build/commonjs/Tab/Tab.js.map +1 -1
  3. package/build/commonjs/Tabs/IndexAwareTab.js +28 -0
  4. package/build/commonjs/Tabs/IndexAwareTab.js.map +1 -0
  5. package/build/commonjs/Tabs/TabIndicator.js +18 -12
  6. package/build/commonjs/Tabs/TabIndicator.js.map +1 -1
  7. package/build/commonjs/Tabs/TabIndicatorProps.js.map +1 -1
  8. package/build/commonjs/Tabs/Tabs.js +41 -61
  9. package/build/commonjs/Tabs/Tabs.js.map +1 -1
  10. package/build/commonjs/Tabs/TabsProps.js.map +1 -1
  11. package/build/commonjs/Tabs/index.js.map +1 -1
  12. package/build/commonjs/Tabs/useScrollViewReaction.js +54 -0
  13. package/build/commonjs/Tabs/useScrollViewReaction.js.map +1 -0
  14. package/build/module/Tab/Tab.js +5 -5
  15. package/build/module/Tab/Tab.js.map +1 -1
  16. package/build/module/Tabs/IndexAwareTab.js +18 -0
  17. package/build/module/Tabs/IndexAwareTab.js.map +1 -0
  18. package/build/module/Tabs/TabIndicator.js +18 -13
  19. package/build/module/Tabs/TabIndicator.js.map +1 -1
  20. package/build/module/Tabs/TabIndicatorProps.js.map +1 -1
  21. package/build/module/Tabs/Tabs.js +40 -60
  22. package/build/module/Tabs/Tabs.js.map +1 -1
  23. package/build/module/Tabs/TabsProps.js.map +1 -1
  24. package/build/module/Tabs/index.js.map +1 -1
  25. package/build/module/Tabs/useScrollViewReaction.js +44 -0
  26. package/build/module/Tabs/useScrollViewReaction.js.map +1 -0
  27. package/build/typescript/Tabs/IndexAwareTab.d.ts +9 -0
  28. package/build/typescript/Tabs/TabIndicatorProps.d.ts +2 -2
  29. package/build/typescript/Tabs/Tabs.d.ts +4 -1
  30. package/build/typescript/Tabs/TabsProps.d.ts +19 -11
  31. package/build/typescript/Tabs/index.d.ts +1 -1
  32. package/build/typescript/Tabs/useScrollViewReaction.d.ts +9 -0
  33. package/package.json +2 -2
  34. package/src/Tab/Tab.tsx +5 -5
  35. package/src/Tabs/IndexAwareTab.tsx +30 -0
  36. package/src/Tabs/TabIndicator.tsx +17 -13
  37. package/src/Tabs/TabIndicatorProps.ts +2 -2
  38. package/src/Tabs/Tabs.tsx +47 -62
  39. package/src/Tabs/TabsProps.ts +22 -12
  40. package/src/Tabs/index.ts +1 -1
  41. package/src/Tabs/useScrollViewReaction.ts +55 -0
  42. package/build/commonjs/Tabs/useTabsWidth.js +0 -26
  43. package/build/commonjs/Tabs/useTabsWidth.js.map +0 -1
  44. package/build/module/Tabs/useTabsWidth.js +0 -18
  45. package/build/module/Tabs/useTabsWidth.js.map +0 -1
  46. package/build/typescript/Tabs/useTabsWidth.d.ts +0 -2
  47. package/src/Tabs/useTabsWidth.ts +0 -20
@@ -1,7 +1,7 @@
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
3
  import React from 'react';
4
- import Animated, { useAnimatedStyle } from 'react-native-reanimated';
4
+ import Animated, { Easing, useAnimatedStyle, withTiming } from 'react-native-reanimated';
5
5
  import { useTheme } from '../styles';
6
6
  import { defaultCoordinate } from './TabCoordinate';
7
7
 
@@ -20,29 +20,34 @@ const useStyles = function () {
20
20
  };
21
21
  };
22
22
 
23
+ const ANIMATION_CONFIG = {
24
+ duration: 200,
25
+ easing: Easing.out(Easing.exp)
26
+ };
23
27
  export default function TabIndicator(props) {
24
28
  const {
25
29
  coordinates,
26
30
  disabled,
27
31
  scrollable,
28
- scrollValue,
32
+ sharedIndex,
29
33
  style,
30
34
  ...otherProps
31
35
  } = props;
32
36
  const styles = useStyles();
33
37
  const animatedStyle = useAnimatedStyle(() => {
34
- const rawScrollValue = scrollValue.value;
35
- const index = Math.floor(rawScrollValue);
36
- const offset = rawScrollValue % 1;
37
- const coordinate = coordinates[index] ?? defaultCoordinate;
38
- const nextCoordinate = coordinates[index + 1] ?? defaultCoordinate;
39
- const x1 = offset * nextCoordinate.x1 + (1 - offset) * coordinate.x1;
40
- const x2 = offset * nextCoordinate.x2 + (1 - offset) * coordinate.x2;
41
- const leftInset = scrollable ? 12 : 0;
42
- const rightInset = scrollable ? 24 : 0;
38
+ const index = sharedIndex.value;
39
+ const {
40
+ x1,
41
+ x2
42
+ } = coordinates[index] ?? defaultCoordinate;
43
+ const tabWidth = x2 - x1;
44
+ const singleInset = scrollable ? 12 : 0;
45
+ const totalInset = singleInset * 2;
46
+ const nextLeft = x1 + singleInset;
47
+ const nextWidth = tabWidth - totalInset;
43
48
  return {
44
- left: x1 + leftInset,
45
- width: Math.max(x2 - x1 - rightInset, 0)
49
+ left: withTiming(nextLeft, ANIMATION_CONFIG),
50
+ width: withTiming(nextWidth, ANIMATION_CONFIG)
46
51
  };
47
52
  }, [coordinates, scrollable]);
48
53
  return /*#__PURE__*/React.createElement(Animated.View, _extends({
@@ -1 +1 @@
1
- {"version":3,"names":["React","Animated","useAnimatedStyle","useTheme","defaultCoordinate","useStyles","theme","root","backgroundColor","palette","secondary","main","bottom","height","position","disabled","TabIndicator","props","coordinates","scrollable","scrollValue","style","otherProps","styles","animatedStyle","rawScrollValue","value","index","Math","floor","offset","coordinate","nextCoordinate","x1","x2","leftInset","rightInset","left","width","max","undefined"],"sources":["TabIndicator.tsx"],"sourcesContent":["import React from 'react';\nimport Animated, { useAnimatedStyle } from 'react-native-reanimated';\nimport { NamedStylesStringUnion, UseStyles } from '@fountain-ui/styles';\nimport { useTheme } from '../styles';\nimport type TabIndicatorProps from './TabIndicatorProps';\nimport { defaultCoordinate } from './TabCoordinate';\n\ntype TabIndicatorStyles = NamedStylesStringUnion<'root' | 'disabled'>;\n\nconst useStyles: UseStyles<TabIndicatorStyles> = function (): TabIndicatorStyles {\n const theme = useTheme();\n\n return {\n root: {\n backgroundColor: theme.palette.secondary.main,\n bottom: 0,\n height: 4,\n position: 'absolute',\n },\n disabled: {\n height: 0,\n },\n };\n};\n\nexport default function TabIndicator(props: TabIndicatorProps) {\n const {\n coordinates,\n disabled,\n scrollable,\n scrollValue,\n style,\n ...otherProps\n } = props;\n\n const styles = useStyles();\n\n const animatedStyle = useAnimatedStyle(() => {\n const rawScrollValue = scrollValue.value;\n\n const index = Math.floor(rawScrollValue);\n const offset = rawScrollValue % 1;\n\n const coordinate = coordinates[index] ?? defaultCoordinate;\n const nextCoordinate = coordinates[index + 1] ?? defaultCoordinate;\n\n const x1 = (offset * nextCoordinate.x1 + (1 - offset) * coordinate.x1);\n const x2 = (offset * nextCoordinate.x2 + (1 - offset) * coordinate.x2);\n\n const leftInset = scrollable ? 12 : 0;\n const rightInset = scrollable ? 24 : 0;\n\n return {\n left: x1 + leftInset,\n width: Math.max(x2 - x1 - rightInset, 0),\n };\n }, [coordinates, scrollable]);\n\n return (\n <Animated.View\n style={[\n styles.root,\n disabled ? styles.disabled : undefined,\n animatedStyle,\n style,\n ]}\n {...otherProps}\n />\n );\n};\n"],"mappings":";;AAAA,OAAOA,KAAP,MAAkB,OAAlB;AACA,OAAOC,QAAP,IAAmBC,gBAAnB,QAA2C,yBAA3C;AAEA,SAASC,QAAT,QAAyB,WAAzB;AAEA,SAASC,iBAAT,QAAkC,iBAAlC;;AAIA,MAAMC,SAAwC,GAAG,YAAgC;EAC7E,MAAMC,KAAK,GAAGH,QAAQ,EAAtB;EAEA,OAAO;IACHI,IAAI,EAAE;MACFC,eAAe,EAAEF,KAAK,CAACG,OAAN,CAAcC,SAAd,CAAwBC,IADvC;MAEFC,MAAM,EAAE,CAFN;MAGFC,MAAM,EAAE,CAHN;MAIFC,QAAQ,EAAE;IAJR,CADH;IAOHC,QAAQ,EAAE;MACNF,MAAM,EAAE;IADF;EAPP,CAAP;AAWH,CAdD;;AAgBA,eAAe,SAASG,YAAT,CAAsBC,KAAtB,EAAgD;EAC3D,MAAM;IACFC,WADE;IAEFH,QAFE;IAGFI,UAHE;IAIFC,WAJE;IAKFC,KALE;IAMF,GAAGC;EAND,IAOFL,KAPJ;EASA,MAAMM,MAAM,GAAGlB,SAAS,EAAxB;EAEA,MAAMmB,aAAa,GAAGtB,gBAAgB,CAAC,MAAM;IACzC,MAAMuB,cAAc,GAAGL,WAAW,CAACM,KAAnC;IAEA,MAAMC,KAAK,GAAGC,IAAI,CAACC,KAAL,CAAWJ,cAAX,CAAd;IACA,MAAMK,MAAM,GAAGL,cAAc,GAAG,CAAhC;IAEA,MAAMM,UAAU,GAAGb,WAAW,CAACS,KAAD,CAAX,IAAsBvB,iBAAzC;IACA,MAAM4B,cAAc,GAAGd,WAAW,CAACS,KAAK,GAAG,CAAT,CAAX,IAA0BvB,iBAAjD;IAEA,MAAM6B,EAAE,GAAIH,MAAM,GAAGE,cAAc,CAACC,EAAxB,GAA6B,CAAC,IAAIH,MAAL,IAAeC,UAAU,CAACE,EAAnE;IACA,MAAMC,EAAE,GAAIJ,MAAM,GAAGE,cAAc,CAACE,EAAxB,GAA6B,CAAC,IAAIJ,MAAL,IAAeC,UAAU,CAACG,EAAnE;IAEA,MAAMC,SAAS,GAAGhB,UAAU,GAAG,EAAH,GAAQ,CAApC;IACA,MAAMiB,UAAU,GAAGjB,UAAU,GAAG,EAAH,GAAQ,CAArC;IAEA,OAAO;MACHkB,IAAI,EAAEJ,EAAE,GAAGE,SADR;MAEHG,KAAK,EAAEV,IAAI,CAACW,GAAL,CAASL,EAAE,GAAGD,EAAL,GAAUG,UAAnB,EAA+B,CAA/B;IAFJ,CAAP;EAIH,CAnBqC,EAmBnC,CAAClB,WAAD,EAAcC,UAAd,CAnBmC,CAAtC;EAqBA,oBACI,oBAAC,QAAD,CAAU,IAAV;IACI,KAAK,EAAE,CACHI,MAAM,CAAChB,IADJ,EAEHQ,QAAQ,GAAGQ,MAAM,CAACR,QAAV,GAAqByB,SAF1B,EAGHhB,aAHG,EAIHH,KAJG;EADX,GAOQC,UAPR,EADJ;AAWH;AAAA"}
1
+ {"version":3,"names":["React","Animated","Easing","useAnimatedStyle","withTiming","useTheme","defaultCoordinate","useStyles","theme","root","backgroundColor","palette","secondary","main","bottom","height","position","disabled","ANIMATION_CONFIG","duration","easing","out","exp","TabIndicator","props","coordinates","scrollable","sharedIndex","style","otherProps","styles","animatedStyle","index","value","x1","x2","tabWidth","singleInset","totalInset","nextLeft","nextWidth","left","width","undefined"],"sources":["TabIndicator.tsx"],"sourcesContent":["import React from 'react';\nimport type { WithTimingConfig } from 'react-native-reanimated';\nimport Animated, { Easing, useAnimatedStyle, withTiming } from 'react-native-reanimated';\nimport { NamedStylesStringUnion, UseStyles } from '@fountain-ui/styles';\nimport { useTheme } from '../styles';\nimport type TabIndicatorProps from './TabIndicatorProps';\nimport { defaultCoordinate } from './TabCoordinate';\n\ntype TabIndicatorStyles = NamedStylesStringUnion<'root' | 'disabled'>;\n\nconst useStyles: UseStyles<TabIndicatorStyles> = function (): TabIndicatorStyles {\n const theme = useTheme();\n\n return {\n root: {\n backgroundColor: theme.palette.secondary.main,\n bottom: 0,\n height: 4,\n position: 'absolute',\n },\n disabled: {\n height: 0,\n },\n };\n};\n\nconst ANIMATION_CONFIG: Readonly<WithTimingConfig> = {\n duration: 200,\n easing: Easing.out(Easing.exp),\n};\n\nexport default function TabIndicator(props: TabIndicatorProps) {\n const {\n coordinates,\n disabled,\n scrollable,\n sharedIndex,\n style,\n ...otherProps\n } = props;\n\n const styles = useStyles();\n\n const animatedStyle = useAnimatedStyle(() => {\n const index = sharedIndex.value;\n\n const { x1, x2 } = coordinates[index] ?? defaultCoordinate;\n\n const tabWidth = x2 - x1;\n\n const singleInset = scrollable ? 12 : 0;\n const totalInset = singleInset * 2;\n\n const nextLeft = x1 + singleInset;\n const nextWidth = tabWidth - totalInset;\n\n return {\n left: withTiming(nextLeft, ANIMATION_CONFIG),\n width: withTiming(nextWidth, ANIMATION_CONFIG),\n };\n }, [coordinates, scrollable]);\n\n return (\n <Animated.View\n style={[\n styles.root,\n disabled ? styles.disabled : undefined,\n animatedStyle,\n style,\n ]}\n {...otherProps}\n />\n );\n};\n"],"mappings":";;AAAA,OAAOA,KAAP,MAAkB,OAAlB;AAEA,OAAOC,QAAP,IAAmBC,MAAnB,EAA2BC,gBAA3B,EAA6CC,UAA7C,QAA+D,yBAA/D;AAEA,SAASC,QAAT,QAAyB,WAAzB;AAEA,SAASC,iBAAT,QAAkC,iBAAlC;;AAIA,MAAMC,SAAwC,GAAG,YAAgC;EAC7E,MAAMC,KAAK,GAAGH,QAAQ,EAAtB;EAEA,OAAO;IACHI,IAAI,EAAE;MACFC,eAAe,EAAEF,KAAK,CAACG,OAAN,CAAcC,SAAd,CAAwBC,IADvC;MAEFC,MAAM,EAAE,CAFN;MAGFC,MAAM,EAAE,CAHN;MAIFC,QAAQ,EAAE;IAJR,CADH;IAOHC,QAAQ,EAAE;MACNF,MAAM,EAAE;IADF;EAPP,CAAP;AAWH,CAdD;;AAgBA,MAAMG,gBAA4C,GAAG;EACjDC,QAAQ,EAAE,GADuC;EAEjDC,MAAM,EAAElB,MAAM,CAACmB,GAAP,CAAWnB,MAAM,CAACoB,GAAlB;AAFyC,CAArD;AAKA,eAAe,SAASC,YAAT,CAAsBC,KAAtB,EAAgD;EAC3D,MAAM;IACFC,WADE;IAEFR,QAFE;IAGFS,UAHE;IAIFC,WAJE;IAKFC,KALE;IAMF,GAAGC;EAND,IAOFL,KAPJ;EASA,MAAMM,MAAM,GAAGvB,SAAS,EAAxB;EAEA,MAAMwB,aAAa,GAAG5B,gBAAgB,CAAC,MAAM;IACzC,MAAM6B,KAAK,GAAGL,WAAW,CAACM,KAA1B;IAEA,MAAM;MAAEC,EAAF;MAAMC;IAAN,IAAaV,WAAW,CAACO,KAAD,CAAX,IAAsB1B,iBAAzC;IAEA,MAAM8B,QAAQ,GAAGD,EAAE,GAAGD,EAAtB;IAEA,MAAMG,WAAW,GAAGX,UAAU,GAAG,EAAH,GAAQ,CAAtC;IACA,MAAMY,UAAU,GAAGD,WAAW,GAAG,CAAjC;IAEA,MAAME,QAAQ,GAAGL,EAAE,GAAGG,WAAtB;IACA,MAAMG,SAAS,GAAGJ,QAAQ,GAAGE,UAA7B;IAEA,OAAO;MACHG,IAAI,EAAErC,UAAU,CAACmC,QAAD,EAAWrB,gBAAX,CADb;MAEHwB,KAAK,EAAEtC,UAAU,CAACoC,SAAD,EAAYtB,gBAAZ;IAFd,CAAP;EAIH,CAjBqC,EAiBnC,CAACO,WAAD,EAAcC,UAAd,CAjBmC,CAAtC;EAmBA,oBACI,oBAAC,QAAD,CAAU,IAAV;IACI,KAAK,EAAE,CACHI,MAAM,CAACrB,IADJ,EAEHQ,QAAQ,GAAGa,MAAM,CAACb,QAAV,GAAqB0B,SAF1B,EAGHZ,aAHG,EAIHH,KAJG;EADX,GAOQC,UAPR,EADJ;AAWH;AAAA"}
@@ -1 +1 @@
1
- {"version":3,"names":[],"sources":["TabIndicatorProps.ts"],"sourcesContent":["import type { ViewProps } from 'react-native';\nimport type { SharedValue } from 'react-native-reanimated';\nimport type { OverridableComponentProps } from '../types';\nimport type TabCoordinate from './TabCoordinate';\n\nexport default interface TabIndicatorProps extends OverridableComponentProps<ViewProps, {\n /**\n * Tab item coordinates.\n */\n coordinates: TabCoordinate[];\n\n /**\n * If `true`, the indicator is disabled.\n */\n disabled: boolean;\n\n /**\n * If `true`, the tab will be able to scroll.\n */\n scrollable: boolean;\n\n /**\n * Scrollable value for using animated interpolation.\n */\n scrollValue: SharedValue<number>;\n}> {}\n"],"mappings":""}
1
+ {"version":3,"names":[],"sources":["TabIndicatorProps.ts"],"sourcesContent":["import type { ViewProps } from 'react-native';\nimport type { SharedValue } from 'react-native-reanimated';\nimport type { OverridableComponentProps } from '../types';\nimport type TabCoordinate from './TabCoordinate';\n\nexport default interface TabIndicatorProps extends OverridableComponentProps<ViewProps, {\n /**\n * Tab item coordinates.\n */\n coordinates: TabCoordinate[];\n\n /**\n * If `true`, the indicator is disabled.\n */\n disabled: boolean;\n\n /**\n * If `true`, the tab will be able to scroll.\n */\n scrollable: boolean;\n\n /**\n * Shared index value for using animated interpolation.\n */\n sharedIndex: SharedValue<number>;\n}> {}\n"],"mappings":""}
@@ -1,12 +1,11 @@
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
-
3
- import React, { cloneElement, useEffect, useMemo, useRef } from 'react';
1
+ import React, { cloneElement, forwardRef, useImperativeHandle } from 'react';
4
2
  import { ScrollView, View } from 'react-native';
5
- import { Easing, useSharedValue, withTiming } from 'react-native-reanimated';
3
+ import { useSharedValue } from 'react-native-reanimated';
6
4
  import { css, useTheme } from '../styles';
7
5
  import TabIndicator from './TabIndicator';
8
- import useTabsWidth from './useTabsWidth';
6
+ import IndexAwareTab from './IndexAwareTab';
9
7
  import useTabCoordinates from './useTabCoordinates';
8
+ import useScrollViewReaction from './useScrollViewReaction';
10
9
 
11
10
  const useStyles = function () {
12
11
  const theme = useTheme();
@@ -24,62 +23,40 @@ const useStyles = function () {
24
23
  };
25
24
  };
26
25
 
27
- const ANIMATION_CONFIG = {
28
- duration: 200,
29
- easing: Easing.out(Easing.exp)
30
- };
31
- export default function Tabs(props) {
26
+ const Tabs = /*#__PURE__*/forwardRef(function Tabs(props, ref) {
32
27
  const {
33
28
  children,
34
- index: indexProp,
29
+ initialIndex = 0,
35
30
  disableIndicator = false,
36
31
  keyboardDismissMode = 'none',
37
32
  keyboardShouldPersistTaps = 'never',
38
33
  onChange,
39
34
  scrollable = false,
40
- scrollValue: scrollValueProp,
41
35
  style,
42
- variant = 'primary',
43
- ...otherProps
36
+ variant = 'primary'
44
37
  } = props;
38
+ const sharedIndex = useSharedValue(initialIndex);
39
+
40
+ const getCurrentIndex = () => sharedIndex.value;
41
+
42
+ const setTab = newIndex => {
43
+ sharedIndex.value = newIndex;
44
+ };
45
+
46
+ useImperativeHandle(ref, () => ({
47
+ getCurrentIndex,
48
+ setTab
49
+ }), [sharedIndex]);
45
50
  const styles = useStyles();
46
- const [containerWidth, handleLayout] = useTabsWidth();
47
- const scrollViewRef = useRef(null);
48
51
  const {
49
52
  coordinates,
50
53
  updateCoordinate
51
54
  } = useTabCoordinates(children);
52
- const internalScrollValue = useSharedValue(0);
53
- const scrollValue = scrollValueProp ?? internalScrollValue;
55
+ const {
56
+ scrollViewRef,
57
+ onLayout
58
+ } = useScrollViewReaction(sharedIndex, coordinates);
54
59
  const isReadyToRenderIndicator = coordinates.length > 0;
55
- useEffect(() => {
56
- const animateTab = index => {
57
- scrollValue.value = withTiming(index, ANIMATION_CONFIG);
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);
68
- }
69
-
70
- return 0;
71
- }, [indexProp, coordinates]);
72
- useEffect(() => {
73
- const scrollView = scrollViewRef.current;
74
-
75
- if (scrollView) {
76
- scrollView.scrollTo({
77
- x: scrollPosition,
78
- y: 0,
79
- animated: true
80
- });
81
- }
82
- }, [scrollPosition, containerWidth]);
83
60
  const tabElements = React.Children.map(children, (child, index) => {
84
61
  const onLayout = event => {
85
62
  const {
@@ -98,34 +75,37 @@ export default function Tabs(props) {
98
75
  const onPress = () => {
99
76
  var _child$props$onPress, _child$props;
100
77
 
78
+ setTab(index);
101
79
  onChange === null || onChange === void 0 ? void 0 : onChange(index); // @ts-ignore
102
80
 
103
81
  (_child$props$onPress = (_child$props = child.props).onPress) === null || _child$props$onPress === void 0 ? void 0 : _child$props$onPress.call(_child$props);
104
- };
82
+ }; // @ts-ignore
105
83
 
106
- const selected = index === indexProp;
107
- const enableIndicatorPlaceholder = disableIndicator ? false : isReadyToRenderIndicator ? false : selected; //@ts-ignore
108
84
 
109
- return /*#__PURE__*/cloneElement(child, {
110
- enableIndicator: enableIndicatorPlaceholder,
85
+ const tabElement = /*#__PURE__*/cloneElement(child, {
86
+ enableIndicator: !disableIndicator && isReadyToRenderIndicator,
111
87
  onLayout,
112
88
  onPress,
113
89
  onMouseDown,
114
90
  variant,
115
- selected,
116
91
  style: scrollable ? undefined : styles.fixedTab
117
92
  });
93
+ return /*#__PURE__*/React.createElement(IndexAwareTab, {
94
+ children: tabElement,
95
+ index: index,
96
+ sharedIndex: sharedIndex
97
+ });
118
98
  });
119
- const indicator = /*#__PURE__*/React.createElement(TabIndicator, {
99
+ const tabIndicator = /*#__PURE__*/React.createElement(TabIndicator, {
120
100
  coordinates: coordinates,
121
101
  disabled: disableIndicator,
122
102
  scrollable: scrollable,
123
- scrollValue: scrollValue
103
+ sharedIndex: sharedIndex
124
104
  });
125
- return /*#__PURE__*/React.createElement(View, _extends({
126
- onLayout: handleLayout,
105
+ return /*#__PURE__*/React.createElement(View, {
106
+ onLayout: onLayout,
127
107
  style: css([styles.root, scrollable ? undefined : styles.fixedRoot, style])
128
- }, otherProps), scrollable ? /*#__PURE__*/React.createElement(ScrollView, {
108
+ }, scrollable ? /*#__PURE__*/React.createElement(ScrollView, {
129
109
  automaticallyAdjustContentInsets: false,
130
110
  bounces: false,
131
111
  contentContainerStyle: styles.scrollableContainer,
@@ -137,7 +117,7 @@ export default function Tabs(props) {
137
117
  showsVerticalScrollIndicator: false,
138
118
  keyboardDismissMode: keyboardDismissMode,
139
119
  keyboardShouldPersistTaps: keyboardShouldPersistTaps
140
- }, tabElements, indicator) : /*#__PURE__*/React.createElement(React.Fragment, null, tabElements, indicator));
141
- }
142
- ;
120
+ }, tabElements, tabIndicator) : /*#__PURE__*/React.createElement(React.Fragment, null, tabElements, tabIndicator));
121
+ });
122
+ export default Tabs;
143
123
  //# sourceMappingURL=Tabs.js.map
@@ -1 +1 @@
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) {\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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"}
1
+ {"version":3,"names":["React","cloneElement","forwardRef","useImperativeHandle","ScrollView","View","useSharedValue","css","useTheme","TabIndicator","IndexAwareTab","useTabCoordinates","useScrollViewReaction","useStyles","theme","root","fixedRoot","flexDirection","fixedTab","flex","scrollableContainer","paddingHorizontal","spacing","Tabs","props","ref","children","initialIndex","disableIndicator","keyboardDismissMode","keyboardShouldPersistTaps","onChange","scrollable","style","variant","sharedIndex","getCurrentIndex","value","setTab","newIndex","styles","coordinates","updateCoordinate","scrollViewRef","onLayout","isReadyToRenderIndicator","length","tabElements","Children","map","child","index","event","x","width","nativeEvent","layout","onMouseDown","e","preventDefault","onPress","tabElement","enableIndicator","undefined","tabIndicator"],"sources":["Tabs.tsx"],"sourcesContent":["import React, { cloneElement, forwardRef, useImperativeHandle } from 'react';\nimport type { GestureResponderEvent, LayoutChangeEvent } from 'react-native';\nimport { ScrollView, View } from 'react-native';\nimport { useSharedValue } from 'react-native-reanimated';\nimport { NamedStylesStringUnion, UseStyles } from '@fountain-ui/styles';\nimport { css, useTheme } from '../styles';\nimport type TabsProps from './TabsProps';\nimport type { TabsInstance } from './TabsProps';\nimport TabIndicator from './TabIndicator';\nimport IndexAwareTab from './IndexAwareTab';\nimport useTabCoordinates from './useTabCoordinates';\nimport useScrollViewReaction from './useScrollViewReaction';\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 Tabs = forwardRef<TabsInstance, TabsProps>(function Tabs(props, ref) {\n const {\n children,\n initialIndex = 0,\n disableIndicator = false,\n keyboardDismissMode = 'none',\n keyboardShouldPersistTaps = 'never',\n onChange,\n scrollable = false,\n style,\n variant = 'primary',\n } = props;\n\n const sharedIndex = useSharedValue<number>(initialIndex);\n\n const getCurrentIndex = (): number => sharedIndex.value;\n\n const setTab = (newIndex: number) => {\n sharedIndex.value = newIndex;\n };\n\n useImperativeHandle(\n ref,\n () => ({\n getCurrentIndex,\n setTab,\n }),\n [sharedIndex],\n );\n\n const styles = useStyles();\n\n const { coordinates, updateCoordinate } = useTabCoordinates(children);\n\n const { scrollViewRef, onLayout } = useScrollViewReaction(sharedIndex, coordinates);\n\n const isReadyToRenderIndicator = coordinates.length > 0;\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 setTab(index);\n\n onChange?.(index);\n // @ts-ignore\n child.props.onPress?.();\n };\n\n // @ts-ignore\n const tabElement = cloneElement(child, {\n enableIndicator: !disableIndicator && isReadyToRenderIndicator,\n onLayout,\n onPress,\n onMouseDown,\n variant,\n style: scrollable ? undefined : styles.fixedTab,\n });\n\n return (\n <IndexAwareTab\n children={tabElement}\n index={index}\n sharedIndex={sharedIndex}\n />\n );\n });\n\n const tabIndicator = (\n <TabIndicator\n coordinates={coordinates}\n disabled={disableIndicator}\n scrollable={scrollable}\n sharedIndex={sharedIndex}\n />\n );\n\n return (\n <View\n onLayout={onLayout}\n style={css([\n styles.root,\n scrollable ? undefined : styles.fixedRoot,\n style,\n ])}\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 {tabIndicator}\n </ScrollView>\n ) : (\n <React.Fragment>\n {tabElements}\n {tabIndicator}\n </React.Fragment>\n )}\n </View>\n );\n});\n\nexport default Tabs;\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"names":[],"sources":["TabsProps.ts"],"sourcesContent":["import React from 'react';\nimport type { ViewProps } from 'react-native';\nimport Animated from 'react-native-reanimated';\nimport type { TabVariant } from '../Tab';\nimport type { OverridableComponentProps } from '../types';\n\nexport type KeyboardDismissMode =\n 'none'\n | 'on-drag'\n | 'interactive'; // ios only\n\nexport type KeyboardShouldPersistTaps =\n 'never'\n | boolean\n | 'always'\n | 'handled'; // app only\n\nexport default interface TabsProps extends OverridableComponentProps<ViewProps, {\n /**\n * Collection of Tab components.\n */\n children: React.ReactNode;\n\n /**\n * Selected index.\n */\n index: number;\n\n /**\n * If `true`, the indicator is disabled.\n * @default false\n */\n disableIndicator?: boolean;\n\n /**\n * keyboard dismissing condition of dragging.\n * @default 'none'\n */\n keyboardDismissMode?: KeyboardDismissMode,\n\n /**\n * keyboard persisting condition of tapping.\n * @default 'never'\n */\n keyboardShouldPersistTaps?: KeyboardShouldPersistTaps,\n\n /**\n * Callback fired when a tab is selected.\n */\n onChange?: (newIndex: number) => void;\n\n /**\n * If `true`, the component will be able to scroll.\n * @default false\n */\n scrollable?: boolean;\n\n /**\n * Scrollable value for using animated interpolation.\n */\n scrollValue?: Animated.SharedValue<number>;\n\n /**\n * The variant to use.\n * @default 'primary'\n */\n variant?: TabVariant;\n}> {}\n"],"mappings":""}
1
+ {"version":3,"names":[],"sources":["TabsProps.ts"],"sourcesContent":["import type { ReactNode, Ref } from 'react';\nimport type { ViewProps } from 'react-native';\nimport type { TabVariant } from '../Tab';\nimport type { OverridableComponentProps } from '../types';\n\nexport type KeyboardDismissMode =\n 'none'\n | 'on-drag'\n | 'interactive'; // ios only\n\nexport type KeyboardShouldPersistTaps =\n 'never'\n | boolean\n | 'always'\n | 'handled'; // app only\n\nexport interface TabsInstance {\n /**\n * Get current tab index.\n */\n getCurrentIndex: () => number;\n\n /**\n * Function to scroll to a specific tab. Invalid index is ignored.\n * @param index\n */\n setTab: (index: number) => void;\n}\n\nexport default interface TabsProps extends OverridableComponentProps<ViewProps, {\n ref?: Ref<TabsInstance>;\n\n /**\n * Collection of Tab components.\n */\n children: ReactNode;\n\n /**\n * If `true`, the indicator is disabled.\n * @default false\n */\n disableIndicator?: boolean;\n\n /**\n * Index of initial tab that should be selected.\n * @default 0\n */\n initialIndex?: number;\n\n /**\n * keyboard dismissing condition of dragging.\n * @default 'none'\n */\n keyboardDismissMode?: KeyboardDismissMode,\n\n /**\n * keyboard persisting condition of tapping.\n * @default 'never'\n */\n keyboardShouldPersistTaps?: KeyboardShouldPersistTaps,\n\n /**\n * Callback fired when a tab is selected.\n */\n onChange?: (newIndex: number) => void;\n\n /**\n * If `true`, the component will be able to scroll.\n * @default false\n */\n scrollable?: boolean;\n\n /**\n * The variant to use.\n * @default 'primary'\n */\n variant?: TabVariant;\n}> {}\n"],"mappings":""}
@@ -1 +1 @@
1
- {"version":3,"names":["default"],"sources":["index.ts"],"sourcesContent":["export { default } from './Tabs';\nexport type { default as TabsProps } from './TabsProps';"],"mappings":"AAAA,SAASA,OAAT,QAAwB,QAAxB"}
1
+ {"version":3,"names":["default"],"sources":["index.ts"],"sourcesContent":["export { default } from './Tabs';\nexport type { default as TabsProps, TabsInstance } from './TabsProps';\n"],"mappings":"AAAA,SAASA,OAAT,QAAwB,QAAxB"}
@@ -0,0 +1,44 @@
1
+ import { useCallback, useRef } from 'react';
2
+ import { runOnJS, useAnimatedReaction } from 'react-native-reanimated';
3
+ export default function useScrollViewReaction(sharedIndex, coordinates) {
4
+ const scrollViewRef = useRef(null);
5
+ const lastScrolledPositionRef = useRef(NaN);
6
+
7
+ const scrollTo = scrollPosition => {
8
+ const scrollView = scrollViewRef.current;
9
+
10
+ if (scrollView && Number.isFinite(scrollPosition)) {
11
+ scrollView.scrollTo({
12
+ x: scrollPosition,
13
+ y: 0,
14
+ animated: true
15
+ });
16
+ lastScrolledPositionRef.current = scrollPosition;
17
+ }
18
+ };
19
+
20
+ const onLayout = useCallback(() => {
21
+ scrollTo(lastScrolledPositionRef.current);
22
+ }, []);
23
+ useAnimatedReaction(() => {
24
+ const prevIndex = sharedIndex.value - 1;
25
+ const prevCoordinate = coordinates[prevIndex];
26
+
27
+ if (prevCoordinate) {
28
+ const prevTabWidth = prevCoordinate.x2 - prevCoordinate.x1;
29
+ return Math.floor(prevCoordinate.x1 + prevTabWidth / 2);
30
+ }
31
+
32
+ return 0;
33
+ }, (scrollPosition, prevScrollPosition) => {
34
+ if (scrollPosition !== prevScrollPosition) {
35
+ runOnJS(scrollTo)(scrollPosition);
36
+ }
37
+ }, [coordinates]);
38
+ return {
39
+ scrollViewRef,
40
+ onLayout
41
+ };
42
+ }
43
+ ;
44
+ //# sourceMappingURL=useScrollViewReaction.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["useCallback","useRef","runOnJS","useAnimatedReaction","useScrollViewReaction","sharedIndex","coordinates","scrollViewRef","lastScrolledPositionRef","NaN","scrollTo","scrollPosition","scrollView","current","Number","isFinite","x","y","animated","onLayout","prevIndex","value","prevCoordinate","prevTabWidth","x2","x1","Math","floor","prevScrollPosition"],"sources":["useScrollViewReaction.ts"],"sourcesContent":["import type { MutableRefObject } from 'react';\nimport { useCallback, useRef } from 'react';\nimport type { ScrollView, ViewProps } from 'react-native';\nimport { runOnJS, SharedValue, useAnimatedReaction } from 'react-native-reanimated';\nimport type TabCoordinate from './TabCoordinate';\n\nexport interface UseScrollViewReaction {\n scrollViewRef: MutableRefObject<ScrollView | null>;\n onLayout: ViewProps['onLayout'];\n}\n\nexport default function useScrollViewReaction(\n sharedIndex: SharedValue<number>,\n coordinates: TabCoordinate[],\n): UseScrollViewReaction {\n const scrollViewRef = useRef<ScrollView | null>(null);\n\n const lastScrolledPositionRef = useRef<number>(NaN);\n\n const scrollTo = (scrollPosition: number) => {\n const scrollView = scrollViewRef.current;\n\n if (scrollView && Number.isFinite(scrollPosition)) {\n scrollView.scrollTo({ x: scrollPosition, y: 0, animated: true });\n\n lastScrolledPositionRef.current = scrollPosition;\n }\n };\n\n const onLayout = useCallback(() => {\n scrollTo(lastScrolledPositionRef.current);\n }, []);\n\n useAnimatedReaction(\n () => {\n const prevIndex = sharedIndex.value - 1;\n const prevCoordinate = coordinates[prevIndex];\n\n if (prevCoordinate) {\n const prevTabWidth = prevCoordinate.x2 - prevCoordinate.x1;\n return Math.floor(prevCoordinate.x1 + prevTabWidth / 2);\n }\n\n return 0;\n },\n (scrollPosition, prevScrollPosition) => {\n if (scrollPosition !== prevScrollPosition) {\n runOnJS(scrollTo)(scrollPosition);\n }\n },\n [coordinates],\n );\n\n return { scrollViewRef, onLayout };\n};\n"],"mappings":"AACA,SAASA,WAAT,EAAsBC,MAAtB,QAAoC,OAApC;AAEA,SAASC,OAAT,EAA+BC,mBAA/B,QAA0D,yBAA1D;AAQA,eAAe,SAASC,qBAAT,CACXC,WADW,EAEXC,WAFW,EAGU;EACrB,MAAMC,aAAa,GAAGN,MAAM,CAAoB,IAApB,CAA5B;EAEA,MAAMO,uBAAuB,GAAGP,MAAM,CAASQ,GAAT,CAAtC;;EAEA,MAAMC,QAAQ,GAAIC,cAAD,IAA4B;IACzC,MAAMC,UAAU,GAAGL,aAAa,CAACM,OAAjC;;IAEA,IAAID,UAAU,IAAIE,MAAM,CAACC,QAAP,CAAgBJ,cAAhB,CAAlB,EAAmD;MAC/CC,UAAU,CAACF,QAAX,CAAoB;QAAEM,CAAC,EAAEL,cAAL;QAAqBM,CAAC,EAAE,CAAxB;QAA2BC,QAAQ,EAAE;MAArC,CAApB;MAEAV,uBAAuB,CAACK,OAAxB,GAAkCF,cAAlC;IACH;EACJ,CARD;;EAUA,MAAMQ,QAAQ,GAAGnB,WAAW,CAAC,MAAM;IAC/BU,QAAQ,CAACF,uBAAuB,CAACK,OAAzB,CAAR;EACH,CAF2B,EAEzB,EAFyB,CAA5B;EAIAV,mBAAmB,CACf,MAAM;IACF,MAAMiB,SAAS,GAAGf,WAAW,CAACgB,KAAZ,GAAoB,CAAtC;IACA,MAAMC,cAAc,GAAGhB,WAAW,CAACc,SAAD,CAAlC;;IAEA,IAAIE,cAAJ,EAAoB;MAChB,MAAMC,YAAY,GAAGD,cAAc,CAACE,EAAf,GAAoBF,cAAc,CAACG,EAAxD;MACA,OAAOC,IAAI,CAACC,KAAL,CAAWL,cAAc,CAACG,EAAf,GAAoBF,YAAY,GAAG,CAA9C,CAAP;IACH;;IAED,OAAO,CAAP;EACH,CAXc,EAYf,CAACZ,cAAD,EAAiBiB,kBAAjB,KAAwC;IACpC,IAAIjB,cAAc,KAAKiB,kBAAvB,EAA2C;MACvC1B,OAAO,CAACQ,QAAD,CAAP,CAAkBC,cAAlB;IACH;EACJ,CAhBc,EAiBf,CAACL,WAAD,CAjBe,CAAnB;EAoBA,OAAO;IAAEC,aAAF;IAAiBY;EAAjB,CAAP;AACH;AAAA"}
@@ -0,0 +1,9 @@
1
+ import type { ReactElement } from 'react';
2
+ import React from 'react';
3
+ import type { SharedValue } from 'react-native-reanimated';
4
+ export interface IndexAwareTabProps {
5
+ children: ReactElement;
6
+ index: number;
7
+ sharedIndex: SharedValue<number>;
8
+ }
9
+ export default function IndexAwareTab(props: IndexAwareTabProps): ReactElement<any, string | React.JSXElementConstructor<any>>;
@@ -16,8 +16,8 @@ export default interface TabIndicatorProps extends OverridableComponentProps<Vie
16
16
  */
17
17
  scrollable: boolean;
18
18
  /**
19
- * Scrollable value for using animated interpolation.
19
+ * Shared index value for using animated interpolation.
20
20
  */
21
- scrollValue: SharedValue<number>;
21
+ sharedIndex: SharedValue<number>;
22
22
  }> {
23
23
  }
@@ -1,2 +1,5 @@
1
+ import React from 'react';
1
2
  import type TabsProps from './TabsProps';
2
- export default function Tabs(props: TabsProps): JSX.Element;
3
+ import type { TabsInstance } from './TabsProps';
4
+ declare const Tabs: React.ForwardRefExoticComponent<Pick<TabsProps, "testID" | "style" | "onLayout" | "keyboardDismissMode" | "children" | "pointerEvents" | "onStartShouldSetResponder" | "onMoveShouldSetResponder" | "onResponderEnd" | "onResponderGrant" | "onResponderReject" | "onResponderMove" | "onResponderRelease" | "onResponderStart" | "onResponderTerminationRequest" | "onResponderTerminate" | "onStartShouldSetResponderCapture" | "onMoveShouldSetResponderCapture" | "hitSlop" | "removeClippedSubviews" | "nativeID" | "collapsable" | "needsOffscreenAlphaCompositing" | "renderToHardwareTextureAndroid" | "focusable" | "shouldRasterizeIOS" | "isTVSelectable" | "hasTVPreferredFocus" | "tvParallaxProperties" | "tvParallaxShiftDistanceX" | "tvParallaxShiftDistanceY" | "tvParallaxTiltAngle" | "tvParallaxMagnification" | "onTouchStart" | "onTouchMove" | "onTouchEnd" | "onTouchCancel" | "onTouchEndCapture" | "accessible" | "accessibilityActions" | "accessibilityLabel" | "accessibilityRole" | "accessibilityState" | "accessibilityHint" | "accessibilityValue" | "onAccessibilityAction" | "accessibilityLiveRegion" | "importantForAccessibility" | "accessibilityElementsHidden" | "accessibilityViewIsModal" | "onAccessibilityEscape" | "onAccessibilityTap" | "onMagicTap" | "accessibilityIgnoresInvertColors" | "variant" | "keyboardShouldPersistTaps" | "onChange" | "disableIndicator" | "initialIndex" | "scrollable"> & React.RefAttributes<TabsInstance>>;
5
+ export default Tabs;
@@ -1,24 +1,36 @@
1
- import React from 'react';
1
+ import type { ReactNode, Ref } from 'react';
2
2
  import type { ViewProps } from 'react-native';
3
- import Animated from 'react-native-reanimated';
4
3
  import type { TabVariant } from '../Tab';
5
4
  import type { OverridableComponentProps } from '../types';
6
5
  export declare type KeyboardDismissMode = 'none' | 'on-drag' | 'interactive';
7
6
  export declare type KeyboardShouldPersistTaps = 'never' | boolean | 'always' | 'handled';
8
- export default interface TabsProps extends OverridableComponentProps<ViewProps, {
7
+ export interface TabsInstance {
9
8
  /**
10
- * Collection of Tab components.
9
+ * Get current tab index.
11
10
  */
12
- children: React.ReactNode;
11
+ getCurrentIndex: () => number;
13
12
  /**
14
- * Selected index.
13
+ * Function to scroll to a specific tab. Invalid index is ignored.
14
+ * @param index
15
15
  */
16
- index: number;
16
+ setTab: (index: number) => void;
17
+ }
18
+ export default interface TabsProps extends OverridableComponentProps<ViewProps, {
19
+ ref?: Ref<TabsInstance>;
20
+ /**
21
+ * Collection of Tab components.
22
+ */
23
+ children: ReactNode;
17
24
  /**
18
25
  * If `true`, the indicator is disabled.
19
26
  * @default false
20
27
  */
21
28
  disableIndicator?: boolean;
29
+ /**
30
+ * Index of initial tab that should be selected.
31
+ * @default 0
32
+ */
33
+ initialIndex?: number;
22
34
  /**
23
35
  * keyboard dismissing condition of dragging.
24
36
  * @default 'none'
@@ -38,10 +50,6 @@ export default interface TabsProps extends OverridableComponentProps<ViewProps,
38
50
  * @default false
39
51
  */
40
52
  scrollable?: boolean;
41
- /**
42
- * Scrollable value for using animated interpolation.
43
- */
44
- scrollValue?: Animated.SharedValue<number>;
45
53
  /**
46
54
  * The variant to use.
47
55
  * @default 'primary'
@@ -1,2 +1,2 @@
1
1
  export { default } from './Tabs';
2
- export type { default as TabsProps } from './TabsProps';
2
+ export type { default as TabsProps, TabsInstance } from './TabsProps';
@@ -0,0 +1,9 @@
1
+ import type { MutableRefObject } from 'react';
2
+ import type { ScrollView, ViewProps } from 'react-native';
3
+ import { SharedValue } from 'react-native-reanimated';
4
+ import type TabCoordinate from './TabCoordinate';
5
+ export interface UseScrollViewReaction {
6
+ scrollViewRef: MutableRefObject<ScrollView | null>;
7
+ onLayout: ViewProps['onLayout'];
8
+ }
9
+ export default function useScrollViewReaction(sharedIndex: SharedValue<number>, coordinates: TabCoordinate[]): UseScrollViewReaction;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fountain-ui/core",
3
- "version": "2.0.0-beta.13",
3
+ "version": "2.0.0-beta.14",
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": "0ac49f4ca5f910fc8b5edad2593300d796b2d914"
70
+ "gitHead": "80988af3fdfd671fcb655d4b36a017ce13baf29e"
71
71
  }
package/src/Tab/Tab.tsx CHANGED
@@ -1,4 +1,4 @@
1
- import React from 'react';
1
+ import React, { cloneElement } from 'react';
2
2
  import { Platform, Text } from 'react-native';
3
3
  import Badge from '../Badge';
4
4
  import TabBase from '../TabBase';
@@ -26,9 +26,9 @@ export default function Tab(props: TabProps) {
26
26
  const {
27
27
  badgeVisible = false,
28
28
  children,
29
- enableIndicator,
29
+ enableIndicator = false,
30
30
  icon: defaultIcon,
31
- selected,
31
+ selected = false,
32
32
  selectedIcon,
33
33
  variant = 'primary',
34
34
  style,
@@ -59,7 +59,7 @@ export default function Tab(props: TabProps) {
59
59
  const pressEffect = selected ? 'none' : 'opacity';
60
60
 
61
61
  const icon = selected ? (selectedIcon || defaultIcon) : defaultIcon;
62
- const iconElement = icon ? React.cloneElement(icon, { fill: color }) : null;
62
+ const iconElement = icon ? cloneElement(icon, { fill: color }) : null;
63
63
 
64
64
  return (
65
65
  <TabBase
@@ -78,7 +78,7 @@ export default function Tab(props: TabProps) {
78
78
  style={css(fontStyle)}
79
79
  />
80
80
 
81
- {enableIndicator ? <TabIndicator/> : null}
81
+ {(enableIndicator && selected) ? <TabIndicator/> : null}
82
82
  </TabBase>
83
83
  );
84
84
  };
@@ -0,0 +1,30 @@
1
+ import type { ReactElement } from 'react';
2
+ import React, { cloneElement, useState } from 'react';
3
+ import type { SharedValue } from 'react-native-reanimated';
4
+ import { runOnJS, useAnimatedReaction } from 'react-native-reanimated';
5
+
6
+ export interface IndexAwareTabProps {
7
+ children: ReactElement;
8
+ index: number;
9
+ sharedIndex: SharedValue<number>;
10
+ }
11
+
12
+ export default function IndexAwareTab(props: IndexAwareTabProps) {
13
+ const {
14
+ children,
15
+ index,
16
+ sharedIndex,
17
+ } = props;
18
+
19
+ const [selected, setSelected] = useState(index === sharedIndex.value);
20
+
21
+ useAnimatedReaction(
22
+ () => index === sharedIndex.value,
23
+ (result) => {
24
+ runOnJS(setSelected)(result);
25
+ },
26
+ [index],
27
+ );
28
+
29
+ return cloneElement(children, { selected });
30
+ };
@@ -1,5 +1,6 @@
1
1
  import React from 'react';
2
- import Animated, { useAnimatedStyle } from 'react-native-reanimated';
2
+ import type { WithTimingConfig } from 'react-native-reanimated';
3
+ import Animated, { Easing, useAnimatedStyle, withTiming } from 'react-native-reanimated';
3
4
  import { NamedStylesStringUnion, UseStyles } from '@fountain-ui/styles';
4
5
  import { useTheme } from '../styles';
5
6
  import type TabIndicatorProps from './TabIndicatorProps';
@@ -23,12 +24,17 @@ const useStyles: UseStyles<TabIndicatorStyles> = function (): TabIndicatorStyles
23
24
  };
24
25
  };
25
26
 
27
+ const ANIMATION_CONFIG: Readonly<WithTimingConfig> = {
28
+ duration: 200,
29
+ easing: Easing.out(Easing.exp),
30
+ };
31
+
26
32
  export default function TabIndicator(props: TabIndicatorProps) {
27
33
  const {
28
34
  coordinates,
29
35
  disabled,
30
36
  scrollable,
31
- scrollValue,
37
+ sharedIndex,
32
38
  style,
33
39
  ...otherProps
34
40
  } = props;
@@ -36,23 +42,21 @@ export default function TabIndicator(props: TabIndicatorProps) {
36
42
  const styles = useStyles();
37
43
 
38
44
  const animatedStyle = useAnimatedStyle(() => {
39
- const rawScrollValue = scrollValue.value;
45
+ const index = sharedIndex.value;
40
46
 
41
- const index = Math.floor(rawScrollValue);
42
- const offset = rawScrollValue % 1;
47
+ const { x1, x2 } = coordinates[index] ?? defaultCoordinate;
43
48
 
44
- const coordinate = coordinates[index] ?? defaultCoordinate;
45
- const nextCoordinate = coordinates[index + 1] ?? defaultCoordinate;
49
+ const tabWidth = x2 - x1;
46
50
 
47
- const x1 = (offset * nextCoordinate.x1 + (1 - offset) * coordinate.x1);
48
- const x2 = (offset * nextCoordinate.x2 + (1 - offset) * coordinate.x2);
51
+ const singleInset = scrollable ? 12 : 0;
52
+ const totalInset = singleInset * 2;
49
53
 
50
- const leftInset = scrollable ? 12 : 0;
51
- const rightInset = scrollable ? 24 : 0;
54
+ const nextLeft = x1 + singleInset;
55
+ const nextWidth = tabWidth - totalInset;
52
56
 
53
57
  return {
54
- left: x1 + leftInset,
55
- width: Math.max(x2 - x1 - rightInset, 0),
58
+ left: withTiming(nextLeft, ANIMATION_CONFIG),
59
+ width: withTiming(nextWidth, ANIMATION_CONFIG),
56
60
  };
57
61
  }, [coordinates, scrollable]);
58
62
 
@@ -20,7 +20,7 @@ export default interface TabIndicatorProps extends OverridableComponentProps<Vie
20
20
  scrollable: boolean;
21
21
 
22
22
  /**
23
- * Scrollable value for using animated interpolation.
23
+ * Shared index value for using animated interpolation.
24
24
  */
25
- scrollValue: SharedValue<number>;
25
+ sharedIndex: SharedValue<number>;
26
26
  }> {}