import React, {createRef, useRef, useMemo, useEffect, useState} from 'react' import {observer} from 'mobx-react-lite' import { ScrollView, StyleSheet, Text, TouchableWithoutFeedback, View, } from 'react-native' import Animated, { interpolate, useSharedValue, useAnimatedStyle, withTiming, runOnJS, } from 'react-native-reanimated' import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome' import Swipeable from 'react-native-gesture-handler/Swipeable' import {useStores} from '../../../state' import {s, colors} from '../../lib/styles' import {match} from '../../routes' import {LinkActionsModel} from '../../../state/models/shell-ui' const TAB_HEIGHT = 42 export const TabsSelector = observer( ({active, onClose}: {active: boolean; onClose: () => void}) => { const store = useStores() const [closingTabIndex, setClosingTabIndex] = useState( undefined, ) const initInterp = useSharedValue(0) const closeInterp = useSharedValue(0) const tabsRef = useRef(null) const tabRefs = useMemo( () => Array.from({length: store.nav.tabs.length}).map(() => createRef(), ), [store.nav.tabs.length], ) useEffect(() => { if (active) { initInterp.value = withTiming(1, {duration: 150}) } else { initInterp.value = 0 } }, [initInterp, active]) const wrapperAnimStyle = useAnimatedStyle(() => ({ bottom: interpolate(initInterp.value, [0, 1.0], [50, 75]), })) // events // = const onPressNewTab = () => { store.nav.newTab('/') onClose() } const onPressCloneTab = () => { store.nav.newTab(store.nav.tab.current.url) onClose() } const onPressShareTab = () => { onClose() store.shell.openModal( new LinkActionsModel( store.nav.tab.current.url, store.nav.tab.current.title || 'This Page', {newTab: false}, ), ) } const onPressChangeTab = (tabIndex: number) => { store.nav.setActiveTab(tabIndex) onClose() } const doCloseTab = (index: number) => store.nav.closeTab(index) const onCloseTab = (tabIndex: number) => { setClosingTabIndex(tabIndex) closeInterp.value = 0 closeInterp.value = withTiming(1, {duration: 300}, () => { runOnJS(setClosingTabIndex)(undefined) runOnJS(doCloseTab)(tabIndex) }) } const onLayout = () => { // focus the current tab const targetTab = tabRefs[store.nav.tabIndex] if (tabsRef.current && targetTab.current) { targetTab.current.measureLayout?.( tabsRef.current, (_left: number, top: number) => { tabsRef.current?.scrollTo({y: top, animated: false}) }, () => {}, ) } } // rendering // = const renderSwipeActions = () => { return } const currentTabIndex = store.nav.tabIndex const closingTabAnimStyle = useAnimatedStyle(() => ({ height: TAB_HEIGHT * (1 - closeInterp.value), opacity: 1 - closeInterp.value, marginBottom: 4 * (1 - closeInterp.value), })) if (!active) { return } return ( <> Share Clone tab New tab {store.nav.tabs.map((tab, tabIndex) => { const {icon} = match(tab.current.url) const isActive = tabIndex === currentTabIndex const isClosing = closingTabIndex === tabIndex return ( onCloseTab(tabIndex)}> onPressChangeTab(tabIndex)}> {tab.current.title || tab.current.url} onCloseTab(tabIndex)}> ) })} ) }, ) const styles = StyleSheet.create({ bg: { position: 'absolute', top: 0, right: 0, bottom: 0, left: 0, backgroundColor: '#000', opacity: 0.2, }, wrapper: { position: 'absolute', // bottom: 75, width: '100%', backgroundColor: '#fff', borderRadius: 8, opacity: 1, }, section: { borderBottomColor: colors.gray2, borderBottomWidth: 1, }, sectionGrayBg: { backgroundColor: colors.gray1, borderBottomLeftRadius: 8, borderBottomRightRadius: 8, }, fatMenuItems: { flexDirection: 'row', marginTop: 10, marginBottom: 10, }, fatMenuItem: { width: 80, alignItems: 'center', marginRight: 6, }, fatMenuItemMargin: { marginRight: 14, }, fatMenuItemIconWrapper: { borderRadius: 6, width: 60, height: 60, justifyContent: 'center', alignItems: 'center', marginBottom: 5, shadowColor: '#000', shadowOpacity: 0.2, shadowOffset: {width: 0, height: 2}, shadowRadius: 2, }, fatMenuItemIcon: { color: colors.white, }, fatMenuImage: { borderRadius: 30, width: 60, height: 60, marginBottom: 5, }, fatMenuItemLabel: { fontSize: 13, }, tabs: { height: 240, }, tabOuter: { height: TAB_HEIGHT + 4, overflow: 'hidden', }, tab: { flexDirection: 'row', height: TAB_HEIGHT, backgroundColor: colors.gray1, alignItems: 'center', borderRadius: 4, }, tabInner: { flexDirection: 'row', flex: 1, alignItems: 'center', paddingLeft: 12, paddingVertical: 12, }, existing: { borderColor: colors.gray4, borderWidth: 1, }, active: { backgroundColor: colors.white, borderColor: colors.black, borderWidth: 1, }, tabIcon: {}, tabText: { flex: 1, paddingHorizontal: 10, fontSize: 16, }, tabTextActive: { fontWeight: '500', }, tabClose: { paddingVertical: 16, paddingRight: 16, }, tabCloseIcon: { color: '#655', }, btns: { flexDirection: 'row', paddingTop: 2, }, btn: { flexDirection: 'row', flex: 1, alignItems: 'center', justifyContent: 'center', backgroundColor: colors.gray1, borderRadius: 4, marginRight: 5, paddingLeft: 12, paddingRight: 16, paddingVertical: 10, }, btnIcon: { marginRight: 8, }, btnText: { fontWeight: '500', fontSize: 16, }, })