import { useEffect, useState, createContext, useContext, RefObject, SetStateAction } from "react"; import { View, Text, StyleSheet, Pressable, Keyboard } from "react-native"; import { Feather, FontAwesome6 } from "@expo/vector-icons"; import { ScrollView } from "react-native-gesture-handler"; import InsertBlockSection from "./tabs/InsertBlockSection"; import ReplaceBlockSection from "./tabs/ReplaceBlockSection"; import { findPrevTextBlockInContent, useTextBlocksContext, useBlocksContext, useKeyboardStatus } from "@react-native-blocks/core"; interface FooterButtonProps { children: React.ReactNode; onPress: () => void; style?: any; } interface FooterProps { children: React.ReactNode; style?: StyleSheet; } interface FooterContext { activeTab: "none" | "keyboard" | "add-block" | "turn-block-into"; hidden: boolean; inputRefs: RefObject; setShowSoftInputOnFocus?: SetStateAction; setActiveTab: (tab: string) => void; setHidden: (hidden: boolean) => void; } const FooterContext = createContext({ activeTab: "none", hidden: true, setActiveTab: (tab: string) => {}, setHidden: (hidden: boolean) => {} }); export const useFooterContext = () => { const context = useContext(FooterContext); if (!context) { throw new Error("useFooterContext must be used within a FooterProvider"); } return context; } Footer.ContextProvider = ({ children }) => { const [footerContext, setFooterContext] = useState({ activeTab: "", hidden: true, }); const value = { activeTab: footerContext.activeTab, hidden: footerContext.hidden, setActiveTab: (tab: string) => { setFooterContext(prevState => ({ ...prevState, activeTab: tab })); }, setHidden: (hidden: boolean) => { setFooterContext(prevState => ({ ...prevState, hidden })); } }; return ( {children} ); }; export function Footer({ children, style, } : FooterProps) { const { isKeyboardOpen, keyboardHeight } = useKeyboardStatus(); const { hidden, setActiveTab, setHidden, activeTab } = useFooterContext(); useEffect(() => { if (isKeyboardOpen) { setActiveTab("keyboard"); setHidden(false); } }, [isKeyboardOpen]); return ( ) } Footer.Button = ({ children, onPress, style } : FooterButtonProps) => { return ( [ styles.button, { opacity: pressed ? 0.5 : 1 }, style ]} > {children} ) } Footer.AddBlock = () => { const { activeTab, setActiveTab } = useFooterContext(); const { inputRefs, setShowSoftInputOnFocus } = useTextBlocksContext(); const { focusedBlockId } = useBlocksContext(); const handleOnPress = () => { setShowSoftInputOnFocus(false); setActiveTab("add-block"); Keyboard.dismiss(); requestAnimationFrame(() => { inputRefs.current[focusedBlockId].current.focus(); }) }; return ( ) } Footer.TurnBlockInto = () => { const { activeTab, setActiveTab } = useFooterContext(); const { inputRefs, setShowSoftInputOnFocus } = useTextBlocksContext(); const { focusedBlockId, blocksOrder } = useBlocksContext(); const handleOnPress = () => { setShowSoftInputOnFocus(false); setActiveTab("turn-block-into"); Keyboard.dismiss(); requestAnimationFrame(() => { inputRefs.current[focusedBlockId].current.focus(); }) }; if (blocksOrder[0] === focusedBlockId) return null; return ( ) } Footer.RemoveBlock = () => { const { setHidden, setActiveTab } = useFooterContext(); const { focusedBlockId, removeBlock, blocksOrder, blocks } = useBlocksContext(); const { inputRefs, textBasedBlocks } = useTextBlocksContext(); const handleOnPress = () => { const prevTextBlock = findPrevTextBlockInContent(focusedBlockId, blocks, textBasedBlocks); if (prevTextBlock) { setActiveTab("keyboard"); inputRefs.current[prevTextBlock.id].current.focus(); } else { setActiveTab("none"); setHidden(true); }; requestAnimationFrame(() => { removeBlock(focusedBlockId); }); } if (blocksOrder[0] === focusedBlockId) return null; return ( ) } Footer.DismissKeyboard = () => { const { setHidden, setActiveTab } = useFooterContext(); const { setShowSoftInputOnFocus } = useTextBlocksContext(); const { setFocusedBlockId } = useBlocksContext(); const handleOnPress = () => { setShowSoftInputOnFocus(true); setHidden(true); setActiveTab("none"); setFocusedBlockId(""); Keyboard.dismiss(); }; return ( ) } Footer.OpenKeyboard = () => { const { setActiveTab } = useFooterContext(); const { setShowSoftInputOnFocus, inputRefs } = useTextBlocksContext(); const { focusedBlockId } = useBlocksContext(); const handleOpenKeyboard = () => { setActiveTab("keyboard"); inputRefs.current[focusedBlockId].current.focus(); setShowSoftInputOnFocus(true); }; return ( ) } const styles = StyleSheet.create({ container: { height: 44, flexDirection: "row", boxShadow: "0px -1px 0px rgba(0, 0, 0, 0.1)" }, button: { width: 44, height: 44, justifyContent: "center", alignItems: "center", }, tabSectionContainer: { backgroundColor: "#f5f5f5", }, keyboardDown: { width: 44, height: 44, alignItems: "center", justifyContent: "center", position: "relative", paddingBottom: 4 }, keyboardArrowContainer: { position: "absolute", bottom: 8 } });