@fountain-ui/core 2.0.0-beta.18 → 2.0.0-beta.20

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 (41) hide show
  1. package/build/commonjs/Tabs/IndexAwareTab.js +3 -2
  2. package/build/commonjs/Tabs/IndexAwareTab.js.map +1 -1
  3. package/build/commonjs/Tabs/Tabs.js +14 -10
  4. package/build/commonjs/Tabs/Tabs.js.map +1 -1
  5. package/build/commonjs/Tabs/useTabCoordinates.js +9 -23
  6. package/build/commonjs/Tabs/useTabCoordinates.js.map +1 -1
  7. package/build/commonjs/Tabs/utils.js +19 -0
  8. package/build/commonjs/Tabs/utils.js.map +1 -0
  9. package/build/commonjs/hooks/index.js +8 -0
  10. package/build/commonjs/hooks/index.js.map +1 -1
  11. package/build/commonjs/hooks/useImperativeState.js +26 -0
  12. package/build/commonjs/hooks/useImperativeState.js.map +1 -0
  13. package/build/commonjs/store/SimpleStore.js +9 -1
  14. package/build/commonjs/store/SimpleStore.js.map +1 -1
  15. package/build/module/Tabs/IndexAwareTab.js +3 -2
  16. package/build/module/Tabs/IndexAwareTab.js.map +1 -1
  17. package/build/module/Tabs/Tabs.js +14 -11
  18. package/build/module/Tabs/Tabs.js.map +1 -1
  19. package/build/module/Tabs/useTabCoordinates.js +9 -18
  20. package/build/module/Tabs/useTabCoordinates.js.map +1 -1
  21. package/build/module/Tabs/utils.js +9 -0
  22. package/build/module/Tabs/utils.js.map +1 -0
  23. package/build/module/hooks/index.js +1 -0
  24. package/build/module/hooks/index.js.map +1 -1
  25. package/build/module/hooks/useImperativeState.js +17 -0
  26. package/build/module/hooks/useImperativeState.js.map +1 -0
  27. package/build/module/store/SimpleStore.js +9 -1
  28. package/build/module/store/SimpleStore.js.map +1 -1
  29. package/build/typescript/Tabs/IndexAwareTab.d.ts +1 -0
  30. package/build/typescript/Tabs/useTabCoordinates.d.ts +3 -4
  31. package/build/typescript/Tabs/utils.d.ts +3 -0
  32. package/build/typescript/hooks/index.d.ts +1 -0
  33. package/build/typescript/hooks/useImperativeState.d.ts +6 -0
  34. package/package.json +2 -2
  35. package/src/Tabs/IndexAwareTab.tsx +3 -1
  36. package/src/Tabs/Tabs.tsx +13 -6
  37. package/src/Tabs/useTabCoordinates.ts +12 -23
  38. package/src/Tabs/utils.ts +14 -0
  39. package/src/hooks/index.ts +1 -0
  40. package/src/hooks/useImperativeState.ts +24 -0
  41. package/src/store/SimpleStore.ts +9 -2
@@ -14,9 +14,10 @@ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { de
14
14
  function IndexAwareTab(props) {
15
15
  const {
16
16
  children,
17
- index
17
+ index,
18
+ initialIndex
18
19
  } = props;
19
- const [selected, setSelected] = (0, _react.useState)(false);
20
+ const [selected, setSelected] = (0, _react.useState)(initialIndex === index);
20
21
  const {
21
22
  indexStore
22
23
  } = (0, _react.useContext)(_InternalContext.default);
@@ -1 +1 @@
1
- {"version":3,"names":["IndexAwareTab","props","children","index","selected","setSelected","useState","indexStore","useContext","InternalContext","useEffect","subscribe","currentIndex","cloneElement"],"sources":["IndexAwareTab.tsx"],"sourcesContent":["import type { ReactElement } from 'react';\nimport React, { cloneElement, useContext, useEffect, useState } from 'react';\nimport InternalContext from './InternalContext';\n\nexport interface IndexAwareTabProps {\n children: ReactElement;\n index: number;\n}\n\nexport default function IndexAwareTab(props: IndexAwareTabProps) {\n const {\n children,\n index,\n } = props;\n\n const [selected, setSelected] = useState(false);\n\n const { indexStore } = useContext(InternalContext);\n\n useEffect(() => {\n return indexStore.subscribe((currentIndex) => {\n setSelected(currentIndex === index);\n });\n }, [indexStore, index]);\n\n return cloneElement(children, { selected });\n};\n"],"mappings":";;;;;;;AACA;;AACA;;;;AAOe,SAASA,aAAT,CAAuBC,KAAvB,EAAkD;EAC7D,MAAM;IACFC,QADE;IAEFC;EAFE,IAGFF,KAHJ;EAKA,MAAM,CAACG,QAAD,EAAWC,WAAX,IAA0B,IAAAC,eAAA,EAAS,KAAT,CAAhC;EAEA,MAAM;IAAEC;EAAF,IAAiB,IAAAC,iBAAA,EAAWC,wBAAX,CAAvB;EAEA,IAAAC,gBAAA,EAAU,MAAM;IACZ,OAAOH,UAAU,CAACI,SAAX,CAAsBC,YAAD,IAAkB;MAC1CP,WAAW,CAACO,YAAY,KAAKT,KAAlB,CAAX;IACH,CAFM,CAAP;EAGH,CAJD,EAIG,CAACI,UAAD,EAAaJ,KAAb,CAJH;EAMA,oBAAO,IAAAU,mBAAA,EAAaX,QAAb,EAAuB;IAAEE;EAAF,CAAvB,CAAP;AACH;;AAAA"}
1
+ {"version":3,"names":["IndexAwareTab","props","children","index","initialIndex","selected","setSelected","useState","indexStore","useContext","InternalContext","useEffect","subscribe","currentIndex","cloneElement"],"sources":["IndexAwareTab.tsx"],"sourcesContent":["import type { ReactElement } from 'react';\nimport React, { cloneElement, useContext, useEffect, useState } from 'react';\nimport InternalContext from './InternalContext';\n\nexport interface IndexAwareTabProps {\n children: ReactElement;\n index: number;\n initialIndex: number;\n}\n\nexport default function IndexAwareTab(props: IndexAwareTabProps) {\n const {\n children,\n index,\n initialIndex,\n } = props;\n\n const [selected, setSelected] = useState(initialIndex === index);\n\n const { indexStore } = useContext(InternalContext);\n\n useEffect(() => {\n return indexStore.subscribe((currentIndex) => {\n setSelected(currentIndex === index);\n });\n }, [indexStore, index]);\n\n return cloneElement(children, { selected });\n};\n"],"mappings":";;;;;;;AACA;;AACA;;;;AAQe,SAASA,aAAT,CAAuBC,KAAvB,EAAkD;EAC7D,MAAM;IACFC,QADE;IAEFC,KAFE;IAGFC;EAHE,IAIFH,KAJJ;EAMA,MAAM,CAACI,QAAD,EAAWC,WAAX,IAA0B,IAAAC,eAAA,EAASH,YAAY,KAAKD,KAA1B,CAAhC;EAEA,MAAM;IAAEK;EAAF,IAAiB,IAAAC,iBAAA,EAAWC,wBAAX,CAAvB;EAEA,IAAAC,gBAAA,EAAU,MAAM;IACZ,OAAOH,UAAU,CAACI,SAAX,CAAsBC,YAAD,IAAkB;MAC1CP,WAAW,CAACO,YAAY,KAAKV,KAAlB,CAAX;IACH,CAFM,CAAP;EAGH,CAJD,EAIG,CAACK,UAAD,EAAaL,KAAb,CAJH;EAMA,oBAAO,IAAAW,mBAAA,EAAaZ,QAAb,EAAuB;IAAEG;EAAF,CAAvB,CAAP;AACH;;AAAA"}
@@ -25,6 +25,8 @@ var _useIndexStore = _interopRequireDefault(require("./useIndexStore"));
25
25
 
26
26
  var _InternalContext = _interopRequireDefault(require("./InternalContext"));
27
27
 
28
+ var _utils = require("./utils");
29
+
28
30
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
29
31
 
30
32
  function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function (nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
@@ -73,12 +75,14 @@ const Tabs = /*#__PURE__*/(0, _react.forwardRef)(function Tabs(props, ref) {
73
75
  setTab
74
76
  }), [sharedIndex]);
75
77
  const styles = useStyles();
76
- const {
77
- coordinates,
78
- updateCoordinate
79
- } = (0, _useTabCoordinates.default)(children);
78
+ const [coordinates, updateCoordinate] = (0, _useTabCoordinates.default)(children);
79
+ const canRenderIndicator = (0, _utils.isEveryTabCoordinatesDefined)(coordinates, children);
80
80
  const indexStore = (0, _useIndexStore.default)(sharedIndex);
81
- const isReadyToRenderIndicator = coordinates.length > 0;
81
+ (0, _react.useEffect)(() => {
82
+ return indexStore.subscribe(newIndex => {
83
+ onChange === null || onChange === void 0 ? void 0 : onChange(newIndex);
84
+ });
85
+ }, [indexStore, onChange]);
82
86
 
83
87
  const tabElements = _react.default.Children.map(children, (child, index) => {
84
88
  const onLayout = event => {
@@ -98,15 +102,14 @@ const Tabs = /*#__PURE__*/(0, _react.forwardRef)(function Tabs(props, ref) {
98
102
  const onPress = () => {
99
103
  var _child$props$onPress, _child$props;
100
104
 
101
- setTab(index);
102
- onChange === null || onChange === void 0 ? void 0 : onChange(index); // @ts-ignore
105
+ setTab(index); // @ts-ignore
103
106
 
104
107
  (_child$props$onPress = (_child$props = child.props).onPress) === null || _child$props$onPress === void 0 ? void 0 : _child$props$onPress.call(_child$props);
105
108
  }; // @ts-ignore
106
109
 
107
110
 
108
111
  const tabElement = /*#__PURE__*/(0, _react.cloneElement)(child, {
109
- enableIndicator: !disableIndicator && !isReadyToRenderIndicator,
112
+ enableIndicator: !disableIndicator && !canRenderIndicator,
110
113
  onLayout,
111
114
  onPress,
112
115
  onMouseDown,
@@ -115,11 +118,12 @@ const Tabs = /*#__PURE__*/(0, _react.forwardRef)(function Tabs(props, ref) {
115
118
  });
116
119
  return /*#__PURE__*/_react.default.createElement(_IndexAwareTab.default, {
117
120
  children: tabElement,
118
- index: index
121
+ index: index,
122
+ initialIndex: initialIndex
119
123
  });
120
124
  });
121
125
 
122
- const tabIndicator = isReadyToRenderIndicator ? /*#__PURE__*/_react.default.createElement(_TabIndicator.default, {
126
+ const tabIndicator = canRenderIndicator ? /*#__PURE__*/_react.default.createElement(_TabIndicator.default, {
123
127
  coordinates: coordinates,
124
128
  disabled: disableIndicator,
125
129
  initialIndex: sharedIndex.initialValue,
@@ -1 +1 @@
1
- {"version":3,"names":["useStyles","theme","useTheme","root","fixedRoot","flexDirection","fixedTab","flex","scrollableContainer","paddingHorizontal","spacing","Tabs","forwardRef","props","ref","children","initialIndex","disableIndicator","keyboardDismissMode","keyboardShouldPersistTaps","onChange","scrollable","style","variant","UNSTABLE_sharedIndex","fallbackSharedIndex","useSyncAnimatedValue","initialValue","sharedIndex","setTab","newIndex","animatedValue","setValue","useImperativeHandle","styles","coordinates","updateCoordinate","useTabCoordinates","indexStore","useIndexStore","isReadyToRenderIndicator","length","tabElements","React","Children","map","child","index","onLayout","event","x","width","nativeEvent","layout","onMouseDown","e","preventDefault","onPress","tabElement","cloneElement","enableIndicator","undefined","tabIndicator","css"],"sources":["Tabs.tsx"],"sourcesContent":["import React, { cloneElement, forwardRef, useImperativeHandle } from 'react';\nimport type { GestureResponderEvent, LayoutChangeEvent } from 'react-native';\nimport { View } from 'react-native';\nimport { NamedStylesStringUnion, UseStyles } from '@fountain-ui/styles';\nimport { css, useTheme } from '../styles';\nimport { useSyncAnimatedValue } from '../hooks';\nimport type TabsProps from './TabsProps';\nimport type { TabsInstance } from './types';\nimport TabIndicator from './TabIndicator';\nimport ScrollableTabsView from './ScrollableTabsView';\nimport IndexAwareTab from './IndexAwareTab';\nimport useTabCoordinates from './useTabCoordinates';\nimport useIndexStore from './useIndexStore';\nimport InternalContext from './InternalContext';\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 UNSTABLE_sharedIndex,\n } = props;\n\n const fallbackSharedIndex = useSyncAnimatedValue({ initialValue: initialIndex });\n\n const sharedIndex = UNSTABLE_sharedIndex ?? fallbackSharedIndex;\n\n const setTab = (newIndex: number) => {\n sharedIndex.animatedValue.setValue(newIndex);\n };\n\n useImperativeHandle(\n ref,\n () => ({\n setTab,\n }),\n [sharedIndex],\n );\n\n const styles = useStyles();\n\n const { coordinates, updateCoordinate } = useTabCoordinates(children);\n\n const indexStore = useIndexStore(sharedIndex);\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 />\n );\n });\n\n const tabIndicator = isReadyToRenderIndicator ? (\n <TabIndicator\n coordinates={coordinates}\n disabled={disableIndicator}\n initialIndex={sharedIndex.initialValue}\n scrollable={scrollable}\n />\n ) : null;\n\n return (\n <InternalContext.Provider value={{ indexStore }}>\n <View\n style={css([\n styles.root,\n scrollable ? undefined : styles.fixedRoot,\n style,\n ])}\n >\n {scrollable ? (\n <ScrollableTabsView\n automaticallyAdjustContentInsets={false}\n bounces={false}\n contentContainerStyle={styles.scrollableContainer}\n coordinates={coordinates}\n directionalLockEnabled={true}\n horizontal={true}\n scrollsToTop={false}\n showsHorizontalScrollIndicator={false}\n showsVerticalScrollIndicator={false}\n keyboardDismissMode={keyboardDismissMode}\n keyboardShouldPersistTaps={keyboardShouldPersistTaps}\n >\n {tabElements}\n {tabIndicator}\n </ScrollableTabsView>\n ) : (\n <React.Fragment>\n {tabElements}\n {tabIndicator}\n </React.Fragment>\n )}\n </View>\n </InternalContext.Provider>\n );\n});\n\nexport default Tabs;\n"],"mappings":"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"}
1
+ {"version":3,"names":["useStyles","theme","useTheme","root","fixedRoot","flexDirection","fixedTab","flex","scrollableContainer","paddingHorizontal","spacing","Tabs","forwardRef","props","ref","children","initialIndex","disableIndicator","keyboardDismissMode","keyboardShouldPersistTaps","onChange","scrollable","style","variant","UNSTABLE_sharedIndex","fallbackSharedIndex","useSyncAnimatedValue","initialValue","sharedIndex","setTab","newIndex","animatedValue","setValue","useImperativeHandle","styles","coordinates","updateCoordinate","useTabCoordinates","canRenderIndicator","isEveryTabCoordinatesDefined","indexStore","useIndexStore","useEffect","subscribe","tabElements","React","Children","map","child","index","onLayout","event","x","width","nativeEvent","layout","onMouseDown","e","preventDefault","onPress","tabElement","cloneElement","enableIndicator","undefined","tabIndicator","css"],"sources":["Tabs.tsx"],"sourcesContent":["import React, { cloneElement, forwardRef, useEffect, useImperativeHandle } from 'react';\nimport type { GestureResponderEvent, LayoutChangeEvent } from 'react-native';\nimport { View } from 'react-native';\nimport { NamedStylesStringUnion, UseStyles } from '@fountain-ui/styles';\nimport { css, useTheme } from '../styles';\nimport { useSyncAnimatedValue } from '../hooks';\nimport type TabsProps from './TabsProps';\nimport type { TabsInstance } from './types';\nimport TabIndicator from './TabIndicator';\nimport ScrollableTabsView from './ScrollableTabsView';\nimport IndexAwareTab from './IndexAwareTab';\nimport useTabCoordinates from './useTabCoordinates';\nimport useIndexStore from './useIndexStore';\nimport InternalContext from './InternalContext';\nimport { isEveryTabCoordinatesDefined } from './utils';\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 UNSTABLE_sharedIndex,\n } = props;\n\n const fallbackSharedIndex = useSyncAnimatedValue({ initialValue: initialIndex });\n\n const sharedIndex = UNSTABLE_sharedIndex ?? fallbackSharedIndex;\n\n const setTab = (newIndex: number) => {\n sharedIndex.animatedValue.setValue(newIndex);\n };\n\n useImperativeHandle(\n ref,\n () => ({\n setTab,\n }),\n [sharedIndex],\n );\n\n const styles = useStyles();\n\n const [coordinates, updateCoordinate] = useTabCoordinates(children);\n\n const canRenderIndicator = isEveryTabCoordinatesDefined(coordinates, children);\n\n const indexStore = useIndexStore(sharedIndex);\n\n useEffect(() => {\n return indexStore.subscribe(newIndex => {\n onChange?.(newIndex);\n });\n }, [indexStore, onChange]);\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 // @ts-ignore\n child.props.onPress?.();\n };\n\n // @ts-ignore\n const tabElement = cloneElement(child, {\n enableIndicator: !disableIndicator && !canRenderIndicator,\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 initialIndex={initialIndex}\n />\n );\n });\n\n const tabIndicator = canRenderIndicator ? (\n <TabIndicator\n coordinates={coordinates}\n disabled={disableIndicator}\n initialIndex={sharedIndex.initialValue}\n scrollable={scrollable}\n />\n ) : null;\n\n return (\n <InternalContext.Provider value={{ indexStore }}>\n <View\n style={css([\n styles.root,\n scrollable ? undefined : styles.fixedRoot,\n style,\n ])}\n >\n {scrollable ? (\n <ScrollableTabsView\n automaticallyAdjustContentInsets={false}\n bounces={false}\n contentContainerStyle={styles.scrollableContainer}\n coordinates={coordinates}\n directionalLockEnabled={true}\n horizontal={true}\n scrollsToTop={false}\n showsHorizontalScrollIndicator={false}\n showsVerticalScrollIndicator={false}\n keyboardDismissMode={keyboardDismissMode}\n keyboardShouldPersistTaps={keyboardShouldPersistTaps}\n >\n {tabElements}\n {tabIndicator}\n </ScrollableTabsView>\n ) : (\n <React.Fragment>\n {tabElements}\n {tabIndicator}\n </React.Fragment>\n )}\n </View>\n </InternalContext.Provider>\n );\n});\n\nexport default Tabs;\n"],"mappings":"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"}
@@ -5,40 +5,26 @@ Object.defineProperty(exports, "__esModule", {
5
5
  });
6
6
  exports.default = useTabCoordinates;
7
7
 
8
- var _react = _interopRequireWildcard(require("react"));
8
+ var _react = require("react");
9
9
 
10
- var _utils = require("@fountain-ui/utils");
11
-
12
- function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function (nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
13
-
14
- function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
10
+ var _utils = require("./utils");
15
11
 
16
12
  function useTabCoordinates(tabElements) {
17
- const incompleteCoordinatesRef = (0, _react.useRef)([]);
18
- const [completeCoordinates, setCompleteCoordinates] = (0, _react.useState)([]);
19
-
20
- const isAllCoordinatesDefined = coordinates => {
21
- const numberOfTab = _react.default.Children.count(tabElements);
22
-
23
- const numberOfCoordinates = coordinates.length;
24
- const everyCoordinatesDefined = (0, _utils.isEveryDefined)(coordinates);
25
- return numberOfTab === numberOfCoordinates && everyCoordinatesDefined;
26
- };
13
+ const [coordinates, setCoordinates] = (0, _react.useState)([]);
14
+ const cacheRef = (0, _react.useRef)([]);
27
15
 
28
16
  const updateCoordinate = (index, x, width) => {
29
- incompleteCoordinatesRef.current[index] = {
17
+ cacheRef.current[index] = {
30
18
  x1: x,
31
19
  x2: x + width
32
20
  };
33
21
 
34
- if (isAllCoordinatesDefined(incompleteCoordinatesRef.current)) {
35
- setCompleteCoordinates(incompleteCoordinatesRef.current);
22
+ if ((0, _utils.isEveryTabCoordinatesDefined)(cacheRef.current, tabElements)) {
23
+ setCoordinates([...cacheRef.current]);
24
+ cacheRef.current = [];
36
25
  }
37
26
  };
38
27
 
39
- return {
40
- coordinates: completeCoordinates,
41
- updateCoordinate
42
- };
28
+ return [coordinates, updateCoordinate];
43
29
  }
44
30
  //# sourceMappingURL=useTabCoordinates.js.map
@@ -1 +1 @@
1
- {"version":3,"names":["useTabCoordinates","tabElements","incompleteCoordinatesRef","useRef","completeCoordinates","setCompleteCoordinates","useState","isAllCoordinatesDefined","coordinates","numberOfTab","React","Children","count","numberOfCoordinates","length","everyCoordinatesDefined","isEveryDefined","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;;AACA;;;;;;AAQe,SAASA,iBAAT,CAA2BC,WAA3B,EAA4E;EACvF,MAAMC,wBAAwB,GAAG,IAAAC,aAAA,EAAwB,EAAxB,CAAjC;EAEA,MAAM,CAACC,mBAAD,EAAsBC,sBAAtB,IAAgD,IAAAC,eAAA,EAA0B,EAA1B,CAAtD;;EAEA,MAAMC,uBAAuB,GAAIC,WAAD,IAA2C;IACvE,MAAMC,WAAW,GAAGC,cAAA,CAAMC,QAAN,CAAeC,KAAf,CAAqBX,WAArB,CAApB;;IACA,MAAMY,mBAAmB,GAAGL,WAAW,CAACM,MAAxC;IAEA,MAAMC,uBAAuB,GAAG,IAAAC,qBAAA,EAAeR,WAAf,CAAhC;IAEA,OAAOC,WAAW,KAAKI,mBAAhB,IAAuCE,uBAA9C;EACH,CAPD;;EASA,MAAME,gBAAgB,GAAG,CAACC,KAAD,EAAgBC,CAAhB,EAA2BC,KAA3B,KAA6C;IAClElB,wBAAwB,CAACmB,OAAzB,CAAiCH,KAAjC,IAA0C;MAAEI,EAAE,EAAEH,CAAN;MAASI,EAAE,EAAEJ,CAAC,GAAGC;IAAjB,CAA1C;;IAEA,IAAIb,uBAAuB,CAACL,wBAAwB,CAACmB,OAA1B,CAA3B,EAA+D;MAC3DhB,sBAAsB,CAACH,wBAAwB,CAACmB,OAA1B,CAAtB;IACH;EACJ,CAND;;EAQA,OAAO;IACHb,WAAW,EAAEJ,mBADV;IAEHa;EAFG,CAAP;AAIH"}
1
+ {"version":3,"names":["useTabCoordinates","tabElements","coordinates","setCoordinates","useState","cacheRef","useRef","updateCoordinate","index","x","width","current","x1","x2","isEveryTabCoordinatesDefined"],"sources":["useTabCoordinates.ts"],"sourcesContent":["import React, { useRef, useState } from 'react';\nimport TabCoordinate from './TabCoordinate';\nimport { isEveryTabCoordinatesDefined } from './utils';\n\nexport interface UpdateCoordinate {\n (index: number, x: number, width: number): void;\n}\n\nexport default function useTabCoordinates(tabElements: React.ReactNode): [TabCoordinate[], UpdateCoordinate] {\n const [coordinates, setCoordinates] = useState<TabCoordinate[]>([]);\n\n const cacheRef = useRef<TabCoordinate[]>([]);\n\n const updateCoordinate: UpdateCoordinate = (index, x, width) => {\n cacheRef.current[index] = { x1: x, x2: x + width };\n\n if (isEveryTabCoordinatesDefined(cacheRef.current, tabElements)) {\n setCoordinates([...cacheRef.current]);\n\n cacheRef.current = [];\n }\n };\n\n return [coordinates, updateCoordinate];\n}\n"],"mappings":";;;;;;;AAAA;;AAEA;;AAMe,SAASA,iBAAT,CAA2BC,WAA3B,EAA8F;EACzG,MAAM,CAACC,WAAD,EAAcC,cAAd,IAAgC,IAAAC,eAAA,EAA0B,EAA1B,CAAtC;EAEA,MAAMC,QAAQ,GAAG,IAAAC,aAAA,EAAwB,EAAxB,CAAjB;;EAEA,MAAMC,gBAAkC,GAAG,CAACC,KAAD,EAAQC,CAAR,EAAWC,KAAX,KAAqB;IAC5DL,QAAQ,CAACM,OAAT,CAAiBH,KAAjB,IAA0B;MAAEI,EAAE,EAAEH,CAAN;MAASI,EAAE,EAAEJ,CAAC,GAAGC;IAAjB,CAA1B;;IAEA,IAAI,IAAAI,mCAAA,EAA6BT,QAAQ,CAACM,OAAtC,EAA+CV,WAA/C,CAAJ,EAAiE;MAC7DE,cAAc,CAAC,CAAC,GAAGE,QAAQ,CAACM,OAAb,CAAD,CAAd;MAEAN,QAAQ,CAACM,OAAT,GAAmB,EAAnB;IACH;EACJ,CARD;;EAUA,OAAO,CAACT,WAAD,EAAcK,gBAAd,CAAP;AACH"}
@@ -0,0 +1,19 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.isEveryTabCoordinatesDefined = isEveryTabCoordinatesDefined;
7
+
8
+ var _react = require("react");
9
+
10
+ var _utils = require("@fountain-ui/utils");
11
+
12
+ function isEveryTabCoordinatesDefined(coordinates, tabElements) {
13
+ const numberOfTabs = _react.Children.count(tabElements);
14
+
15
+ const numberOfCoordinates = coordinates.length;
16
+ const everyCoordinatesDefined = (0, _utils.isEveryDefined)(coordinates);
17
+ return numberOfTabs === numberOfCoordinates && everyCoordinatesDefined;
18
+ }
19
+ //# sourceMappingURL=utils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["isEveryTabCoordinatesDefined","coordinates","tabElements","numberOfTabs","Children","count","numberOfCoordinates","length","everyCoordinatesDefined","isEveryDefined"],"sources":["utils.ts"],"sourcesContent":["import type { ReactNode } from 'react';\nimport { Children } from 'react';\nimport { isEveryDefined } from '@fountain-ui/utils';\nimport type TabCoordinate from './TabCoordinate';\n\n\nexport function isEveryTabCoordinatesDefined(coordinates: TabCoordinate[], tabElements: ReactNode): boolean {\n const numberOfTabs = Children.count(tabElements);\n const numberOfCoordinates = coordinates.length;\n\n const everyCoordinatesDefined = isEveryDefined(coordinates);\n\n return numberOfTabs === numberOfCoordinates && everyCoordinatesDefined;\n}\n"],"mappings":";;;;;;;AACA;;AACA;;AAIO,SAASA,4BAAT,CAAsCC,WAAtC,EAAoEC,WAApE,EAAqG;EACxG,MAAMC,YAAY,GAAGC,eAAA,CAASC,KAAT,CAAeH,WAAf,CAArB;;EACA,MAAMI,mBAAmB,GAAGL,WAAW,CAACM,MAAxC;EAEA,MAAMC,uBAAuB,GAAG,IAAAC,qBAAA,EAAeR,WAAf,CAAhC;EAEA,OAAOE,YAAY,KAAKG,mBAAjB,IAAwCE,uBAA/C;AACH"}
@@ -33,6 +33,12 @@ Object.defineProperty(exports, "useFadeInAppBar", {
33
33
  return _useFadeInAppBar.default;
34
34
  }
35
35
  });
36
+ Object.defineProperty(exports, "useImperativeState", {
37
+ enumerable: true,
38
+ get: function () {
39
+ return _useImperativeState.default;
40
+ }
41
+ });
36
42
  Object.defineProperty(exports, "useSyncAnimatedValue", {
37
43
  enumerable: true,
38
44
  get: function () {
@@ -62,6 +68,8 @@ var _useElevationStyle = _interopRequireDefault(require("./useElevationStyle"));
62
68
 
63
69
  var _useFadeInAppBar = _interopRequireDefault(require("./useFadeInAppBar"));
64
70
 
71
+ var _useImperativeState = _interopRequireDefault(require("./useImperativeState"));
72
+
65
73
  var _useSyncAnimatedValue = _interopRequireDefault(require("./useSyncAnimatedValue"));
66
74
 
67
75
  var _useThrottle = _interopRequireDefault(require("./useThrottle"));
@@ -1 +1 @@
1
- {"version":3,"names":[],"sources":["index.ts"],"sourcesContent":["export { default as useBreakpointUp } from './useBreakpointUp';\nexport { default as useCollapsibleAppBar } from './useCollapsibleAppBar';\nexport { default as useContentContainerStyle } from './useContentContainerStyle';\nexport { default as useElevationStyle } from './useElevationStyle';\nexport { default as useFadeInAppBar } from './useFadeInAppBar';\nexport { default as useSyncAnimatedValue } from './useSyncAnimatedValue';\nexport { default as useThrottle } from './useThrottle';\nexport { default as useValidWindowDimensions } from './useValidWindowDimensions';\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;;AACA;;AACA;;AACA;;AACA;;AACA;;AACA;;AACA"}
1
+ {"version":3,"names":[],"sources":["index.ts"],"sourcesContent":["export { default as useBreakpointUp } from './useBreakpointUp';\nexport { default as useCollapsibleAppBar } from './useCollapsibleAppBar';\nexport { default as useContentContainerStyle } from './useContentContainerStyle';\nexport { default as useElevationStyle } from './useElevationStyle';\nexport { default as useFadeInAppBar } from './useFadeInAppBar';\nexport { default as useImperativeState } from './useImperativeState';\nexport { default as useSyncAnimatedValue } from './useSyncAnimatedValue';\nexport { default as useThrottle } from './useThrottle';\nexport { default as useValidWindowDimensions } from './useValidWindowDimensions';\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;;AACA;;AACA;;AACA;;AACA;;AACA;;AACA;;AACA;;AACA"}
@@ -0,0 +1,26 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.default = useImperativeState;
7
+
8
+ var _react = require("react");
9
+
10
+ function useImperativeState(initialValue) {
11
+ return (0, _react.useMemo)(() => {
12
+ let prevState = initialValue;
13
+ let currentState = initialValue;
14
+ return {
15
+ hasChanged: () => prevState !== currentState,
16
+ get: () => currentState,
17
+ set: nextState => {
18
+ prevState = currentState;
19
+ currentState = nextState;
20
+ }
21
+ };
22
+ }, []);
23
+ }
24
+
25
+ ;
26
+ //# sourceMappingURL=useImperativeState.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["useImperativeState","initialValue","useMemo","prevState","currentState","hasChanged","get","set","nextState"],"sources":["useImperativeState.ts"],"sourcesContent":["import { useMemo } from 'react';\n\n\nexport interface ImperativeState<T> {\n hasChanged: () => boolean;\n get: () => T;\n set: (nextState: T) => void;\n}\n\nexport default function useImperativeState<T>(initialValue: T): ImperativeState<T> {\n return useMemo<ImperativeState<T>>(() => {\n let prevState: T = initialValue;\n let currentState: T = initialValue;\n\n return {\n hasChanged: () => prevState !== currentState,\n get: () => currentState,\n set: (nextState) => {\n prevState = currentState;\n currentState = nextState;\n },\n };\n }, []);\n};\n"],"mappings":";;;;;;;AAAA;;AASe,SAASA,kBAAT,CAA+BC,YAA/B,EAAoE;EAC/E,OAAO,IAAAC,cAAA,EAA4B,MAAM;IACrC,IAAIC,SAAY,GAAGF,YAAnB;IACA,IAAIG,YAAe,GAAGH,YAAtB;IAEA,OAAO;MACHI,UAAU,EAAE,MAAMF,SAAS,KAAKC,YAD7B;MAEHE,GAAG,EAAE,MAAMF,YAFR;MAGHG,GAAG,EAAGC,SAAD,IAAe;QAChBL,SAAS,GAAGC,YAAZ;QACAA,YAAY,GAAGI,SAAf;MACH;IANE,CAAP;EAQH,CAZM,EAYJ,EAZI,CAAP;AAaH;;AAAA"}
@@ -7,6 +7,10 @@ exports.default = void 0;
7
7
 
8
8
  function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
9
9
 
10
+ function refEqual(a, b) {
11
+ return a === b;
12
+ }
13
+
10
14
  class SimpleStore {
11
15
  constructor(initialData) {
12
16
  _defineProperty(this, "data", void 0);
@@ -18,7 +22,6 @@ class SimpleStore {
18
22
 
19
23
  subscribe(listener) {
20
24
  this.listeners.push(listener);
21
- listener(this.data);
22
25
  return () => {
23
26
  const index = this.listeners.indexOf(listener);
24
27
  this.listeners.splice(index, 1);
@@ -26,6 +29,11 @@ class SimpleStore {
26
29
  }
27
30
 
28
31
  dispatch(data) {
32
+ // Do not dispatch if data ref is equal
33
+ if (refEqual(this.data, data)) {
34
+ return;
35
+ }
36
+
29
37
  this.data = data;
30
38
 
31
39
  for (const id in this.listeners) {
@@ -1 +1 @@
1
- {"version":3,"names":["SimpleStore","constructor","initialData","data","subscribe","listener","listeners","push","index","indexOf","splice","dispatch","id","removeAllListeners","length"],"sources":["SimpleStore.ts"],"sourcesContent":["import { MonoStore, StoreSubscription } from './types';\n\nexport default class SimpleStore<T> implements MonoStore<T> {\n\n private data: T;\n\n private listeners: Array<(data: T) => void> = [];\n\n constructor(initialData: T) {\n this.data = initialData;\n }\n\n subscribe(listener: (data: T) => void): StoreSubscription {\n this.listeners.push(listener);\n\n listener(this.data);\n\n return () => {\n const index = this.listeners.indexOf(listener);\n this.listeners.splice(index, 1);\n };\n }\n\n dispatch(data: T): void {\n this.data = data;\n for (const id in this.listeners) {\n const listener = this.listeners[id];\n listener?.(data);\n }\n }\n\n removeAllListeners(): void {\n this.listeners.splice(0, this.listeners.length);\n }\n\n};\n"],"mappings":";;;;;;;;;AAEe,MAAMA,WAAN,CAA6C;EAMxDC,WAAW,CAACC,WAAD,EAAiB;IAAA;;IAAA,mCAFkB,EAElB;;IACxB,KAAKC,IAAL,GAAYD,WAAZ;EACH;;EAEDE,SAAS,CAACC,QAAD,EAAiD;IACtD,KAAKC,SAAL,CAAeC,IAAf,CAAoBF,QAApB;IAEAA,QAAQ,CAAC,KAAKF,IAAN,CAAR;IAEA,OAAO,MAAM;MACT,MAAMK,KAAK,GAAG,KAAKF,SAAL,CAAeG,OAAf,CAAuBJ,QAAvB,CAAd;MACA,KAAKC,SAAL,CAAeI,MAAf,CAAsBF,KAAtB,EAA6B,CAA7B;IACH,CAHD;EAIH;;EAEDG,QAAQ,CAACR,IAAD,EAAgB;IACpB,KAAKA,IAAL,GAAYA,IAAZ;;IACA,KAAK,MAAMS,EAAX,IAAiB,KAAKN,SAAtB,EAAiC;MAC7B,MAAMD,QAAQ,GAAG,KAAKC,SAAL,CAAeM,EAAf,CAAjB;MACAP,QAAQ,SAAR,IAAAA,QAAQ,WAAR,YAAAA,QAAQ,CAAGF,IAAH,CAAR;IACH;EACJ;;EAEDU,kBAAkB,GAAS;IACvB,KAAKP,SAAL,CAAeI,MAAf,CAAsB,CAAtB,EAAyB,KAAKJ,SAAL,CAAeQ,MAAxC;EACH;;AA/BuD;;;AAiC3D"}
1
+ {"version":3,"names":["refEqual","a","b","SimpleStore","constructor","initialData","data","subscribe","listener","listeners","push","index","indexOf","splice","dispatch","id","removeAllListeners","length"],"sources":["SimpleStore.ts"],"sourcesContent":["import { MonoStore, StoreSubscription } from './types';\n\nfunction refEqual(a: any, b: any): boolean {\n return a === b;\n}\n\nexport default class SimpleStore<T> implements MonoStore<T> {\n\n private data: T;\n\n private listeners: Array<(data: T) => void> = [];\n\n constructor(initialData: T) {\n this.data = initialData;\n }\n\n subscribe(listener: (data: T) => void): StoreSubscription {\n this.listeners.push(listener);\n\n return () => {\n const index = this.listeners.indexOf(listener);\n this.listeners.splice(index, 1);\n };\n }\n\n dispatch(data: T): void {\n // Do not dispatch if data ref is equal\n if (refEqual(this.data, data)) {\n return;\n }\n\n this.data = data;\n for (const id in this.listeners) {\n const listener = this.listeners[id];\n listener?.(data);\n }\n }\n\n removeAllListeners(): void {\n this.listeners.splice(0, this.listeners.length);\n }\n\n};\n"],"mappings":";;;;;;;;;AAEA,SAASA,QAAT,CAAkBC,CAAlB,EAA0BC,CAA1B,EAA2C;EACvC,OAAOD,CAAC,KAAKC,CAAb;AACH;;AAEc,MAAMC,WAAN,CAA6C;EAMxDC,WAAW,CAACC,WAAD,EAAiB;IAAA;;IAAA,mCAFkB,EAElB;;IACxB,KAAKC,IAAL,GAAYD,WAAZ;EACH;;EAEDE,SAAS,CAACC,QAAD,EAAiD;IACtD,KAAKC,SAAL,CAAeC,IAAf,CAAoBF,QAApB;IAEA,OAAO,MAAM;MACT,MAAMG,KAAK,GAAG,KAAKF,SAAL,CAAeG,OAAf,CAAuBJ,QAAvB,CAAd;MACA,KAAKC,SAAL,CAAeI,MAAf,CAAsBF,KAAtB,EAA6B,CAA7B;IACH,CAHD;EAIH;;EAEDG,QAAQ,CAACR,IAAD,EAAgB;IACpB;IACA,IAAIN,QAAQ,CAAC,KAAKM,IAAN,EAAYA,IAAZ,CAAZ,EAA+B;MAC3B;IACH;;IAED,KAAKA,IAAL,GAAYA,IAAZ;;IACA,KAAK,MAAMS,EAAX,IAAiB,KAAKN,SAAtB,EAAiC;MAC7B,MAAMD,QAAQ,GAAG,KAAKC,SAAL,CAAeM,EAAf,CAAjB;MACAP,QAAQ,SAAR,IAAAA,QAAQ,WAAR,YAAAA,QAAQ,CAAGF,IAAH,CAAR;IACH;EACJ;;EAEDU,kBAAkB,GAAS;IACvB,KAAKP,SAAL,CAAeI,MAAf,CAAsB,CAAtB,EAAyB,KAAKJ,SAAL,CAAeQ,MAAxC;EACH;;AAlCuD;;;AAoC3D"}
@@ -3,9 +3,10 @@ import InternalContext from './InternalContext';
3
3
  export default function IndexAwareTab(props) {
4
4
  const {
5
5
  children,
6
- index
6
+ index,
7
+ initialIndex
7
8
  } = props;
8
- const [selected, setSelected] = useState(false);
9
+ const [selected, setSelected] = useState(initialIndex === index);
9
10
  const {
10
11
  indexStore
11
12
  } = useContext(InternalContext);
@@ -1 +1 @@
1
- {"version":3,"names":["cloneElement","useContext","useEffect","useState","InternalContext","IndexAwareTab","props","children","index","selected","setSelected","indexStore","subscribe","currentIndex"],"sources":["IndexAwareTab.tsx"],"sourcesContent":["import type { ReactElement } from 'react';\nimport React, { cloneElement, useContext, useEffect, useState } from 'react';\nimport InternalContext from './InternalContext';\n\nexport interface IndexAwareTabProps {\n children: ReactElement;\n index: number;\n}\n\nexport default function IndexAwareTab(props: IndexAwareTabProps) {\n const {\n children,\n index,\n } = props;\n\n const [selected, setSelected] = useState(false);\n\n const { indexStore } = useContext(InternalContext);\n\n useEffect(() => {\n return indexStore.subscribe((currentIndex) => {\n setSelected(currentIndex === index);\n });\n }, [indexStore, index]);\n\n return cloneElement(children, { selected });\n};\n"],"mappings":"AACA,SAAgBA,YAAhB,EAA8BC,UAA9B,EAA0CC,SAA1C,EAAqDC,QAArD,QAAqE,OAArE;AACA,OAAOC,eAAP,MAA4B,mBAA5B;AAOA,eAAe,SAASC,aAAT,CAAuBC,KAAvB,EAAkD;EAC7D,MAAM;IACFC,QADE;IAEFC;EAFE,IAGFF,KAHJ;EAKA,MAAM,CAACG,QAAD,EAAWC,WAAX,IAA0BP,QAAQ,CAAC,KAAD,CAAxC;EAEA,MAAM;IAAEQ;EAAF,IAAiBV,UAAU,CAACG,eAAD,CAAjC;EAEAF,SAAS,CAAC,MAAM;IACZ,OAAOS,UAAU,CAACC,SAAX,CAAsBC,YAAD,IAAkB;MAC1CH,WAAW,CAACG,YAAY,KAAKL,KAAlB,CAAX;IACH,CAFM,CAAP;EAGH,CAJQ,EAIN,CAACG,UAAD,EAAaH,KAAb,CAJM,CAAT;EAMA,oBAAOR,YAAY,CAACO,QAAD,EAAW;IAAEE;EAAF,CAAX,CAAnB;AACH;AAAA"}
1
+ {"version":3,"names":["cloneElement","useContext","useEffect","useState","InternalContext","IndexAwareTab","props","children","index","initialIndex","selected","setSelected","indexStore","subscribe","currentIndex"],"sources":["IndexAwareTab.tsx"],"sourcesContent":["import type { ReactElement } from 'react';\nimport React, { cloneElement, useContext, useEffect, useState } from 'react';\nimport InternalContext from './InternalContext';\n\nexport interface IndexAwareTabProps {\n children: ReactElement;\n index: number;\n initialIndex: number;\n}\n\nexport default function IndexAwareTab(props: IndexAwareTabProps) {\n const {\n children,\n index,\n initialIndex,\n } = props;\n\n const [selected, setSelected] = useState(initialIndex === index);\n\n const { indexStore } = useContext(InternalContext);\n\n useEffect(() => {\n return indexStore.subscribe((currentIndex) => {\n setSelected(currentIndex === index);\n });\n }, [indexStore, index]);\n\n return cloneElement(children, { selected });\n};\n"],"mappings":"AACA,SAAgBA,YAAhB,EAA8BC,UAA9B,EAA0CC,SAA1C,EAAqDC,QAArD,QAAqE,OAArE;AACA,OAAOC,eAAP,MAA4B,mBAA5B;AAQA,eAAe,SAASC,aAAT,CAAuBC,KAAvB,EAAkD;EAC7D,MAAM;IACFC,QADE;IAEFC,KAFE;IAGFC;EAHE,IAIFH,KAJJ;EAMA,MAAM,CAACI,QAAD,EAAWC,WAAX,IAA0BR,QAAQ,CAACM,YAAY,KAAKD,KAAlB,CAAxC;EAEA,MAAM;IAAEI;EAAF,IAAiBX,UAAU,CAACG,eAAD,CAAjC;EAEAF,SAAS,CAAC,MAAM;IACZ,OAAOU,UAAU,CAACC,SAAX,CAAsBC,YAAD,IAAkB;MAC1CH,WAAW,CAACG,YAAY,KAAKN,KAAlB,CAAX;IACH,CAFM,CAAP;EAGH,CAJQ,EAIN,CAACI,UAAD,EAAaJ,KAAb,CAJM,CAAT;EAMA,oBAAOR,YAAY,CAACO,QAAD,EAAW;IAAEG;EAAF,CAAX,CAAnB;AACH;AAAA"}
@@ -1,4 +1,4 @@
1
- import React, { cloneElement, forwardRef, useImperativeHandle } from 'react';
1
+ import React, { cloneElement, forwardRef, useEffect, useImperativeHandle } from 'react';
2
2
  import { View } from 'react-native';
3
3
  import { css, useTheme } from '../styles';
4
4
  import { useSyncAnimatedValue } from '../hooks';
@@ -8,6 +8,7 @@ import IndexAwareTab from './IndexAwareTab';
8
8
  import useTabCoordinates from './useTabCoordinates';
9
9
  import useIndexStore from './useIndexStore';
10
10
  import InternalContext from './InternalContext';
11
+ import { isEveryTabCoordinatesDefined } from './utils';
11
12
 
12
13
  const useStyles = function () {
13
14
  const theme = useTheme();
@@ -51,12 +52,14 @@ const Tabs = /*#__PURE__*/forwardRef(function Tabs(props, ref) {
51
52
  setTab
52
53
  }), [sharedIndex]);
53
54
  const styles = useStyles();
54
- const {
55
- coordinates,
56
- updateCoordinate
57
- } = useTabCoordinates(children);
55
+ const [coordinates, updateCoordinate] = useTabCoordinates(children);
56
+ const canRenderIndicator = isEveryTabCoordinatesDefined(coordinates, children);
58
57
  const indexStore = useIndexStore(sharedIndex);
59
- const isReadyToRenderIndicator = coordinates.length > 0;
58
+ useEffect(() => {
59
+ return indexStore.subscribe(newIndex => {
60
+ onChange === null || onChange === void 0 ? void 0 : onChange(newIndex);
61
+ });
62
+ }, [indexStore, onChange]);
60
63
  const tabElements = React.Children.map(children, (child, index) => {
61
64
  const onLayout = event => {
62
65
  const {
@@ -75,15 +78,14 @@ const Tabs = /*#__PURE__*/forwardRef(function Tabs(props, ref) {
75
78
  const onPress = () => {
76
79
  var _child$props$onPress, _child$props;
77
80
 
78
- setTab(index);
79
- onChange === null || onChange === void 0 ? void 0 : onChange(index); // @ts-ignore
81
+ setTab(index); // @ts-ignore
80
82
 
81
83
  (_child$props$onPress = (_child$props = child.props).onPress) === null || _child$props$onPress === void 0 ? void 0 : _child$props$onPress.call(_child$props);
82
84
  }; // @ts-ignore
83
85
 
84
86
 
85
87
  const tabElement = /*#__PURE__*/cloneElement(child, {
86
- enableIndicator: !disableIndicator && !isReadyToRenderIndicator,
88
+ enableIndicator: !disableIndicator && !canRenderIndicator,
87
89
  onLayout,
88
90
  onPress,
89
91
  onMouseDown,
@@ -92,10 +94,11 @@ const Tabs = /*#__PURE__*/forwardRef(function Tabs(props, ref) {
92
94
  });
93
95
  return /*#__PURE__*/React.createElement(IndexAwareTab, {
94
96
  children: tabElement,
95
- index: index
97
+ index: index,
98
+ initialIndex: initialIndex
96
99
  });
97
100
  });
98
- const tabIndicator = isReadyToRenderIndicator ? /*#__PURE__*/React.createElement(TabIndicator, {
101
+ const tabIndicator = canRenderIndicator ? /*#__PURE__*/React.createElement(TabIndicator, {
99
102
  coordinates: coordinates,
100
103
  disabled: disableIndicator,
101
104
  initialIndex: sharedIndex.initialValue,
@@ -1 +1 @@
1
- {"version":3,"names":["React","cloneElement","forwardRef","useImperativeHandle","View","css","useTheme","useSyncAnimatedValue","TabIndicator","ScrollableTabsView","IndexAwareTab","useTabCoordinates","useIndexStore","InternalContext","useStyles","theme","root","fixedRoot","flexDirection","fixedTab","flex","scrollableContainer","paddingHorizontal","spacing","Tabs","props","ref","children","initialIndex","disableIndicator","keyboardDismissMode","keyboardShouldPersistTaps","onChange","scrollable","style","variant","UNSTABLE_sharedIndex","fallbackSharedIndex","initialValue","sharedIndex","setTab","newIndex","animatedValue","setValue","styles","coordinates","updateCoordinate","indexStore","isReadyToRenderIndicator","length","tabElements","Children","map","child","index","onLayout","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 { View } from 'react-native';\nimport { NamedStylesStringUnion, UseStyles } from '@fountain-ui/styles';\nimport { css, useTheme } from '../styles';\nimport { useSyncAnimatedValue } from '../hooks';\nimport type TabsProps from './TabsProps';\nimport type { TabsInstance } from './types';\nimport TabIndicator from './TabIndicator';\nimport ScrollableTabsView from './ScrollableTabsView';\nimport IndexAwareTab from './IndexAwareTab';\nimport useTabCoordinates from './useTabCoordinates';\nimport useIndexStore from './useIndexStore';\nimport InternalContext from './InternalContext';\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 UNSTABLE_sharedIndex,\n } = props;\n\n const fallbackSharedIndex = useSyncAnimatedValue({ initialValue: initialIndex });\n\n const sharedIndex = UNSTABLE_sharedIndex ?? fallbackSharedIndex;\n\n const setTab = (newIndex: number) => {\n sharedIndex.animatedValue.setValue(newIndex);\n };\n\n useImperativeHandle(\n ref,\n () => ({\n setTab,\n }),\n [sharedIndex],\n );\n\n const styles = useStyles();\n\n const { coordinates, updateCoordinate } = useTabCoordinates(children);\n\n const indexStore = useIndexStore(sharedIndex);\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 />\n );\n });\n\n const tabIndicator = isReadyToRenderIndicator ? (\n <TabIndicator\n coordinates={coordinates}\n disabled={disableIndicator}\n initialIndex={sharedIndex.initialValue}\n scrollable={scrollable}\n />\n ) : null;\n\n return (\n <InternalContext.Provider value={{ indexStore }}>\n <View\n style={css([\n styles.root,\n scrollable ? undefined : styles.fixedRoot,\n style,\n ])}\n >\n {scrollable ? (\n <ScrollableTabsView\n automaticallyAdjustContentInsets={false}\n bounces={false}\n contentContainerStyle={styles.scrollableContainer}\n coordinates={coordinates}\n directionalLockEnabled={true}\n horizontal={true}\n scrollsToTop={false}\n showsHorizontalScrollIndicator={false}\n showsVerticalScrollIndicator={false}\n keyboardDismissMode={keyboardDismissMode}\n keyboardShouldPersistTaps={keyboardShouldPersistTaps}\n >\n {tabElements}\n {tabIndicator}\n </ScrollableTabsView>\n ) : (\n <React.Fragment>\n {tabElements}\n {tabIndicator}\n </React.Fragment>\n )}\n </View>\n </InternalContext.Provider>\n );\n});\n\nexport default Tabs;\n"],"mappings":"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"}
1
+ {"version":3,"names":["React","cloneElement","forwardRef","useEffect","useImperativeHandle","View","css","useTheme","useSyncAnimatedValue","TabIndicator","ScrollableTabsView","IndexAwareTab","useTabCoordinates","useIndexStore","InternalContext","isEveryTabCoordinatesDefined","useStyles","theme","root","fixedRoot","flexDirection","fixedTab","flex","scrollableContainer","paddingHorizontal","spacing","Tabs","props","ref","children","initialIndex","disableIndicator","keyboardDismissMode","keyboardShouldPersistTaps","onChange","scrollable","style","variant","UNSTABLE_sharedIndex","fallbackSharedIndex","initialValue","sharedIndex","setTab","newIndex","animatedValue","setValue","styles","coordinates","updateCoordinate","canRenderIndicator","indexStore","subscribe","tabElements","Children","map","child","index","onLayout","event","x","width","nativeEvent","layout","onMouseDown","e","preventDefault","onPress","tabElement","enableIndicator","undefined","tabIndicator"],"sources":["Tabs.tsx"],"sourcesContent":["import React, { cloneElement, forwardRef, useEffect, useImperativeHandle } from 'react';\nimport type { GestureResponderEvent, LayoutChangeEvent } from 'react-native';\nimport { View } from 'react-native';\nimport { NamedStylesStringUnion, UseStyles } from '@fountain-ui/styles';\nimport { css, useTheme } from '../styles';\nimport { useSyncAnimatedValue } from '../hooks';\nimport type TabsProps from './TabsProps';\nimport type { TabsInstance } from './types';\nimport TabIndicator from './TabIndicator';\nimport ScrollableTabsView from './ScrollableTabsView';\nimport IndexAwareTab from './IndexAwareTab';\nimport useTabCoordinates from './useTabCoordinates';\nimport useIndexStore from './useIndexStore';\nimport InternalContext from './InternalContext';\nimport { isEveryTabCoordinatesDefined } from './utils';\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 UNSTABLE_sharedIndex,\n } = props;\n\n const fallbackSharedIndex = useSyncAnimatedValue({ initialValue: initialIndex });\n\n const sharedIndex = UNSTABLE_sharedIndex ?? fallbackSharedIndex;\n\n const setTab = (newIndex: number) => {\n sharedIndex.animatedValue.setValue(newIndex);\n };\n\n useImperativeHandle(\n ref,\n () => ({\n setTab,\n }),\n [sharedIndex],\n );\n\n const styles = useStyles();\n\n const [coordinates, updateCoordinate] = useTabCoordinates(children);\n\n const canRenderIndicator = isEveryTabCoordinatesDefined(coordinates, children);\n\n const indexStore = useIndexStore(sharedIndex);\n\n useEffect(() => {\n return indexStore.subscribe(newIndex => {\n onChange?.(newIndex);\n });\n }, [indexStore, onChange]);\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 // @ts-ignore\n child.props.onPress?.();\n };\n\n // @ts-ignore\n const tabElement = cloneElement(child, {\n enableIndicator: !disableIndicator && !canRenderIndicator,\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 initialIndex={initialIndex}\n />\n );\n });\n\n const tabIndicator = canRenderIndicator ? (\n <TabIndicator\n coordinates={coordinates}\n disabled={disableIndicator}\n initialIndex={sharedIndex.initialValue}\n scrollable={scrollable}\n />\n ) : null;\n\n return (\n <InternalContext.Provider value={{ indexStore }}>\n <View\n style={css([\n styles.root,\n scrollable ? undefined : styles.fixedRoot,\n style,\n ])}\n >\n {scrollable ? (\n <ScrollableTabsView\n automaticallyAdjustContentInsets={false}\n bounces={false}\n contentContainerStyle={styles.scrollableContainer}\n coordinates={coordinates}\n directionalLockEnabled={true}\n horizontal={true}\n scrollsToTop={false}\n showsHorizontalScrollIndicator={false}\n showsVerticalScrollIndicator={false}\n keyboardDismissMode={keyboardDismissMode}\n keyboardShouldPersistTaps={keyboardShouldPersistTaps}\n >\n {tabElements}\n {tabIndicator}\n </ScrollableTabsView>\n ) : (\n <React.Fragment>\n {tabElements}\n {tabIndicator}\n </React.Fragment>\n )}\n </View>\n </InternalContext.Provider>\n );\n});\n\nexport default Tabs;\n"],"mappings":"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"}
@@ -1,30 +1,21 @@
1
- import React, { useRef, useState } from 'react';
2
- import { isEveryDefined } from '@fountain-ui/utils';
1
+ import { useRef, useState } from 'react';
2
+ import { isEveryTabCoordinatesDefined } from './utils';
3
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
- };
4
+ const [coordinates, setCoordinates] = useState([]);
5
+ const cacheRef = useRef([]);
13
6
 
14
7
  const updateCoordinate = (index, x, width) => {
15
- incompleteCoordinatesRef.current[index] = {
8
+ cacheRef.current[index] = {
16
9
  x1: x,
17
10
  x2: x + width
18
11
  };
19
12
 
20
- if (isAllCoordinatesDefined(incompleteCoordinatesRef.current)) {
21
- setCompleteCoordinates(incompleteCoordinatesRef.current);
13
+ if (isEveryTabCoordinatesDefined(cacheRef.current, tabElements)) {
14
+ setCoordinates([...cacheRef.current]);
15
+ cacheRef.current = [];
22
16
  }
23
17
  };
24
18
 
25
- return {
26
- coordinates: completeCoordinates,
27
- updateCoordinate
28
- };
19
+ return [coordinates, updateCoordinate];
29
20
  }
30
21
  //# sourceMappingURL=useTabCoordinates.js.map
@@ -1 +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"}
1
+ {"version":3,"names":["useRef","useState","isEveryTabCoordinatesDefined","useTabCoordinates","tabElements","coordinates","setCoordinates","cacheRef","updateCoordinate","index","x","width","current","x1","x2"],"sources":["useTabCoordinates.ts"],"sourcesContent":["import React, { useRef, useState } from 'react';\nimport TabCoordinate from './TabCoordinate';\nimport { isEveryTabCoordinatesDefined } from './utils';\n\nexport interface UpdateCoordinate {\n (index: number, x: number, width: number): void;\n}\n\nexport default function useTabCoordinates(tabElements: React.ReactNode): [TabCoordinate[], UpdateCoordinate] {\n const [coordinates, setCoordinates] = useState<TabCoordinate[]>([]);\n\n const cacheRef = useRef<TabCoordinate[]>([]);\n\n const updateCoordinate: UpdateCoordinate = (index, x, width) => {\n cacheRef.current[index] = { x1: x, x2: x + width };\n\n if (isEveryTabCoordinatesDefined(cacheRef.current, tabElements)) {\n setCoordinates([...cacheRef.current]);\n\n cacheRef.current = [];\n }\n };\n\n return [coordinates, updateCoordinate];\n}\n"],"mappings":"AAAA,SAAgBA,MAAhB,EAAwBC,QAAxB,QAAwC,OAAxC;AAEA,SAASC,4BAAT,QAA6C,SAA7C;AAMA,eAAe,SAASC,iBAAT,CAA2BC,WAA3B,EAA8F;EACzG,MAAM,CAACC,WAAD,EAAcC,cAAd,IAAgCL,QAAQ,CAAkB,EAAlB,CAA9C;EAEA,MAAMM,QAAQ,GAAGP,MAAM,CAAkB,EAAlB,CAAvB;;EAEA,MAAMQ,gBAAkC,GAAG,CAACC,KAAD,EAAQC,CAAR,EAAWC,KAAX,KAAqB;IAC5DJ,QAAQ,CAACK,OAAT,CAAiBH,KAAjB,IAA0B;MAAEI,EAAE,EAAEH,CAAN;MAASI,EAAE,EAAEJ,CAAC,GAAGC;IAAjB,CAA1B;;IAEA,IAAIT,4BAA4B,CAACK,QAAQ,CAACK,OAAV,EAAmBR,WAAnB,CAAhC,EAAiE;MAC7DE,cAAc,CAAC,CAAC,GAAGC,QAAQ,CAACK,OAAb,CAAD,CAAd;MAEAL,QAAQ,CAACK,OAAT,GAAmB,EAAnB;IACH;EACJ,CARD;;EAUA,OAAO,CAACP,WAAD,EAAcG,gBAAd,CAAP;AACH"}
@@ -0,0 +1,9 @@
1
+ import { Children } from 'react';
2
+ import { isEveryDefined } from '@fountain-ui/utils';
3
+ export function isEveryTabCoordinatesDefined(coordinates, tabElements) {
4
+ const numberOfTabs = Children.count(tabElements);
5
+ const numberOfCoordinates = coordinates.length;
6
+ const everyCoordinatesDefined = isEveryDefined(coordinates);
7
+ return numberOfTabs === numberOfCoordinates && everyCoordinatesDefined;
8
+ }
9
+ //# sourceMappingURL=utils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["Children","isEveryDefined","isEveryTabCoordinatesDefined","coordinates","tabElements","numberOfTabs","count","numberOfCoordinates","length","everyCoordinatesDefined"],"sources":["utils.ts"],"sourcesContent":["import type { ReactNode } from 'react';\nimport { Children } from 'react';\nimport { isEveryDefined } from '@fountain-ui/utils';\nimport type TabCoordinate from './TabCoordinate';\n\n\nexport function isEveryTabCoordinatesDefined(coordinates: TabCoordinate[], tabElements: ReactNode): boolean {\n const numberOfTabs = Children.count(tabElements);\n const numberOfCoordinates = coordinates.length;\n\n const everyCoordinatesDefined = isEveryDefined(coordinates);\n\n return numberOfTabs === numberOfCoordinates && everyCoordinatesDefined;\n}\n"],"mappings":"AACA,SAASA,QAAT,QAAyB,OAAzB;AACA,SAASC,cAAT,QAA+B,oBAA/B;AAIA,OAAO,SAASC,4BAAT,CAAsCC,WAAtC,EAAoEC,WAApE,EAAqG;EACxG,MAAMC,YAAY,GAAGL,QAAQ,CAACM,KAAT,CAAeF,WAAf,CAArB;EACA,MAAMG,mBAAmB,GAAGJ,WAAW,CAACK,MAAxC;EAEA,MAAMC,uBAAuB,GAAGR,cAAc,CAACE,WAAD,CAA9C;EAEA,OAAOE,YAAY,KAAKE,mBAAjB,IAAwCE,uBAA/C;AACH"}
@@ -3,6 +3,7 @@ export { default as useCollapsibleAppBar } from './useCollapsibleAppBar';
3
3
  export { default as useContentContainerStyle } from './useContentContainerStyle';
4
4
  export { default as useElevationStyle } from './useElevationStyle';
5
5
  export { default as useFadeInAppBar } from './useFadeInAppBar';
6
+ export { default as useImperativeState } from './useImperativeState';
6
7
  export { default as useSyncAnimatedValue } from './useSyncAnimatedValue';
7
8
  export { default as useThrottle } from './useThrottle';
8
9
  export { default as useValidWindowDimensions } from './useValidWindowDimensions';
@@ -1 +1 @@
1
- {"version":3,"names":["default","useBreakpointUp","useCollapsibleAppBar","useContentContainerStyle","useElevationStyle","useFadeInAppBar","useSyncAnimatedValue","useThrottle","useValidWindowDimensions"],"sources":["index.ts"],"sourcesContent":["export { default as useBreakpointUp } from './useBreakpointUp';\nexport { default as useCollapsibleAppBar } from './useCollapsibleAppBar';\nexport { default as useContentContainerStyle } from './useContentContainerStyle';\nexport { default as useElevationStyle } from './useElevationStyle';\nexport { default as useFadeInAppBar } from './useFadeInAppBar';\nexport { default as useSyncAnimatedValue } from './useSyncAnimatedValue';\nexport { default as useThrottle } from './useThrottle';\nexport { default as useValidWindowDimensions } from './useValidWindowDimensions';\n"],"mappings":"AAAA,SAASA,OAAO,IAAIC,eAApB,QAA2C,mBAA3C;AACA,SAASD,OAAO,IAAIE,oBAApB,QAAgD,wBAAhD;AACA,SAASF,OAAO,IAAIG,wBAApB,QAAoD,4BAApD;AACA,SAASH,OAAO,IAAII,iBAApB,QAA6C,qBAA7C;AACA,SAASJ,OAAO,IAAIK,eAApB,QAA2C,mBAA3C;AACA,SAASL,OAAO,IAAIM,oBAApB,QAAgD,wBAAhD;AACA,SAASN,OAAO,IAAIO,WAApB,QAAuC,eAAvC;AACA,SAASP,OAAO,IAAIQ,wBAApB,QAAoD,4BAApD"}
1
+ {"version":3,"names":["default","useBreakpointUp","useCollapsibleAppBar","useContentContainerStyle","useElevationStyle","useFadeInAppBar","useImperativeState","useSyncAnimatedValue","useThrottle","useValidWindowDimensions"],"sources":["index.ts"],"sourcesContent":["export { default as useBreakpointUp } from './useBreakpointUp';\nexport { default as useCollapsibleAppBar } from './useCollapsibleAppBar';\nexport { default as useContentContainerStyle } from './useContentContainerStyle';\nexport { default as useElevationStyle } from './useElevationStyle';\nexport { default as useFadeInAppBar } from './useFadeInAppBar';\nexport { default as useImperativeState } from './useImperativeState';\nexport { default as useSyncAnimatedValue } from './useSyncAnimatedValue';\nexport { default as useThrottle } from './useThrottle';\nexport { default as useValidWindowDimensions } from './useValidWindowDimensions';\n"],"mappings":"AAAA,SAASA,OAAO,IAAIC,eAApB,QAA2C,mBAA3C;AACA,SAASD,OAAO,IAAIE,oBAApB,QAAgD,wBAAhD;AACA,SAASF,OAAO,IAAIG,wBAApB,QAAoD,4BAApD;AACA,SAASH,OAAO,IAAII,iBAApB,QAA6C,qBAA7C;AACA,SAASJ,OAAO,IAAIK,eAApB,QAA2C,mBAA3C;AACA,SAASL,OAAO,IAAIM,kBAApB,QAA8C,sBAA9C;AACA,SAASN,OAAO,IAAIO,oBAApB,QAAgD,wBAAhD;AACA,SAASP,OAAO,IAAIQ,WAApB,QAAuC,eAAvC;AACA,SAASR,OAAO,IAAIS,wBAApB,QAAoD,4BAApD"}
@@ -0,0 +1,17 @@
1
+ import { useMemo } from 'react';
2
+ export default function useImperativeState(initialValue) {
3
+ return useMemo(() => {
4
+ let prevState = initialValue;
5
+ let currentState = initialValue;
6
+ return {
7
+ hasChanged: () => prevState !== currentState,
8
+ get: () => currentState,
9
+ set: nextState => {
10
+ prevState = currentState;
11
+ currentState = nextState;
12
+ }
13
+ };
14
+ }, []);
15
+ }
16
+ ;
17
+ //# sourceMappingURL=useImperativeState.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["useMemo","useImperativeState","initialValue","prevState","currentState","hasChanged","get","set","nextState"],"sources":["useImperativeState.ts"],"sourcesContent":["import { useMemo } from 'react';\n\n\nexport interface ImperativeState<T> {\n hasChanged: () => boolean;\n get: () => T;\n set: (nextState: T) => void;\n}\n\nexport default function useImperativeState<T>(initialValue: T): ImperativeState<T> {\n return useMemo<ImperativeState<T>>(() => {\n let prevState: T = initialValue;\n let currentState: T = initialValue;\n\n return {\n hasChanged: () => prevState !== currentState,\n get: () => currentState,\n set: (nextState) => {\n prevState = currentState;\n currentState = nextState;\n },\n };\n }, []);\n};\n"],"mappings":"AAAA,SAASA,OAAT,QAAwB,OAAxB;AASA,eAAe,SAASC,kBAAT,CAA+BC,YAA/B,EAAoE;EAC/E,OAAOF,OAAO,CAAqB,MAAM;IACrC,IAAIG,SAAY,GAAGD,YAAnB;IACA,IAAIE,YAAe,GAAGF,YAAtB;IAEA,OAAO;MACHG,UAAU,EAAE,MAAMF,SAAS,KAAKC,YAD7B;MAEHE,GAAG,EAAE,MAAMF,YAFR;MAGHG,GAAG,EAAGC,SAAD,IAAe;QAChBL,SAAS,GAAGC,YAAZ;QACAA,YAAY,GAAGI,SAAf;MACH;IANE,CAAP;EAQH,CAZa,EAYX,EAZW,CAAd;AAaH;AAAA"}
@@ -1,5 +1,9 @@
1
1
  function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
2
2
 
3
+ function refEqual(a, b) {
4
+ return a === b;
5
+ }
6
+
3
7
  export default class SimpleStore {
4
8
  constructor(initialData) {
5
9
  _defineProperty(this, "data", void 0);
@@ -11,7 +15,6 @@ export default class SimpleStore {
11
15
 
12
16
  subscribe(listener) {
13
17
  this.listeners.push(listener);
14
- listener(this.data);
15
18
  return () => {
16
19
  const index = this.listeners.indexOf(listener);
17
20
  this.listeners.splice(index, 1);
@@ -19,6 +22,11 @@ export default class SimpleStore {
19
22
  }
20
23
 
21
24
  dispatch(data) {
25
+ // Do not dispatch if data ref is equal
26
+ if (refEqual(this.data, data)) {
27
+ return;
28
+ }
29
+
22
30
  this.data = data;
23
31
 
24
32
  for (const id in this.listeners) {
@@ -1 +1 @@
1
- {"version":3,"names":["SimpleStore","constructor","initialData","data","subscribe","listener","listeners","push","index","indexOf","splice","dispatch","id","removeAllListeners","length"],"sources":["SimpleStore.ts"],"sourcesContent":["import { MonoStore, StoreSubscription } from './types';\n\nexport default class SimpleStore<T> implements MonoStore<T> {\n\n private data: T;\n\n private listeners: Array<(data: T) => void> = [];\n\n constructor(initialData: T) {\n this.data = initialData;\n }\n\n subscribe(listener: (data: T) => void): StoreSubscription {\n this.listeners.push(listener);\n\n listener(this.data);\n\n return () => {\n const index = this.listeners.indexOf(listener);\n this.listeners.splice(index, 1);\n };\n }\n\n dispatch(data: T): void {\n this.data = data;\n for (const id in this.listeners) {\n const listener = this.listeners[id];\n listener?.(data);\n }\n }\n\n removeAllListeners(): void {\n this.listeners.splice(0, this.listeners.length);\n }\n\n};\n"],"mappings":";;AAEA,eAAe,MAAMA,WAAN,CAA6C;EAMxDC,WAAW,CAACC,WAAD,EAAiB;IAAA;;IAAA,mCAFkB,EAElB;;IACxB,KAAKC,IAAL,GAAYD,WAAZ;EACH;;EAEDE,SAAS,CAACC,QAAD,EAAiD;IACtD,KAAKC,SAAL,CAAeC,IAAf,CAAoBF,QAApB;IAEAA,QAAQ,CAAC,KAAKF,IAAN,CAAR;IAEA,OAAO,MAAM;MACT,MAAMK,KAAK,GAAG,KAAKF,SAAL,CAAeG,OAAf,CAAuBJ,QAAvB,CAAd;MACA,KAAKC,SAAL,CAAeI,MAAf,CAAsBF,KAAtB,EAA6B,CAA7B;IACH,CAHD;EAIH;;EAEDG,QAAQ,CAACR,IAAD,EAAgB;IACpB,KAAKA,IAAL,GAAYA,IAAZ;;IACA,KAAK,MAAMS,EAAX,IAAiB,KAAKN,SAAtB,EAAiC;MAC7B,MAAMD,QAAQ,GAAG,KAAKC,SAAL,CAAeM,EAAf,CAAjB;MACAP,QAAQ,SAAR,IAAAA,QAAQ,WAAR,YAAAA,QAAQ,CAAGF,IAAH,CAAR;IACH;EACJ;;EAEDU,kBAAkB,GAAS;IACvB,KAAKP,SAAL,CAAeI,MAAf,CAAsB,CAAtB,EAAyB,KAAKJ,SAAL,CAAeQ,MAAxC;EACH;;AA/BuD;AAiC3D"}
1
+ {"version":3,"names":["refEqual","a","b","SimpleStore","constructor","initialData","data","subscribe","listener","listeners","push","index","indexOf","splice","dispatch","id","removeAllListeners","length"],"sources":["SimpleStore.ts"],"sourcesContent":["import { MonoStore, StoreSubscription } from './types';\n\nfunction refEqual(a: any, b: any): boolean {\n return a === b;\n}\n\nexport default class SimpleStore<T> implements MonoStore<T> {\n\n private data: T;\n\n private listeners: Array<(data: T) => void> = [];\n\n constructor(initialData: T) {\n this.data = initialData;\n }\n\n subscribe(listener: (data: T) => void): StoreSubscription {\n this.listeners.push(listener);\n\n return () => {\n const index = this.listeners.indexOf(listener);\n this.listeners.splice(index, 1);\n };\n }\n\n dispatch(data: T): void {\n // Do not dispatch if data ref is equal\n if (refEqual(this.data, data)) {\n return;\n }\n\n this.data = data;\n for (const id in this.listeners) {\n const listener = this.listeners[id];\n listener?.(data);\n }\n }\n\n removeAllListeners(): void {\n this.listeners.splice(0, this.listeners.length);\n }\n\n};\n"],"mappings":";;AAEA,SAASA,QAAT,CAAkBC,CAAlB,EAA0BC,CAA1B,EAA2C;EACvC,OAAOD,CAAC,KAAKC,CAAb;AACH;;AAED,eAAe,MAAMC,WAAN,CAA6C;EAMxDC,WAAW,CAACC,WAAD,EAAiB;IAAA;;IAAA,mCAFkB,EAElB;;IACxB,KAAKC,IAAL,GAAYD,WAAZ;EACH;;EAEDE,SAAS,CAACC,QAAD,EAAiD;IACtD,KAAKC,SAAL,CAAeC,IAAf,CAAoBF,QAApB;IAEA,OAAO,MAAM;MACT,MAAMG,KAAK,GAAG,KAAKF,SAAL,CAAeG,OAAf,CAAuBJ,QAAvB,CAAd;MACA,KAAKC,SAAL,CAAeI,MAAf,CAAsBF,KAAtB,EAA6B,CAA7B;IACH,CAHD;EAIH;;EAEDG,QAAQ,CAACR,IAAD,EAAgB;IACpB;IACA,IAAIN,QAAQ,CAAC,KAAKM,IAAN,EAAYA,IAAZ,CAAZ,EAA+B;MAC3B;IACH;;IAED,KAAKA,IAAL,GAAYA,IAAZ;;IACA,KAAK,MAAMS,EAAX,IAAiB,KAAKN,SAAtB,EAAiC;MAC7B,MAAMD,QAAQ,GAAG,KAAKC,SAAL,CAAeM,EAAf,CAAjB;MACAP,QAAQ,SAAR,IAAAA,QAAQ,WAAR,YAAAA,QAAQ,CAAGF,IAAH,CAAR;IACH;EACJ;;EAEDU,kBAAkB,GAAS;IACvB,KAAKP,SAAL,CAAeI,MAAf,CAAsB,CAAtB,EAAyB,KAAKJ,SAAL,CAAeQ,MAAxC;EACH;;AAlCuD;AAoC3D"}
@@ -3,5 +3,6 @@ import React from 'react';
3
3
  export interface IndexAwareTabProps {
4
4
  children: ReactElement;
5
5
  index: number;
6
+ initialIndex: number;
6
7
  }
7
8
  export default function IndexAwareTab(props: IndexAwareTabProps): ReactElement<any, string | React.JSXElementConstructor<any>>;
@@ -1,7 +1,6 @@
1
1
  import React from 'react';
2
2
  import TabCoordinate from './TabCoordinate';
3
- export interface UseTabCoordinates {
4
- coordinates: TabCoordinate[];
5
- updateCoordinate: (index: number, x: number, width: number) => void;
3
+ export interface UpdateCoordinate {
4
+ (index: number, x: number, width: number): void;
6
5
  }
7
- export default function useTabCoordinates(tabElements: React.ReactNode): UseTabCoordinates;
6
+ export default function useTabCoordinates(tabElements: React.ReactNode): [TabCoordinate[], UpdateCoordinate];
@@ -0,0 +1,3 @@
1
+ import type { ReactNode } from 'react';
2
+ import type TabCoordinate from './TabCoordinate';
3
+ export declare function isEveryTabCoordinatesDefined(coordinates: TabCoordinate[], tabElements: ReactNode): boolean;
@@ -3,6 +3,7 @@ export { default as useCollapsibleAppBar } from './useCollapsibleAppBar';
3
3
  export { default as useContentContainerStyle } from './useContentContainerStyle';
4
4
  export { default as useElevationStyle } from './useElevationStyle';
5
5
  export { default as useFadeInAppBar } from './useFadeInAppBar';
6
+ export { default as useImperativeState } from './useImperativeState';
6
7
  export { default as useSyncAnimatedValue } from './useSyncAnimatedValue';
7
8
  export { default as useThrottle } from './useThrottle';
8
9
  export { default as useValidWindowDimensions } from './useValidWindowDimensions';
@@ -0,0 +1,6 @@
1
+ export interface ImperativeState<T> {
2
+ hasChanged: () => boolean;
3
+ get: () => T;
4
+ set: (nextState: T) => void;
5
+ }
6
+ export default function useImperativeState<T>(initialValue: T): ImperativeState<T>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fountain-ui/core",
3
- "version": "2.0.0-beta.18",
3
+ "version": "2.0.0-beta.20",
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": "9c4af6d69493666d86b7736892f778af775a3c80"
70
+ "gitHead": "8ca13c00c2424b287a26c7cb62619c2c0a9596df"
71
71
  }
@@ -5,15 +5,17 @@ import InternalContext from './InternalContext';
5
5
  export interface IndexAwareTabProps {
6
6
  children: ReactElement;
7
7
  index: number;
8
+ initialIndex: number;
8
9
  }
9
10
 
10
11
  export default function IndexAwareTab(props: IndexAwareTabProps) {
11
12
  const {
12
13
  children,
13
14
  index,
15
+ initialIndex,
14
16
  } = props;
15
17
 
16
- const [selected, setSelected] = useState(false);
18
+ const [selected, setSelected] = useState(initialIndex === index);
17
19
 
18
20
  const { indexStore } = useContext(InternalContext);
19
21
 
package/src/Tabs/Tabs.tsx CHANGED
@@ -1,4 +1,4 @@
1
- import React, { cloneElement, forwardRef, useImperativeHandle } from 'react';
1
+ import React, { cloneElement, forwardRef, useEffect, useImperativeHandle } from 'react';
2
2
  import type { GestureResponderEvent, LayoutChangeEvent } from 'react-native';
3
3
  import { View } from 'react-native';
4
4
  import { NamedStylesStringUnion, UseStyles } from '@fountain-ui/styles';
@@ -12,6 +12,7 @@ import IndexAwareTab from './IndexAwareTab';
12
12
  import useTabCoordinates from './useTabCoordinates';
13
13
  import useIndexStore from './useIndexStore';
14
14
  import InternalContext from './InternalContext';
15
+ import { isEveryTabCoordinatesDefined } from './utils';
15
16
 
16
17
  type TabsStyleKeys =
17
18
  | 'root'
@@ -70,11 +71,17 @@ const Tabs = forwardRef<TabsInstance, TabsProps>(function Tabs(props, ref) {
70
71
 
71
72
  const styles = useStyles();
72
73
 
73
- const { coordinates, updateCoordinate } = useTabCoordinates(children);
74
+ const [coordinates, updateCoordinate] = useTabCoordinates(children);
75
+
76
+ const canRenderIndicator = isEveryTabCoordinatesDefined(coordinates, children);
74
77
 
75
78
  const indexStore = useIndexStore(sharedIndex);
76
79
 
77
- const isReadyToRenderIndicator = coordinates.length > 0;
80
+ useEffect(() => {
81
+ return indexStore.subscribe(newIndex => {
82
+ onChange?.(newIndex);
83
+ });
84
+ }, [indexStore, onChange]);
78
85
 
79
86
  const tabElements = React.Children.map(children, (child, index) => {
80
87
  const onLayout = (event: LayoutChangeEvent) => {
@@ -92,14 +99,13 @@ const Tabs = forwardRef<TabsInstance, TabsProps>(function Tabs(props, ref) {
92
99
  const onPress = () => {
93
100
  setTab(index);
94
101
 
95
- onChange?.(index);
96
102
  // @ts-ignore
97
103
  child.props.onPress?.();
98
104
  };
99
105
 
100
106
  // @ts-ignore
101
107
  const tabElement = cloneElement(child, {
102
- enableIndicator: !disableIndicator && !isReadyToRenderIndicator,
108
+ enableIndicator: !disableIndicator && !canRenderIndicator,
103
109
  onLayout,
104
110
  onPress,
105
111
  onMouseDown,
@@ -111,11 +117,12 @@ const Tabs = forwardRef<TabsInstance, TabsProps>(function Tabs(props, ref) {
111
117
  <IndexAwareTab
112
118
  children={tabElement}
113
119
  index={index}
120
+ initialIndex={initialIndex}
114
121
  />
115
122
  );
116
123
  });
117
124
 
118
- const tabIndicator = isReadyToRenderIndicator ? (
125
+ const tabIndicator = canRenderIndicator ? (
119
126
  <TabIndicator
120
127
  coordinates={coordinates}
121
128
  disabled={disableIndicator}
@@ -1,36 +1,25 @@
1
1
  import React, { useRef, useState } from 'react';
2
- import { isEveryDefined } from '@fountain-ui/utils';
3
2
  import TabCoordinate from './TabCoordinate';
3
+ import { isEveryTabCoordinatesDefined } from './utils';
4
4
 
5
- export interface UseTabCoordinates {
6
- coordinates: TabCoordinate[];
7
- updateCoordinate: (index: number, x: number, width: number) => void;
5
+ export interface UpdateCoordinate {
6
+ (index: number, x: number, width: number): void;
8
7
  }
9
8
 
10
- export default function useTabCoordinates(tabElements: React.ReactNode): UseTabCoordinates {
11
- const incompleteCoordinatesRef = useRef<TabCoordinate[]>([]);
9
+ export default function useTabCoordinates(tabElements: React.ReactNode): [TabCoordinate[], UpdateCoordinate] {
10
+ const [coordinates, setCoordinates] = useState<TabCoordinate[]>([]);
12
11
 
13
- const [completeCoordinates, setCompleteCoordinates] = useState<TabCoordinate[]>([]);
12
+ const cacheRef = useRef<TabCoordinate[]>([]);
14
13
 
15
- const isAllCoordinatesDefined = (coordinates: TabCoordinate[]): boolean => {
16
- const numberOfTab = React.Children.count(tabElements);
17
- const numberOfCoordinates = coordinates.length;
14
+ const updateCoordinate: UpdateCoordinate = (index, x, width) => {
15
+ cacheRef.current[index] = { x1: x, x2: x + width };
18
16
 
19
- const everyCoordinatesDefined = isEveryDefined(coordinates);
17
+ if (isEveryTabCoordinatesDefined(cacheRef.current, tabElements)) {
18
+ setCoordinates([...cacheRef.current]);
20
19
 
21
- return numberOfTab === numberOfCoordinates && everyCoordinatesDefined;
22
- };
23
-
24
- const updateCoordinate = (index: number, x: number, width: number) => {
25
- incompleteCoordinatesRef.current[index] = { x1: x, x2: x + width };
26
-
27
- if (isAllCoordinatesDefined(incompleteCoordinatesRef.current)) {
28
- setCompleteCoordinates(incompleteCoordinatesRef.current);
20
+ cacheRef.current = [];
29
21
  }
30
22
  };
31
23
 
32
- return {
33
- coordinates: completeCoordinates,
34
- updateCoordinate,
35
- };
24
+ return [coordinates, updateCoordinate];
36
25
  }
@@ -0,0 +1,14 @@
1
+ import type { ReactNode } from 'react';
2
+ import { Children } from 'react';
3
+ import { isEveryDefined } from '@fountain-ui/utils';
4
+ import type TabCoordinate from './TabCoordinate';
5
+
6
+
7
+ export function isEveryTabCoordinatesDefined(coordinates: TabCoordinate[], tabElements: ReactNode): boolean {
8
+ const numberOfTabs = Children.count(tabElements);
9
+ const numberOfCoordinates = coordinates.length;
10
+
11
+ const everyCoordinatesDefined = isEveryDefined(coordinates);
12
+
13
+ return numberOfTabs === numberOfCoordinates && everyCoordinatesDefined;
14
+ }
@@ -3,6 +3,7 @@ export { default as useCollapsibleAppBar } from './useCollapsibleAppBar';
3
3
  export { default as useContentContainerStyle } from './useContentContainerStyle';
4
4
  export { default as useElevationStyle } from './useElevationStyle';
5
5
  export { default as useFadeInAppBar } from './useFadeInAppBar';
6
+ export { default as useImperativeState } from './useImperativeState';
6
7
  export { default as useSyncAnimatedValue } from './useSyncAnimatedValue';
7
8
  export { default as useThrottle } from './useThrottle';
8
9
  export { default as useValidWindowDimensions } from './useValidWindowDimensions';
@@ -0,0 +1,24 @@
1
+ import { useMemo } from 'react';
2
+
3
+
4
+ export interface ImperativeState<T> {
5
+ hasChanged: () => boolean;
6
+ get: () => T;
7
+ set: (nextState: T) => void;
8
+ }
9
+
10
+ export default function useImperativeState<T>(initialValue: T): ImperativeState<T> {
11
+ return useMemo<ImperativeState<T>>(() => {
12
+ let prevState: T = initialValue;
13
+ let currentState: T = initialValue;
14
+
15
+ return {
16
+ hasChanged: () => prevState !== currentState,
17
+ get: () => currentState,
18
+ set: (nextState) => {
19
+ prevState = currentState;
20
+ currentState = nextState;
21
+ },
22
+ };
23
+ }, []);
24
+ };
@@ -1,5 +1,9 @@
1
1
  import { MonoStore, StoreSubscription } from './types';
2
2
 
3
+ function refEqual(a: any, b: any): boolean {
4
+ return a === b;
5
+ }
6
+
3
7
  export default class SimpleStore<T> implements MonoStore<T> {
4
8
 
5
9
  private data: T;
@@ -13,8 +17,6 @@ export default class SimpleStore<T> implements MonoStore<T> {
13
17
  subscribe(listener: (data: T) => void): StoreSubscription {
14
18
  this.listeners.push(listener);
15
19
 
16
- listener(this.data);
17
-
18
20
  return () => {
19
21
  const index = this.listeners.indexOf(listener);
20
22
  this.listeners.splice(index, 1);
@@ -22,6 +24,11 @@ export default class SimpleStore<T> implements MonoStore<T> {
22
24
  }
23
25
 
24
26
  dispatch(data: T): void {
27
+ // Do not dispatch if data ref is equal
28
+ if (refEqual(this.data, data)) {
29
+ return;
30
+ }
31
+
25
32
  this.data = data;
26
33
  for (const id in this.listeners) {
27
34
  const listener = this.listeners[id];