diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index dbbac6f..50d6730 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -135,9 +135,9 @@ jobs: with: path: | **/ios/Pods - key: ${{ runner.os }}-cocoapods-v2-${{ hashFiles('example/ios/Podfile.lock') }} + key: ${{ runner.os }}-cocoapods-v3-${{ hashFiles('example/ios/Podfile.lock') }} restore-keys: | - ${{ runner.os }}-cocoapods-v2- + ${{ runner.os }}-cocoapods-v3- - name: Install cocoapods if: env.turbo_cache_hit != 1 && steps.cocoapods-cache.outputs.cache-hit != 'true' diff --git a/example/src/App.tsx b/example/src/App.tsx index ce261de..99a54f9 100644 --- a/example/src/App.tsx +++ b/example/src/App.tsx @@ -9,7 +9,7 @@ import { Basic } from './Examples/Basic'; import { CustomKeyboardExample } from './Examples/CustomKeyboardExample'; import { EditorStickToKeyboardExample } from './Examples/EditorStickToKeyboardExample'; import { Advanced } from './Examples/Advanced/AdvancedRichText'; -import { Compose } from './Examples/Compose'; +import { Compose } from './Examples/Compose/Compose'; const examples = [ { diff --git a/example/src/Examples/Compose.tsx b/example/src/Examples/Compose/Compose.tsx similarity index 66% rename from example/src/Examples/Compose.tsx rename to example/src/Examples/Compose/Compose.tsx index f363671..77606d2 100644 --- a/example/src/Examples/Compose.tsx +++ b/example/src/Examples/Compose/Compose.tsx @@ -1,14 +1,13 @@ import type { NativeStackScreenProps } from '@react-navigation/native-stack'; -import React, { useRef } from 'react'; +import React from 'react'; import { SafeAreaView, View, - KeyboardAvoidingView, - Platform, StyleSheet, TouchableOpacity, Text, TextInput, + Alert, } from 'react-native'; import { ColorBridge, @@ -16,17 +15,13 @@ import { HighlightBridge, ImageBridge, LinkBridge, - RichText, TaskListBridge, TenTapStartKit, - Toolbar, UnderlineBridge, useNativeEditor, - type EditorInstance, } from 'tentap'; -import { ColorKeyboard } from '../../../src/RichText/Keyboard/ColorKeyboard'; -import { CustomKeyboard } from '../../../src/RichText/Keyboard'; -import { Icon } from './Icon'; +import { Icon } from '../Icon'; +import { ComposeRichText } from './ComposeRichText'; export const Compose = ({ navigation, @@ -47,6 +42,7 @@ export const Compose = ({ const onSendClick = async () => { const mailContent = await editor.getContent(); + Alert.alert('Mail Content', mailContent); console.log('Send Clicked! Mail content: ', mailContent); }; @@ -83,64 +79,19 @@ export const Compose = ({ /> - + ); }; -interface ComposeEditorProps { - editor: EditorInstance; -} -const ComposeEditor = ({ editor }: ComposeEditorProps) => { - const TapRef = useRef(null); - const [activeKeyboard, setActiveKeyboard] = React.useState(); - - return ( - <> - - - - - - - - - ); -}; - const exampleStyles = StyleSheet.create({ - header: { - paddingHorizontal: 14, - backgroundColor: 'white', - }, - compose: { - flex: 1, - paddingHorizontal: 14, - }, fullScreen: { flex: 1, backgroundColor: 'white', }, - keyboardAvoidingView: { - position: 'absolute', - width: '100%', - bottom: 0, + header: { + paddingHorizontal: 14, + backgroundColor: 'white', }, topBar: { flexDirection: 'row', diff --git a/example/src/Examples/Compose/ComposeRichText.tsx b/example/src/Examples/Compose/ComposeRichText.tsx new file mode 100644 index 0000000..e9cea54 --- /dev/null +++ b/example/src/Examples/Compose/ComposeRichText.tsx @@ -0,0 +1,193 @@ +import React, { useEffect, useMemo, useRef, useState } from 'react'; +import { + View, + KeyboardAvoidingView, + Platform, + StyleSheet, + TouchableOpacity, +} from 'react-native'; +import { RichText, useNativeEditorState } from '../../../../src/RichText'; +import { CustomKeyboard } from '../../../../src/RichText/Keyboard'; +import { ColorKeyboard } from '../../../../src/RichText/Keyboard/ColorKeyboard'; +import type { EditorInstance } from '../../../../src/types'; +import { icons } from '../../assets'; +import { Icon } from '../Icon'; +import { useKeyboard } from '../../../../src/utils'; + +interface ComposeRichTextProps { + editor: EditorInstance; + onSendClick: () => void; +} +export const ComposeRichText = ({ + editor, + onSendClick, +}: ComposeRichTextProps) => { + const rootRef = useRef(null); + const [activeKeyboard, setActiveKeyboard] = React.useState(); + + return ( + <> + + + + + + + + + ); +}; + +interface ComposeToolbarProps { + editor: EditorInstance; + activeKeyboard: string | undefined; + setActiveKeyboard: (keyboard: string) => void; + onSendClick: () => void; +} +interface CustomToolbarAction { + isActive: boolean; + isDisabled: boolean; + onPress: () => void; + icon: keyof typeof icons; +} +enum ToolbarType { + Main, + Link, + Formatting, +} +const ComposeToolbar = ({ editor, onSendClick }: ComposeToolbarProps) => { + const editorState = useNativeEditorState(editor); + const { isKeyboardUp } = useKeyboard(); + const [toolbarType, setToolbar] = useState(ToolbarType.Main); + + const hideToolbar = !isKeyboardUp || !editorState.isFocused; + + useEffect(() => { + if (hideToolbar) { + setToolbar(ToolbarType.Main); + } + }, [hideToolbar]); + + const formattingOptions: CustomToolbarAction[] = useMemo( + () => [ + { + isActive: true, + isDisabled: false, + onPress: () => { + setToolbar(ToolbarType.Main); + }, + icon: 'formatting', + }, + { + isActive: editorState.isBoldActive, + isDisabled: !editorState.canToggleBold, + onPress: editor.toggleBold, + icon: 'bold', + }, + { + isActive: editorState.headingLevel === 1, + isDisabled: !editorState.canToggleHeading, + onPress: () => editor.toggleHeading(1), + icon: 'h1', + }, + ], + [editor, editorState] + ); + + if (toolbarType === ToolbarType.Main) { + return ( + + setToolbar(ToolbarType.Formatting)}> + + + + + + + ); + } + + return ( + + {formattingOptions.map(({ isDisabled, isActive, icon, onPress }) => ( + + + + ))} + + ); +}; + +const composeStyles = StyleSheet.create({ + compose: { + flex: 1, + paddingHorizontal: 14, + backgroundColor: 'white', + }, + keyboardAvoidingView: { + position: 'absolute', + width: '100%', + bottom: 0, + }, + mainToolbar: { + flexDirection: 'row', + justifyContent: 'space-between', + paddingHorizontal: 8, + paddingVertical: 4, + backgroundColor: 'white', + borderTopWidth: 1, + borderTopColor: 'lightgray', + }, + formattingToolbar: { + flexDirection: 'row', + justifyContent: 'flex-start', + backgroundColor: 'white', + borderTopWidth: 1, + paddingVertical: 4, + paddingHorizontal: 8, + gap: 4, + borderTopColor: 'lightgray', + }, + button: { + width: 24, + margin: 4, + padding: 5, + }, + activeButton: { + backgroundColor: 'lightblue', + borderRadius: 10, + }, + hidden: { + display: 'none', + }, +}); diff --git a/example/src/assets/bold.svg b/example/src/assets/bold.svg new file mode 100644 index 0000000..0814a2e --- /dev/null +++ b/example/src/assets/bold.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/example/src/assets/formatting.svg b/example/src/assets/formatting.svg new file mode 100644 index 0000000..8c1fde1 --- /dev/null +++ b/example/src/assets/formatting.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/example/src/assets/h1.svg b/example/src/assets/h1.svg new file mode 100644 index 0000000..0df41f6 --- /dev/null +++ b/example/src/assets/h1.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/example/src/assets/index.ts b/example/src/assets/index.ts index f65ab45..2bff67e 100644 --- a/example/src/assets/index.ts +++ b/example/src/assets/index.ts @@ -1,7 +1,13 @@ import close from './close.svg'; import send from './send.svg'; +import formatting from './formatting.svg'; +import bold from './bold.svg'; +import h1 from './h1.svg'; export const icons = { close, send, + formatting, + bold, + h1, };