Skip to content

Commit

Permalink
Merge pull request #3 from 10play/test-merge
Browse files Browse the repository at this point in the history
Test merge
  • Loading branch information
GuySerfaty authored Feb 4, 2024
2 parents 08aa581 + 9aedcfe commit 95dea83
Show file tree
Hide file tree
Showing 17 changed files with 690 additions and 166 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ jsconfig.json
#
build/
!src/editor/build
!example/src/Examples/Advanced/Editor/build
*.pbxuser
!default.pbxuser
*.mode1v3
Expand Down
7 changes: 6 additions & 1 deletion example/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
"scripts": {
"android": "react-native run-android && yarn reverse-android",
"reverse-android": "adb reverse tcp:3000 tcp:3000",
"editor:dev": "vite --config ./src/Examples/Advanced/Editor/vite.config.ts",
"editor:build": "vite --config ./src/Examples/Advanced/Editor/vite.config.ts build",
"ios": "react-native run-ios",
"start": "react-native start",
"build:android": "cd android && ./gradlew assembleDebug --no-daemon --console=plain -PreactNativeArchitectures=arm64-v8a",
Expand All @@ -26,9 +28,12 @@
"@react-native/babel-preset": "0.73.19",
"@react-native/metro-config": "0.73.3",
"@react-native/typescript-config": "0.73.1",
"@tiptap/pm": "^2.2.1",
"@tiptap/react": "^2.2.1",
"babel-plugin-inline-import": "^3.0.0",
"babel-plugin-module-resolver": "^5.0.0",
"pod-install": "^0.1.0"
"pod-install": "^0.1.0",
"vite": "^5.0.12"
},
"engines": {
"node": ">=18"
Expand Down
5 changes: 5 additions & 0 deletions example/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
import { Basic } from './Examples/Basic';
import { CustomKeyboardExample } from './Examples/CustomKeyboardExample';
import { EditorStickToKeyboardExample } from './Examples/EditorStickToKeyboardExample';
import { Advanced } from './Examples/Advanced/AdvancedRichText';

const examples = [
{
Expand All @@ -22,6 +23,10 @@ const examples = [
name: 'EditorStickToKeyboardExample',
component: EditorStickToKeyboardExample,
},
{
name: 'Advanced',
component: Advanced,
},
];

const HomeScreen = ({ navigation }: NativeStackScreenProps<any, any, any>) => {
Expand Down
85 changes: 85 additions & 0 deletions example/src/Examples/Advanced/AdvancedRichText.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
import type { NativeStackScreenProps } from '@react-navigation/native-stack';
import React, { useRef } from 'react';
import {
SafeAreaView,
View,
KeyboardAvoidingView,
Platform,
StyleSheet,
} from 'react-native';
import {
ColorBridge,
HighlightBridge,
ImageBridge,
LinkBridge,
RichText,
TaskListBridge,
TenTapStartKit,
Toolbar,
UnderlineBridge,
useEditor,
} from 'tentap';

// @ts-ignore
import AdvancedEditor from './Editor/build/index.html';
import { CustomKeyboard } from '../../../../src/RichText/Keyboard';
import { ColorKeyboard } from '../../../../src/RichText/Keyboard/ColorKeyboard';

const exampleStyles = StyleSheet.create({
fullScreen: {
flex: 1,
},
keyboardAvoidingView: {
position: 'absolute',
width: '100%',
bottom: 0,
},
});

export const Advanced = ({}: NativeStackScreenProps<any, any, any>) => {
const editor = useEditor({
initialContent: `<p>This is a basic example of implementing images.</p><img src="https://source.unsplash.com/8xznAGy4HcY/800x400" /><p>s</p>`,
plugins: [
TenTapStartKit,
UnderlineBridge,
ImageBridge,
TaskListBridge,
LinkBridge,
ColorBridge,
HighlightBridge,
],
});
const TapRef = useRef(null);
const [activeKeyboard, setActiveKeyboard] = React.useState<string>();

return (
<SafeAreaView style={exampleStyles.fullScreen} ref={TapRef}>
<View style={exampleStyles.fullScreen}>
<RichText
avoidIosKeyboard
editor={editor}
autofocus
customSource={AdvancedEditor}
/>
</View>
<KeyboardAvoidingView
behavior={Platform.OS === 'ios' ? 'padding' : 'height'}
style={exampleStyles.keyboardAvoidingView}
>
<Toolbar
activeKeyboard={activeKeyboard}
setActiveKeyboard={setActiveKeyboard}
editor={editor}
hidden={false}
/>
<CustomKeyboard
rootRef={TapRef}
activeKeyboardID={activeKeyboard}
setActiveKeyboardID={setActiveKeyboard}
keyboards={[ColorKeyboard]}
editor={editor}
/>
</KeyboardAvoidingView>
</SafeAreaView>
);
};
9 changes: 9 additions & 0 deletions example/src/Examples/Advanced/Editor/AdvancedEditor.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import React from 'react';
import { EditorContent } from '@tiptap/react';
import { useTenTap } from 'tentap';

export const AdvancedEditor = () => {
const editor = useTenTap();

return <EditorContent editor={editor} />;
};
233 changes: 233 additions & 0 deletions example/src/Examples/Advanced/Editor/build/index.html

Large diffs are not rendered by default.

33 changes: 33 additions & 0 deletions example/src/Examples/Advanced/Editor/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>RichTextEditor</title>
</head>
<style>
body {
margin: 0;
padding: 0;
}
#root > div {
overflow: auto;
height: 100%;
position: absolute;
width: 100%;
top: 0;
bottom: 0;
}
#root div .ProseMirror {
height: 100%;
overflow: auto;
}
.ProseMirror:focus {
outline: none;
}
</style>
<body>
<div id="root"></div>
<script type="module" src="/index.tsx"></script>
</body>
</html>
10 changes: 10 additions & 0 deletions example/src/Examples/Advanced/Editor/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import React from 'react';
import { createRoot } from 'react-dom/client';
import { AdvancedEditor } from './AdvancedEditor';

/**
* This is the entrypoint for the "web" part of our editor that will be built with vite
*/
const container = document.getElementById('root');
const root = createRoot(container!);
root.render(<AdvancedEditor />);
25 changes: 25 additions & 0 deletions example/src/Examples/Advanced/Editor/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
{
"$schema": "https://json.schemastore.org/tsconfig",
"_version": "2.0.0",
"compilerOptions": {
"lib": ["dom", "dom.iterable", "esnext"],
"module": "esnext",
"moduleResolution": "bundler",
"target": "es2015",

"allowJs": true,
"allowSyntheticDefaultImports": true,
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"isolatedModules": true,
"jsx": "react-jsx",
"noEmit": true,
"noFallthroughCasesInSwitch": true,
"resolveJsonModule": true,
"skipLibCheck": true,
"strict": true,
"paths": {
"tentap": ["../../../../../src/Editor/useTenTap"]
}
},
}
28 changes: 28 additions & 0 deletions example/src/Examples/Advanced/Editor/vite.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { resolve } from 'path';
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
import { viteSingleFile } from 'vite-plugin-singlefile';

// This config is used to build the web editor into a single file

export default defineConfig({
root: 'src/Examples/Advanced/Editor/',
build: {
outDir: 'build',
},
resolve: {
alias: [
{
find: 'tentap',
replacement: resolve(
__dirname,
'../../../../../src/Editor/useTenTap.tsx'
),
},
],
},
plugins: [react(), viteSingleFile()],
server: {
port: 3000,
},
});
9 changes: 9 additions & 0 deletions example/src/Examples/Advanced/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# Advanced Editor

1. Create index.html (or use one from lib?)
2. Create entrypoint index.tsx
3. Create tsconfig
4. Add to ignore on root tsconfig
5. Add commands to package.json
6. In entry point use useTenTap
7. Add -D @tiptap/react @tiptap/pm
125 changes: 3 additions & 122 deletions src/Editor/Tiptap.tsx
Original file line number Diff line number Diff line change
@@ -1,127 +1,8 @@
import debounce from 'lodash/debounce';
import React, { useEffect } from 'react';
import { EditorContent, useEditor } from '@tiptap/react';
import { Editor } from '@tiptap/core';
// import TextStyle from '@tiptap/extension-text-style';
// import { Color } from '@tiptap/extension-color';
// import Highlight from '@tiptap/extension-highlight';
import { EditorMessage, EditorMessageType } from '../types/Messaging';
import { EditorUpdateSettings } from '../types/Actions';
import focusListener from './utils/focusListener';
import { TenTapStartKit } from './plugins/StarterKit';
import { UnderlineBridge } from './plugins/underline';
import { EditorState } from '../types/EditorState';
import { TaskListBridge } from './plugins/tasklist';
import { LinkBridge } from './plugins/link';
import { ColorBridge } from './plugins/color';
import { HighlightBridge } from './plugins/highlight';
import { CoreBridge } from './plugins/core';
import { ImageBridge } from './plugins/image';
// import { blueBackgroundPlugin } from './plugins/HighlightSelection';

const tenTapExtensions = [
// blueBackgroundPlugin,
TenTapStartKit,
UnderlineBridge,
ImageBridge,
TaskListBridge,
LinkBridge,
ColorBridge,
HighlightBridge,
CoreBridge,
].filter(
(e) => !window.whiteListPlugins || window.whiteListPlugins.includes(e.name)
);

function filterExists<T>(object: T): object is NonNullable<T> {
return object !== null && object !== undefined;
}

const extensions = tenTapExtensions
.map((e) => e.tiptapExtension)
.filter(filterExists)
.flat();

const content = window.initialContent || '';

const sendMessage = (message: EditorMessage) => {
// @ts-ignore TODO fix type
window.ReactNativeWebView?.postMessage(JSON.stringify(message));
};

const sendStateUpdate = debounce((editor: Editor) => {
let payload = {
// core
isReady: true,
isFocused: focusListener.isFocused,
};

const state = tenTapExtensions.reduce((acc, e) => {
return Object.assign(acc, e.extendEditorState(editor));
}, payload) as EditorState;

sendMessage({
type: EditorMessageType.StateUpdate,
payload: state,
});
}, 10);
import { EditorContent } from '@tiptap/react';
import { useTenTap } from './useTenTap';

export default function Tiptap() {
const editor = useEditor({
extensions,
content,
onCreate: () =>
sendMessage({ type: EditorMessageType.EditorReady, payload: null }),
onUpdate: (onUpdate) => sendStateUpdate(onUpdate.editor),
onSelectionUpdate: (onUpdate) => sendStateUpdate(onUpdate.editor),
onTransaction: (onUpdate) => sendStateUpdate(onUpdate.editor),
});

useEffect(() => {
if (!editor) return;
// Subscribe to editor message
const handleEditorAction = (action: any) => {
tenTapExtensions.forEach((e) => {
e.onBridgeMessage(editor, action, sendMessage);
});
if (action.type === EditorUpdateSettings.UpdateScrollThresholdAndMargin) {
editor.setOptions({
editorProps: {
scrollThreshold: {
top: 0,
bottom: action.payload,
right: 0,
left: 0,
},
scrollMargin: { top: 0, bottom: action.payload, right: 0, left: 0 },
},
});
}
};
const handleWebviewMessage = (event: MessageEvent | Event) => {
if (!(event instanceof MessageEvent)) return; // TODO check android
const { type, payload } = JSON.parse(event.data) as EditorMessage;
console.log('Received message from webview', { type, payload });
switch (type) {
case EditorMessageType.Action:
if (payload.type === EditorUpdateSettings.Focus) {
editor.commands.focus(payload.payload);
}
// Handle actions
handleEditorAction(payload);
break;
}
};
// We need to listen to both window and document events because some platform get
// webview messages from window and some from document
window.addEventListener('message', handleWebviewMessage);
document.addEventListener('message', handleWebviewMessage);

return () => {
window.removeEventListener('message', handleWebviewMessage);
document.removeEventListener('message', handleWebviewMessage);
};
}, [editor]);
const editor = useTenTap();

return <EditorContent editor={editor} />;

Check warning on line 7 in src/Editor/Tiptap.tsx

View workflow job for this annotation

GitHub Actions / lint

'React' must be in scope when using JSX
}
Loading

0 comments on commit 95dea83

Please sign in to comment.