fix: delete useless files

This commit is contained in:
qinluhe 2023-04-13 19:41:31 +08:00
parent d42084f242
commit 9ed5bfa51e
20 changed files with 274 additions and 242 deletions

View File

@ -23,6 +23,7 @@
"@slate-yjs/core": "^0.3.1",
"@tanstack/react-virtual": "3.0.0-beta.54",
"@tauri-apps/api": "^1.2.0",
"dayjs": "^1.11.7",
"events": "^3.3.0",
"google-protobuf": "^3.21.2",
"i18next": "^22.4.10",
@ -32,6 +33,8 @@
"nanoid": "^4.0.0",
"protoc-gen-ts": "^0.8.5",
"react": "^18.2.0",
"react-beautiful-dnd": "^13.1.1",
"react-calendar": "^4.1.0",
"react-dom": "^18.2.0",
"react-error-boundary": "^3.1.4",
"react-i18next": "^12.2.0",
@ -44,8 +47,8 @@
"slate-react": "^0.91.9",
"ts-results": "^3.3.0",
"utf8": "^3.0.0",
"yjs": "^13.5.51",
"y-indexeddb": "^9.0.9"
"y-indexeddb": "^9.0.9",
"yjs": "^13.5.51"
},
"devDependencies": {
"@tauri-apps/cli": "^1.2.2",
@ -53,6 +56,7 @@
"@types/is-hotkey": "^0.1.7",
"@types/node": "^18.7.10",
"@types/react": "^18.0.15",
"@types/react-beautiful-dnd": "^13.1.3",
"@types/react-dom": "^18.0.6",
"@types/utf8": "^3.0.1",
"@types/uuid": "^9.0.1",
@ -70,4 +74,4 @@
"uuid": "^9.0.0",
"vite": "^4.0.0"
}
}
}

View File

@ -14,6 +14,7 @@ specifiers:
'@types/is-hotkey': ^0.1.7
'@types/node': ^18.7.10
'@types/react': ^18.0.15
'@types/react-beautiful-dnd': ^13.1.3
'@types/react-dom': ^18.0.6
'@types/utf8': ^3.0.1
'@types/uuid': ^9.0.1
@ -21,6 +22,7 @@ specifiers:
'@typescript-eslint/parser': ^5.51.0
'@vitejs/plugin-react': ^3.0.0
autoprefixer: ^10.4.13
dayjs: ^1.11.7
eslint: ^8.34.0
eslint-plugin-react: ^7.32.2
events: ^3.3.0
@ -35,6 +37,8 @@ specifiers:
prettier-plugin-tailwindcss: ^0.2.2
protoc-gen-ts: ^0.8.5
react: ^18.2.0
react-beautiful-dnd: ^13.1.1
react-calendar: ^4.1.0
react-dom: ^18.2.0
react-error-boundary: ^3.1.4
react-i18next: ^12.2.0
@ -63,6 +67,7 @@ dependencies:
'@slate-yjs/core': 0.3.1_slate@0.91.4+yjs@13.5.51
'@tanstack/react-virtual': 3.0.0-beta.54_react@18.2.0
'@tauri-apps/api': 1.2.0
dayjs: 1.11.7
events: 3.3.0
google-protobuf: 3.21.2
i18next: 22.4.10
@ -72,6 +77,8 @@ dependencies:
nanoid: 4.0.1
protoc-gen-ts: 0.8.6_ss7alqtodw6rv4lluxhr36xjoa
react: 18.2.0
react-beautiful-dnd: 13.1.1_biqbaboplfbrettd7655fr4n2y
react-calendar: 4.2.1_biqbaboplfbrettd7655fr4n2y
react-dom: 18.2.0_react@18.2.0
react-error-boundary: 3.1.4_react@18.2.0
react-i18next: 12.2.0_3yopsigl4h4eb2nqrqfsy65uwi
@ -93,6 +100,7 @@ devDependencies:
'@types/is-hotkey': 0.1.7
'@types/node': 18.14.6
'@types/react': 18.0.28
'@types/react-beautiful-dnd': 13.1.4
'@types/react-dom': 18.0.11
'@types/utf8': 3.0.1
'@types/uuid': 9.0.1
@ -1513,6 +1521,12 @@ packages:
resolution: {integrity: sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==}
dev: true
/@types/lodash.memoize/4.1.7:
resolution: {integrity: sha512-lGN7WeO4vO6sICVpf041Q7BX/9k1Y24Zo3FY0aUezr1QlKznpjzsDk3T3wvH8ofYzoK0QupN9TWcFAFZlyPwQQ==}
dependencies:
'@types/lodash': 4.14.191
dev: false
/@types/lodash/4.14.191:
resolution: {integrity: sha512-BdZ5BCCvho3EIXw6wUCXHe7rS53AIDPLE+JzwgT+OsJk53oBfbSmZZ7CX4VaRoN78N+TJpFi9QPlfIVNmJYWxQ==}
dev: false
@ -1531,6 +1545,12 @@ packages:
/@types/prop-types/15.7.5:
resolution: {integrity: sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==}
/@types/react-beautiful-dnd/13.1.4:
resolution: {integrity: sha512-4bIBdzOr0aavN+88q3C7Pgz+xkb7tz3whORYrmSj77wfVEMfiWiooIwVWFR7KM2e+uGTe5BVrXqSfb0aHeflJA==}
dependencies:
'@types/react': 18.0.28
dev: true
/@types/react-dom/18.0.11:
resolution: {integrity: sha512-O38bPbI2CWtgw/OoQoY+BRelw7uysmXbWvw3nLWO21H1HSh+GOlqPuXshJfjmpNlKiiSDG9cc1JZAaMmVdcTlw==}
dependencies:
@ -1542,6 +1562,15 @@ packages:
'@types/react': 18.0.28
dev: false
/@types/react-redux/7.1.25:
resolution: {integrity: sha512-bAGh4e+w5D8dajd6InASVIyCo4pZLJ66oLb80F9OBLO1gKESbZcRCJpTT6uLXX+HAB57zw1WTdwJdAsewuTweg==}
dependencies:
'@types/hoist-non-react-statics': 3.3.1
'@types/react': 18.0.28
hoist-non-react-statics: 3.3.2
redux: 4.2.1
dev: false
/@types/react-transition-group/4.4.5:
resolution: {integrity: sha512-juKD/eiSM3/xZYzjuzH6ZwpP+/lejltmiS3QEzV/vmb/Q8+HfDmxu+Baga8UEMGBqV88Nbg4l2hY/K2DkyaLLA==}
dependencies:
@ -1734,6 +1763,10 @@ packages:
- supports-color
dev: true
/@wojtekmaj/date-utils/1.1.3:
resolution: {integrity: sha512-rHrDuTl1cx5LYo8F4K4HVauVjwzx4LwrKfEk4br4fj4nK8JjJZ8IG6a6pBHkYmPLBQHCOEDwstb0WNXMGsmdOw==}
dev: false
/acorn-jsx/5.3.2_acorn@8.8.2:
resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==}
peerDependencies:
@ -2149,6 +2182,12 @@ packages:
shebang-command: 2.0.0
which: 2.0.2
/css-box-model/1.2.1:
resolution: {integrity: sha512-a7Vr4Q/kd/aw96bnJG332W9V9LkJO69JRcaCYDUqjp6/z0w6VcZjgAcTbgFxEPfBgdnAwlh3iwu+hLopa+flJw==}
dependencies:
tiny-invariant: 1.0.6
dev: false
/cssesc/3.0.0:
resolution: {integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==}
engines: {node: '>=4'}
@ -2158,6 +2197,10 @@ packages:
/csstype/3.1.1:
resolution: {integrity: sha512-DJR/VvkAvSZW9bTouZue2sSxDwdTN92uHjqeKVm+0dAqdfNykRzQ95tay8aXMBAAPpUiq4Qcug2L7neoRh2Egw==}
/dayjs/1.11.7:
resolution: {integrity: sha512-+Yw9U6YO5TQohxLcIkrXBeY73WP3ejHWVvx8XCk3gxvQDCTEmS48ZrSZCKciI7Bhl/uCMyxYtE9UqRILmFphkQ==}
dev: false
/debug/4.3.4:
resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==}
engines: {node: '>=6.0'}
@ -2723,6 +2766,13 @@ packages:
get-intrinsic: 1.2.0
dev: true
/get-user-locale/2.2.1:
resolution: {integrity: sha512-3814zipTZ2MvczOcppEXB3jXu+0HWwj5WmPI6//SeCnUIUaRXu7W4S54eQZTEPadlMZefE+jAlPOn+zY3tD4Qw==}
dependencies:
'@types/lodash.memoize': 4.1.7
lodash.memoize: 4.1.2
dev: false
/glob-parent/5.1.2:
resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==}
engines: {node: '>= 6'}
@ -3635,6 +3685,10 @@ packages:
p-locate: 5.0.0
dev: true
/lodash.memoize/4.1.2:
resolution: {integrity: sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==}
dev: false
/lodash.merge/4.6.2:
resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==}
dev: true
@ -3680,6 +3734,10 @@ packages:
tmpl: 1.0.5
dev: false
/memoize-one/5.2.1:
resolution: {integrity: sha512-zYiwtZUcYyXKo/np96AGZAckk+FWWsUdJ3cHGGmld7+AhvcWmQyGCYUh1hc4Q/pkOhb65dQR/pqCyK0cOaHz4Q==}
dev: false
/merge-stream/2.0.0:
resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==}
dev: false
@ -4121,6 +4179,44 @@ packages:
engines: {node: '>=10'}
dev: true
/raf-schd/4.0.3:
resolution: {integrity: sha512-tQkJl2GRWh83ui2DiPTJz9wEiMN20syf+5oKfB03yYP7ioZcJwsIK8FjrtLwH1m7C7e+Tt2yYBlrOpdT+dyeIQ==}
dev: false
/react-beautiful-dnd/13.1.1_biqbaboplfbrettd7655fr4n2y:
resolution: {integrity: sha512-0Lvs4tq2VcrEjEgDXHjT98r+63drkKEgqyxdA7qD3mvKwga6a5SscbdLPO2IExotU1jW8L0Ksdl0Cj2AF67nPQ==}
peerDependencies:
react: ^16.8.5 || ^17.0.0 || ^18.0.0
react-dom: ^16.8.5 || ^17.0.0 || ^18.0.0
dependencies:
'@babel/runtime': 7.21.0
css-box-model: 1.2.1
memoize-one: 5.2.1
raf-schd: 4.0.3
react: 18.2.0
react-dom: 18.2.0_react@18.2.0
react-redux: 7.2.9_biqbaboplfbrettd7655fr4n2y
redux: 4.2.1
use-memo-one: 1.1.3_react@18.2.0
transitivePeerDependencies:
- react-native
dev: false
/react-calendar/4.2.1_biqbaboplfbrettd7655fr4n2y:
resolution: {integrity: sha512-T5oKXD+KLy/g6bmJJkZ7E9wj0iRMesWMZcrC7q2kI6ybOsu9NlPQx8uXJzG4A4C3Sh5Xi0deznyzWIVsUpF8tA==}
peerDependencies:
react: ^16.8.0 || ^17.0.0 || ^18.0.0
react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0
dependencies:
'@types/react': 18.0.28
'@wojtekmaj/date-utils': 1.1.3
clsx: 1.2.1
get-user-locale: 2.2.1
prop-types: 15.8.1
react: 18.2.0
react-dom: 18.2.0_react@18.2.0
dev: false
/react-dom/18.2.0_react@18.2.0:
resolution: {integrity: sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==}
peerDependencies:
@ -4164,10 +4260,36 @@ packages:
/react-is/16.13.1:
resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==}
/react-is/17.0.2:
resolution: {integrity: sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==}
dev: false
/react-is/18.2.0:
resolution: {integrity: sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==}
dev: false
/react-redux/7.2.9_biqbaboplfbrettd7655fr4n2y:
resolution: {integrity: sha512-Gx4L3uM182jEEayZfRbI/G11ZpYdNAnBs70lFVMNdHJI76XYtR+7m0MN+eAs7UHBPhWXcnFPaS+9owSCJQHNpQ==}
peerDependencies:
react: ^16.8.3 || ^17 || ^18
react-dom: '*'
react-native: '*'
peerDependenciesMeta:
react-dom:
optional: true
react-native:
optional: true
dependencies:
'@babel/runtime': 7.21.0
'@types/react-redux': 7.1.25
hoist-non-react-statics: 3.3.2
loose-envify: 1.4.0
prop-types: 15.8.1
react: 18.2.0
react-dom: 18.2.0_react@18.2.0
react-is: 17.0.2
dev: false
/react-redux/8.0.5_ctrls2ti7t7iutxbwkm5ipogyy:
resolution: {integrity: sha512-Q2f6fCKxPFpkXt1qNRZdEDLlScsDWyrgSj0mliK59qU6W5gvBiKkdMEG2lJzhd1rCctf0hb6EtePPLZ2e0m1uw==}
peerDependencies:
@ -4752,6 +4874,14 @@ packages:
punycode: 2.3.0
dev: true
/use-memo-one/1.1.3_react@18.2.0:
resolution: {integrity: sha512-g66/K7ZQGYrI6dy8GLpVcMsBp4s17xNkYJVSMvTEevGy3nDxHOfE6z8BVE22+5G5x7t3+bhzrlTDB7ObrEE0cQ==}
peerDependencies:
react: ^16.8.0 || ^17.0.0 || ^18.0.0
dependencies:
react: 18.2.0
dev: false
/use-sync-external-store/1.2.0_react@18.2.0:
resolution: {integrity: sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==}
peerDependencies:

View File

@ -1,8 +1,7 @@
import { useSubscribeNode } from '../_shared/SubscribeNode.hooks';
export function useDocumentTitle(id: string) {
const { node, delta } = useSubscribeNode(id);
const { node } = useSubscribeNode(id);
return {
node,
delta
}
}
};
}

View File

@ -1,11 +1,10 @@
import { useEffect, useRef } from 'react';
import { useSubscribeNode } from '../_shared/SubscribeNode.hooks';
import { useAppDispatch } from '$app/stores/store';
import { documentActions } from '$app/stores/reducers/document/slice';
export function useNode(id: string) {
const { node, childIds, delta, isSelected } = useSubscribeNode(id);
const { node, childIds, isSelected } = useSubscribeNode(id);
const ref = useRef<HTMLDivElement>(null);
const dispatch = useAppDispatch();
@ -15,22 +14,23 @@ export function useNode(id: string) {
const rect = ref.current.getBoundingClientRect();
const scrollContainer = document.querySelector('.doc-scroller-container') as HTMLDivElement;
dispatch(documentActions.updateNodePosition({
id,
rect: {
x: rect.x,
y: rect.y + scrollContainer.scrollTop,
height: rect.height,
width: rect.width
}
}))
}, [])
dispatch(
documentActions.updateNodePosition({
id,
rect: {
x: rect.x,
y: rect.y + scrollContainer.scrollTop,
height: rect.height,
width: rect.width,
},
})
);
}, []);
return {
ref,
node,
childIds,
delta,
isSelected
}
}
isSelected,
};
}

View File

@ -7,14 +7,26 @@ import TextBlock from '../TextBlock';
import { TextDelta } from '@/appflowy_app/interfaces/document';
function NodeComponent({ id, ...props }: { id: string } & React.HTMLAttributes<HTMLDivElement>) {
const { node, childIds, delta, isSelected, ref } = useNode(id);
const { node, childIds, isSelected, ref } = useNode(id);
console.log('=====', id);
const renderBlock = useCallback((_props: { node: Node; childIds?: string[]; delta?: TextDelta[] }) => {
const renderBlock = useCallback((_props: { node: Node; childIds?: string[] }) => {
switch (_props.node.type) {
case 'text':
if (!_props.delta) return null;
return <TextBlock {..._props} delta={_props.delta} />;
case 'text': {
const delta = _props.node.data.delta;
if (!delta) return null;
return (
<TextBlock
node={{
..._props.node,
data: {
delta,
},
}}
childIds={childIds}
/>
);
}
default:
break;
}
@ -27,7 +39,6 @@ function NodeComponent({ id, ...props }: { id: string } & React.HTMLAttributes<H
{renderBlock({
node,
childIds,
delta,
})}
<div className='block-overlay' />
{isSelected ? <div className='pointer-events-none absolute inset-0 z-[-1] rounded-[4px] bg-[#E0F8FF]' /> : null}

View File

@ -11,8 +11,7 @@ export function useParseTree(documentData: DocumentData) {
dispatch(
documentActions.create({
nodes: blocks,
delta: meta.text_map,
children: meta.children_map,
children: meta.childrenMap,
})
);

View File

@ -4,7 +4,7 @@ import { useRoot } from './Root.hooks';
import Node from '../Node';
import { withErrorBoundary } from 'react-error-boundary';
import { ErrorBoundaryFallbackComponent } from '../_shared/ErrorBoundaryFallbackComponent';
import VirtualizedList from '../VirtualizerList';
import VirtualizedList from '../VirtualizedList';
import { Skeleton } from '@mui/material';
function Root({ documentData }: { documentData: DocumentData }) {

View File

@ -1,61 +0,0 @@
import { useEffect, useMemo, useRef } from "react";
import { createEditor } from "slate";
import { withReact } from "slate-react";
import * as Y from 'yjs';
import { withYjs, YjsEditor, slateNodesToInsertDelta } from '@slate-yjs/core';
import { Delta } from '@slate-yjs/core/dist/model/types';
import { TextDelta } from '@/appflowy_app/interfaces/document';
const initialValue = [{
type: 'paragraph',
children: [{ text: '' }],
}];
export function useBindYjs(delta: TextDelta[], update: (_delta: TextDelta[]) => void) {
const yTextRef = useRef<Y.XmlText>();
// Create a yjs document and get the shared type
const sharedType = useMemo(() => {
const ydoc = new Y.Doc()
const _sharedType = ydoc.get('content', Y.XmlText) as Y.XmlText;
const insertDelta = slateNodesToInsertDelta(initialValue);
// Load the initial value into the yjs document
_sharedType.applyDelta(insertDelta);
const yText = insertDelta[0].insert as Y.XmlText;
yTextRef.current = yText;
return _sharedType;
}, []);
const editor = useMemo(() => withYjs(withReact(createEditor()), sharedType), []);
useEffect(() => {
YjsEditor.connect(editor);
return () => {
yTextRef.current = undefined;
YjsEditor.disconnect(editor);
}
}, [editor]);
useEffect(() => {
const yText = yTextRef.current;
if (!yText) return;
const textEventHandler = (event: Y.YTextEvent) => {
update(event.changes.delta as TextDelta[]);
}
yText.applyDelta(delta);
yText.observe(textEventHandler);
return () => {
yText.unobserve(textEventHandler);
}
}, [delta])
return { editor }
}

View File

@ -4,8 +4,8 @@ import { Descendant, Range } from 'slate';
import { TextDelta } from '$app/interfaces/document';
import { useTextInput } from '../_shared/TextInput.hooks';
export function useTextBlock(text: string, delta: TextDelta[]) {
const { editor } = useTextInput(text, delta);
export function useTextBlock(delta: TextDelta[]) {
const { editor } = useTextInput(delta);
const [value, setValue] = useState<Descendant[]>([]);
const onChange = useCallback(

View File

@ -4,22 +4,20 @@ import { useTextBlock } from './TextBlock.hooks';
import { Node } from '@/appflowy_app/stores/reducers/document/slice';
import NodeComponent from '../Node';
import HoveringToolbar from '../_shared/HoveringToolbar';
import { TextDelta } from '@/appflowy_app/interfaces/document';
import React from 'react';
import { TextDelta } from '@/appflowy_app/interfaces/document';
function TextBlock({
node,
childIds,
placeholder,
delta,
...props
}: {
node: Node;
delta: TextDelta[];
node: Node & { data: { delta: TextDelta[] } };
childIds?: string[];
placeholder?: string;
} & React.HTMLAttributes<HTMLDivElement>) {
const { editor, value, onChange, onKeyDownCapture, onDOMBeforeInput } = useTextBlock(node.data.text!, delta);
const { editor, value, onChange, onKeyDownCapture, onDOMBeforeInput } = useTextBlock(node.data.delta);
return (
<div {...props} className={`py-[2px] ${props.className}`}>

View File

@ -1,21 +0,0 @@
import { useVirtualizer } from '@tanstack/react-virtual';
import { useRef } from 'react';
const defaultSize = 60;
export function useVirtualizerList(count: number) {
const parentRef = useRef<HTMLDivElement>(null);
const rowVirtualizer = useVirtualizer({
count,
getScrollElement: () => parentRef.current,
estimateSize: () => {
return defaultSize;
},
});
return {
rowVirtualizer,
parentRef,
};
}

View File

@ -1,13 +1,6 @@
import { useEffect, useRef } from 'react';
import { useFocused, useSlate } from 'slate-react';
<<<<<<<< HEAD:frontend/appflowy_tauri/src/appflowy_app/components/document/_shared/HoveringToolbar/index.hooks.ts
import { calcToolbarPosition } from '$app/utils/slate/toolbar';
========
import { calcToolbarPosition } from '@/appflowy_app/utils/slate/toolbar';
>>>>>>>> 341dce67d45ebe46ae55e11349a19191ac99b4cf:frontend/appflowy_tauri/src/appflowy_app/components/document/HoveringToolbar/index.hooks.ts
export function useHoveringToolbar(id: string) {
const editor = useSlate();
const inFocus = useFocused();

View File

@ -1,9 +1,5 @@
import FormatButton from './FormatButton';
<<<<<<<< HEAD:frontend/appflowy_tauri/src/appflowy_app/components/document/_shared/HoveringToolbar/index.tsx
import Portal from '../../BlockPortal';
========
import Portal from '../BlockPortal';
>>>>>>>> 341dce67d45ebe46ae55e11349a19191ac99b4cf:frontend/appflowy_tauri/src/appflowy_app/components/document/HoveringToolbar/index.tsx
import { useHoveringToolbar } from './index.hooks';
const HoveringToolbar = ({ id }: { id: string }) => {

View File

@ -1,7 +1,6 @@
import { Node } from '@/appflowy_app/stores/reducers/document/slice';
import { useAppSelector } from '@/appflowy_app/stores/store';
import { useMemo } from 'react';
import { TextDelta } from '@/appflowy_app/interfaces/document';
/**
* Subscribe to a node and its children
@ -10,37 +9,30 @@ import { TextDelta } from '@/appflowy_app/interfaces/document';
* @param id
*/
export function useSubscribeNode(id: string) {
const node = useAppSelector<Node>(state => state.document.nodes[id]);
const node = useAppSelector<Node>((state) => state.document.nodes[id]);
const childIds = useAppSelector<string[] | undefined>(state => {
const childIds = useAppSelector<string[] | undefined>((state) => {
const childrenId = state.document.nodes[id]?.children;
if (!childrenId) return;
return state.document.children[childrenId];
});
const delta = useAppSelector<TextDelta[] | undefined>(state => {
const externalType = state.document.nodes[id]?.externalType;
if (externalType !== 'text') return;
const deltaId = state.document.nodes[id]?.externalId;
if (!deltaId) return;
return state.document.delta[deltaId];
});
const isSelected = useAppSelector<boolean>(state => {
const isSelected = useAppSelector<boolean>((state) => {
return state.document.selections?.includes(id) || false;
});
// Memoize the node and its children
// So that the component will not be re-rendered when other node is changed
// It very important for performance
const memoizedNode = useMemo(() => node, [node?.id, node?.data, node?.parent, node?.type, node?.children]);
const memoizedNode = useMemo(
() => node,
[node?.id, JSON.stringify(node?.data), node?.parent, node?.type, node?.children]
);
const memoizedChildIds = useMemo(() => childIds, [JSON.stringify(childIds)]);
const memoizedDelta = useMemo(() => delta, [JSON.stringify(delta)]);
return {
node: memoizedNode,
childIds: memoizedChildIds,
delta: memoizedDelta,
isSelected
isSelected,
};
}
}

View File

@ -8,8 +8,8 @@ import { withReact } from 'slate-react';
import * as Y from 'yjs';
import { withYjs, YjsEditor, slateNodesToInsertDelta } from '@slate-yjs/core';
export function useTextInput(text: string, delta: TextDelta[]) {
const { sendDelta } = useTransact(text);
export function useTextInput(delta: TextDelta[]) {
const { sendDelta } = useTransact();
const { editor } = useBindYjs(delta, sendDelta);
return {
@ -17,49 +17,45 @@ export function useTextInput(text: string, delta: TextDelta[]) {
};
}
function useController(textId: string) {
function useController() {
const docController = useContext(DocumentControllerContext);
const update = useCallback(
(delta: TextDelta[]) => {
docController?.yTextApply(textId, delta);
docController?.applyActions([
{
type: 'update',
payload: {
block: {
data: {
delta,
},
},
},
},
]);
},
[textId]
);
const transact = useCallback(
(actions: (() => void)[]) => {
docController?.transact(actions);
},
[textId]
[docController]
);
return {
update,
transact,
};
}
function useTransact(textId: string) {
const pendingActions = useRef<(() => void)[]>([]);
const { update, transact } = useController(textId);
const sendTransact = useCallback(() => {
const actions = pendingActions.current;
transact(actions);
}, [transact]);
const debounceSendTransact = useMemo(() => debounce(sendTransact, 300), [transact]);
function useTransact() {
const { update } = useController();
const sendDelta = useCallback(
(delta: TextDelta[]) => {
const action = () => update(delta);
pendingActions.current.push(action);
debounceSendTransact();
update(delta);
},
[update, debounceSendTransact]
[update]
);
const debounceSendDelta = useMemo(() => debounce(sendDelta, 300), [sendDelta]);
return {
sendDelta,
sendDelta: debounceSendDelta,
};
}
@ -70,7 +66,7 @@ const initialValue = [
},
];
export function useBindYjs(delta: TextDelta[], update: (_delta: TextDelta[]) => void) {
function useBindYjs(delta: TextDelta[], update: (_delta: TextDelta[]) => void) {
const yTextRef = useRef<Y.XmlText>();
// Create a yjs document and get the shared type
const sharedType = useMemo(() => {
@ -102,7 +98,9 @@ export function useBindYjs(delta: TextDelta[], update: (_delta: TextDelta[]) =>
if (!yText) return;
const textEventHandler = (event: Y.YTextEvent) => {
update(event.changes.delta as TextDelta[]);
const textDelta = event.target.toDelta();
console.log('delta', textDelta);
update(textDelta);
};
yText.applyDelta(delta);
yText.observe(textEventHandler);

View File

@ -10,12 +10,14 @@ export enum BlockType {
DividerBlock = 'divider',
MediaBlock = 'media',
TableBlock = 'table',
ColumnBlock = 'column'
ColumnBlock = 'column',
}
export interface NestedBlock {
id: string;
type: BlockType;
data: Record<string, any>;
data: {
delta?: TextDelta[];
};
externalId: string;
externalType: 'text' | 'array' | 'map';
parent: string | null;
@ -29,7 +31,6 @@ export interface DocumentData {
rootId: string;
blocks: Record<string, NestedBlock>;
meta: {
text_map: Record<string, TextDelta[]>;
children_map: Record<string, string[]>;
}
childrenMap: Record<string, string[]>;
};
}

View File

@ -17,30 +17,23 @@ export class DocumentController {
return {
rootId: '',
blocks: {},
ytexts: {},
yarrays: {}
meta: {
childrenMap: {},
},
};
} else {
return null;
}
};
insert(node: {
id: string,
type: BlockType,
delta?: TextDelta[]
}, parentId: string, prevId: string) {
applyActions = (
actions: {
type: string;
payload: any;
}[]
) => {
//
}
transact(actions: (() => void)[]) {
//
}
yTextApply = (yTextId: string, delta: TextDelta[]) => {
//
}
};
dispose = async () => {
await this.backendService.close();

View File

@ -1,13 +1,12 @@
import { BlockType, NestedBlock, TextDelta } from "@/appflowy_app/interfaces/document";
import { PayloadAction, createSlice } from "@reduxjs/toolkit";
import { RegionGrid } from "./region_grid";
import { BlockType, NestedBlock, TextDelta } from '@/appflowy_app/interfaces/document';
import { PayloadAction, createSlice } from '@reduxjs/toolkit';
import { RegionGrid } from './region_grid';
export type Node = NestedBlock;
export interface NodeState {
nodes: Record<string, Node>;
children: Record<string, string[]>;
delta: Record<string, TextDelta[]>;
selections: string[];
}
@ -16,7 +15,6 @@ const regionGrid = new RegionGrid(50);
const initialState: NodeState = {
nodes: {},
children: {},
delta: {},
selections: [],
};
@ -28,42 +26,52 @@ export const documentSlice = createSlice({
return initialState;
},
create: (state, action: PayloadAction<{
nodes: Record<string, Node>;
children: Record<string, string[]>;
delta: Record<string, TextDelta[]>;
}>) => {
const { nodes, children, delta } = action.payload;
create: (
state,
action: PayloadAction<{
nodes: Record<string, Node>;
children: Record<string, string[]>;
}>
) => {
const { nodes, children } = action.payload;
state.nodes = nodes;
state.children = children;
state.delta = delta;
},
updateSelections: (state, action: PayloadAction<string[]>) => {
state.selections = action.payload;
},
setSelectionByRect: (state, action: PayloadAction<{
startX: number;
startY: number;
endX: number;
endY: number
}>) => {
setSelectionByRect: (
state,
action: PayloadAction<{
startX: number;
startY: number;
endX: number;
endY: number;
}>
) => {
const { startX, startY, endX, endY } = action.payload;
const blocks = regionGrid.getIntersectBlocks(startX, startY, endX, endY);
state.selections = blocks.map(block => block.id);
state.selections = blocks.map((block) => block.id);
},
updateNodePosition: (state, action: PayloadAction<{id: string; rect: {
x: number;
y: number;
width: number;
height: number;
}}>) => {
updateNodePosition: (
state,
action: PayloadAction<{
id: string;
rect: {
x: number;
y: number;
width: number;
height: number;
};
}>
) => {
const { id, rect } = action.payload;
const position = {
id,
...rect
...rect,
};
regionGrid.updateBlock(id, position);
},
@ -72,13 +80,13 @@ export const documentSlice = createSlice({
state.nodes[action.payload.id] = action.payload;
},
addChild: (state, action: PayloadAction<{ parentId: string, childId: string, prevId: string }>) => {
addChild: (state, action: PayloadAction<{ parentId: string; childId: string; prevId: string }>) => {
const { parentId, childId, prevId } = action.payload;
const parentChildrenId = state.nodes[parentId].children;
const children = state.children[parentChildrenId];
const prevIndex = children.indexOf(prevId);
if (prevIndex === -1) {
children.push(childId)
children.push(childId);
} else {
children.splice(prevIndex + 1, 0, childId);
}
@ -89,16 +97,11 @@ export const documentSlice = createSlice({
state.children[id] = childIds;
},
updateDelta: (state, action: PayloadAction<{ id: string; delta: TextDelta[] }>) => {
const { id, delta } = action.payload;
state.delta[id] = delta;
},
updateNode: (state, action: PayloadAction<{id: string; type?: BlockType; data?: any }>) => {
updateNode: (state, action: PayloadAction<{ id: string; data: any }>) => {
state.nodes[action.payload.id] = {
...state.nodes[action.payload.id],
...action.payload
}
...action.payload,
};
},
removeNode: (state, action: PayloadAction<string>) => {
@ -114,10 +117,7 @@ export const documentSlice = createSlice({
if (children) {
delete state.children[children];
}
// remove delta
if (data && data.text) {
delete state.delta[data.text];
}
// remove node
delete state.nodes[action.payload];
},