Skip to content

Commit

Permalink
feat: restore selections when undo/redo
Browse files Browse the repository at this point in the history
  • Loading branch information
zxch3n committed May 23, 2024
1 parent c9d0056 commit b786f15
Show file tree
Hide file tree
Showing 8 changed files with 215 additions and 48 deletions.
2 changes: 1 addition & 1 deletion examples/stories/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
"build-storybook": "storybook build"
},
"dependencies": {
"loro-crdt": "^0.16.1",
"loro-crdt": "^0.16.2",
"loro-prosemirror": "link:../..",
"prosemirror-commands": "^1.5.2",
"prosemirror-example-setup": "^1.2.2",
Expand Down
14 changes: 7 additions & 7 deletions examples/stories/pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

13 changes: 10 additions & 3 deletions examples/stories/src/stories/Editor.stories.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@

import type { Meta, StoryObj } from '@storybook/react';
import type { Meta } from '@storybook/react';

import { Editor } from './Editor';
import { Loro } from 'loro-crdt';
Expand All @@ -16,9 +16,16 @@ const meta = {
} satisfies Meta<typeof Editor>;

export default meta;
type Story = StoryObj<typeof meta>;

export const Basic: Story = {};
export const Basic = () => {
const loroARef = useRef<Loro>(createLoro());
const idA = loroARef.current.peerIdStr;
const awarenessA = useRef<CursorAwareness>(new CursorAwareness(idA));
return <div>
<Editor loro={loroARef.current} awareness={awarenessA.current} />
</div>

};

function createLoro() {
const doc = new Loro();
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
"license": "ISC",
"dependencies": {
"lib0": "^0.2.42",
"loro-crdt": "^0.16.1"
"loro-crdt": "^0.16.2"
},
"peerDependencies": {
"prosemirror-model": "^1.18.1",
Expand Down
14 changes: 7 additions & 7 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

37 changes: 21 additions & 16 deletions src/cursor-plugin.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Awareness, Container, ContainerID, Cursor, Loro, LoroList, LoroText, PeerID } from "loro-crdt";
import { EditorState, Plugin, PluginKey, Selection } from "prosemirror-state";
import { Decoration, DecorationAttrs, DecorationSet } from "prosemirror-view";
import { loroSyncPluginKey } from "./sync-plugin";
import { LoroSyncPluginState, loroSyncPluginKey } from "./sync-plugin";
import { Node } from "prosemirror-model";
import { CHILDREN_KEY, LoroDocType, LoroNode, LoroNodeMapping, WEAK_NODE_TO_LORO_CONTAINER_MAPPING } from "./lib";
import { CursorAwareness, cursorEq } from "./awareness";
Expand Down Expand Up @@ -37,10 +37,10 @@ function createDecorations(
continue;
}

const [focus, focusCursorUpdate] = cursorToAbsolutePosition(state.doc, cursor.focus, doc as LoroDocType, loroState.mapping);
const [focus, focusCursorUpdate] = cursorToAbsolutePosition(cursor.focus, doc as LoroDocType, loroState.mapping);
d.push(Decoration.widget(focus, createCursor(peer as PeerID)));
if (!cursorEq(cursor.anchor, cursor.focus)) {
const [anchor, anchorCursorUpdate] = cursorToAbsolutePosition(state.doc, cursor.anchor, doc as LoroDocType, loroState.mapping);
const [anchor, anchorCursorUpdate] = cursorToAbsolutePosition(cursor.anchor, doc as LoroDocType, loroState.mapping);
d.push(Decoration.inline(Math.min(anchor, focus), Math.max(anchor, focus), createSelection(peer as PeerID)));
if (focusCursorUpdate || anchorCursorUpdate) {
awareness.setLocal({
Expand Down Expand Up @@ -135,18 +135,7 @@ export const LoroCursorPlugin = (
const pmRootNode = view.state.doc;
if (view.hasFocus()) {
const selection = getSelection(view.state);
const anchor = absolutePositionToCursor(
pmRootNode,
selection.anchor,
loroState.doc as LoroDocType,
loroState.mapping,
);
const focus = selection.head == selection.anchor ? anchor : absolutePositionToCursor(
pmRootNode,
selection.head,
loroState.doc as LoroDocType,
loroState.mapping,
);
const { anchor, focus } = convertPmSelectionToCursors(pmRootNode, selection, loroState);
if (
current == null ||
!cursorEq(current.anchor, anchor) ||
Expand Down Expand Up @@ -184,6 +173,22 @@ export const LoroCursorPlugin = (
};


export function convertPmSelectionToCursors(pmRootNode: Node, selection: Selection, loroState: LoroSyncPluginState) {
const anchor = absolutePositionToCursor(
pmRootNode,
selection.anchor,
loroState.doc as LoroDocType,
loroState.mapping
);
const focus = selection.head == selection.anchor ? anchor : absolutePositionToCursor(
pmRootNode,
selection.head,
loroState.doc as LoroDocType,
loroState.mapping
);
return { anchor, focus };
}

function absolutePositionToCursor(pmRootNode: Node, anchor: number, doc: LoroDocType, mapping: LoroNodeMapping): Cursor | undefined {
const pos = pmRootNode.resolve(anchor);
const nodeParent = pos.node(pos.depth);
Expand Down Expand Up @@ -230,7 +235,7 @@ function absolutePositionToCursor(pmRootNode: Node, anchor: number, doc: LoroDoc
}


function cursorToAbsolutePosition(_pmRootNode: Node, cursor: Cursor, doc: LoroDocType, mapping: LoroNodeMapping): [number, Cursor | undefined] {
export function cursorToAbsolutePosition(cursor: Cursor, doc: LoroDocType, mapping: LoroNodeMapping): [number, Cursor | undefined] {
const containerId = cursor.containerId()
let index = -1;
let targetChildId: ContainerID;
Expand Down
4 changes: 2 additions & 2 deletions src/sync-plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,11 +34,11 @@ type PluginTransactionType =
};

export interface LoroSyncPluginProps {
doc: Loro;
doc: LoroDocType;
mapping?: LoroNodeMapping;
}

interface LoroSyncPluginState extends LoroSyncPluginProps {
export interface LoroSyncPluginState extends LoroSyncPluginProps {
changedBy: "local" | "import" | "checkout";
mapping: LoroNodeMapping;
snapshot?: Loro | null;
Expand Down
Loading

0 comments on commit b786f15

Please sign in to comment.