loro-prosemirror
Advanced tools
Comparing version 0.0.6 to 0.0.7
@@ -5,2 +5,10 @@ # Changelog | ||
### [0.0.7](https://github.com/loro-dev/prosemirror/compare/v0.0.6...v0.0.7) (2024-08-22) | ||
### Features | ||
* config Loro text style automatically based on ProseMirror schema ([#13](https://github.com/loro-dev/prosemirror/issues/13)) ([47afc9e](https://github.com/loro-dev/prosemirror/commit/47afc9eda4caef39f9f2d98701bf2bc61b23fa7d)) | ||
* make `undo` and `redo` as ProseMirror commands ([#12](https://github.com/loro-dev/prosemirror/issues/12)) ([b0a1bc1](https://github.com/loro-dev/prosemirror/commit/b0a1bc12da9f4fc1b6c74cf759b2427a191ae2be)) | ||
### [0.0.6](https://github.com/loro-dev/prosemirror/compare/v0.0.3...v0.0.6) (2024-07-28) | ||
@@ -7,0 +15,0 @@ |
@@ -1,5 +0,5 @@ | ||
import { Plugin, EditorState, Selection, Transaction } from 'prosemirror-state'; | ||
import { Loro, LoroMap, LoroList, LoroText, ContainerID, Awareness, PeerID, Cursor, UndoManager } from 'loro-crdt'; | ||
import { Node } from 'prosemirror-model'; | ||
import { DecorationAttrs, DecorationSet } from 'prosemirror-view'; | ||
import { Loro, LoroMap, ContainerID, LoroText, LoroList, Awareness, PeerID, Cursor, UndoManager } from 'loro-crdt'; | ||
import { EditorState, PluginKey, Plugin, Selection, Command } from 'prosemirror-state'; | ||
import { EditorView, DecorationAttrs, DecorationSet } from 'prosemirror-view'; | ||
import { Node, Schema } from 'prosemirror-model'; | ||
@@ -15,7 +15,13 @@ type LoroChildrenListType = LoroList<LoroMap<LoroNodeContainerType> | LoroText>; | ||
}>; | ||
type LoroNode = LoroMap<LoroNodeContainerType>; | ||
type LoroNodeMapping = Map<ContainerID, Node | Node[]>; | ||
declare const ROOT_DOC_KEY = "doc"; | ||
declare const ATTRIBUTES_KEY = "attributes"; | ||
declare const CHILDREN_KEY = "children"; | ||
declare const NODE_NAME_KEY = "nodeName"; | ||
declare function updateLoroToPmState(doc: LoroDocType, mapping: LoroNodeMapping, editorState: EditorState): void; | ||
declare function createNodeFromLoroObj(schema: Schema, obj: LoroNode, mapping: LoroNodeMapping): Node; | ||
declare function createNodeFromLoroObj(schema: Schema, obj: LoroText, mapping: LoroNodeMapping): Node[]; | ||
declare const loroSyncPluginKey: PluginKey<LoroSyncPluginState>; | ||
interface LoroSyncPluginProps { | ||
@@ -25,2 +31,9 @@ doc: LoroDocType; | ||
} | ||
interface LoroSyncPluginState extends LoroSyncPluginProps { | ||
changedBy: "local" | "import" | "checkout"; | ||
mapping: LoroNodeMapping; | ||
snapshot?: Loro | null; | ||
view?: EditorView; | ||
docSubscription?: number | null; | ||
} | ||
declare const LoroSyncPlugin: (props: LoroSyncPluginProps) => Plugin; | ||
@@ -59,8 +72,14 @@ | ||
} | ||
declare const loroUndoPluginKey: PluginKey<LoroUndoPluginState>; | ||
interface LoroUndoPluginState { | ||
undoManager: UndoManager; | ||
canUndo: boolean; | ||
canRedo: boolean; | ||
} | ||
declare const LoroUndoPlugin: (props: LoroUndoPluginProps) => Plugin; | ||
declare function canUndo(state: EditorState): boolean; | ||
declare function canRedo(state: EditorState): boolean; | ||
declare function undo(state: EditorState, dispatch: (tr: Transaction) => void): boolean; | ||
declare function redo(state: EditorState, dispatch: (tr: Transaction) => void): boolean; | ||
declare const undo: Command; | ||
declare const redo: Command; | ||
export { CursorAwareness, LoroCursorPlugin, LoroDocType, LoroSyncPlugin, LoroUndoPlugin, canRedo, canUndo, redo, undo }; | ||
export { ATTRIBUTES_KEY, CHILDREN_KEY, CursorAwareness, LoroCursorPlugin, LoroDocType, LoroNodeMapping, LoroSyncPlugin, LoroSyncPluginProps, LoroSyncPluginState, LoroUndoPlugin, LoroUndoPluginProps, NODE_NAME_KEY, ROOT_DOC_KEY, canRedo, canUndo, createNodeFromLoroObj, loroSyncPluginKey, loroUndoPluginKey, redo, undo, updateLoroToPmState }; |
@@ -13,5 +13,6 @@ 'use strict'; | ||
const CHILDREN_KEY = "children"; | ||
const NODE_NAME_KEY = "nodeName"; | ||
const WEAK_NODE_TO_LORO_CONTAINER_MAPPING = /* @__PURE__ */ new WeakMap(); | ||
function updateLoroOnPmChange(doc, mapping, oldEditorState, newEditorState) { | ||
const node = newEditorState.doc; | ||
function updateLoroToPmState(doc, mapping, editorState) { | ||
const node = editorState.doc; | ||
const map = doc.getMap(ROOT_DOC_KEY); | ||
@@ -406,3 +407,3 @@ let isInit = false; | ||
case "doc-changed": | ||
updateLoroOnPmChange(state.doc, state.mapping, oldEditorState, newEditorState); | ||
updateLoroToPmState(state.doc, state.mapping, newEditorState); | ||
break; | ||
@@ -904,27 +905,27 @@ case "update-state": | ||
} | ||
function undo(state, dispatch) { | ||
const undo = (state, dispatch) => { | ||
const undoState = loroUndoPluginKey.getState(state); | ||
if (!undoState || !undoState.undoManager.canUndo()) { | ||
if (!undoState) { | ||
return false; | ||
} | ||
if (!undoState.undoManager.undo()) { | ||
const emptyTr = state.tr; | ||
dispatch(emptyTr); | ||
return false; | ||
if (dispatch) { | ||
return undoState.undoManager.undo(); | ||
} else { | ||
return undoState.undoManager.canUndo(); | ||
} | ||
return true; | ||
} | ||
function redo(state, dispatch) { | ||
}; | ||
const redo = (state, dispatch) => { | ||
const undoState = loroUndoPluginKey.getState(state); | ||
if (!undoState || !undoState.undoManager.canRedo()) { | ||
if (!undoState) { | ||
return false; | ||
} | ||
if (!undoState.undoManager.redo()) { | ||
const emptyTr = state.tr; | ||
dispatch(emptyTr); | ||
return false; | ||
if (dispatch) { | ||
return undoState.undoManager.redo(); | ||
} else { | ||
return undoState.undoManager.canRedo(); | ||
} | ||
return true; | ||
} | ||
}; | ||
exports.ATTRIBUTES_KEY = ATTRIBUTES_KEY; | ||
exports.CHILDREN_KEY = CHILDREN_KEY; | ||
exports.CursorAwareness = CursorAwareness; | ||
@@ -934,6 +935,12 @@ exports.LoroCursorPlugin = LoroCursorPlugin; | ||
exports.LoroUndoPlugin = LoroUndoPlugin; | ||
exports.NODE_NAME_KEY = NODE_NAME_KEY; | ||
exports.ROOT_DOC_KEY = ROOT_DOC_KEY; | ||
exports.canRedo = canRedo; | ||
exports.canUndo = canUndo; | ||
exports.createNodeFromLoroObj = createNodeFromLoroObj; | ||
exports.loroSyncPluginKey = loroSyncPluginKey; | ||
exports.loroUndoPluginKey = loroUndoPluginKey; | ||
exports.redo = redo; | ||
exports.undo = undo; | ||
exports.updateLoroToPmState = updateLoroToPmState; | ||
//# sourceMappingURL=index.js.map |
{ | ||
"name": "loro-prosemirror", | ||
"version": "0.0.6", | ||
"version": "0.0.7", | ||
"description": "Prosemirror Binding for Loro", | ||
"main": "dist/index.js", | ||
"module": "dist/index.mjs", | ||
"typings": "dist/loro.d.ts", | ||
"types": "dist/index.d.ts", | ||
"scripts": { | ||
"build": "rollup -c", | ||
"test": "vitest run", | ||
"lint": "tsc --noEmit", | ||
"coverage": "vitest run --coverage" | ||
@@ -12,0 +13,0 @@ }, |
@@ -26,5 +26,5 @@ # Prosemirror Binding for Loro | ||
keymap({ | ||
"Mod-z": (state) => undo(state, () => {}), | ||
"Mod-y": (state) => redo(state, () => {}), | ||
"Mod-Shift-z": (state) => redo(state, () => {}), | ||
"Mod-z": undo, | ||
"Mod-y": redo, | ||
"Mod-Shift-z": redo, | ||
}), | ||
@@ -31,0 +31,0 @@ LoroCursorPlugin(awareness, {}), |
@@ -1,7 +0,7 @@ | ||
import { Awareness, Container, ContainerID, Cursor, Loro, LoroList, LoroText, PeerID } from "loro-crdt"; | ||
import { Awareness, type Container, type ContainerID, Cursor, Loro, LoroList, LoroText, type PeerID } from "loro-crdt"; | ||
import { EditorState, Plugin, PluginKey, Selection } from "prosemirror-state"; | ||
import { Decoration, DecorationAttrs, DecorationSet } from "prosemirror-view"; | ||
import { LoroSyncPluginState, loroSyncPluginKey } from "./sync-plugin"; | ||
import { Decoration, type DecorationAttrs, DecorationSet } from "prosemirror-view"; | ||
import { type 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 { CHILDREN_KEY, type LoroDocType, type LoroNode, type LoroNodeMapping, WEAK_NODE_TO_LORO_CONTAINER_MAPPING } from "./lib"; | ||
import { CursorAwareness, cursorEq } from "./awareness"; | ||
@@ -8,0 +8,0 @@ |
export { | ||
LoroSyncPlugin, | ||
loroSyncPluginKey, | ||
LoroSyncPluginProps, | ||
LoroSyncPluginState, | ||
type LoroSyncPluginProps, | ||
type LoroSyncPluginState, | ||
} from "./sync-plugin"; | ||
@@ -15,3 +15,3 @@ export type { LoroDocType } from "./lib"; | ||
ATTRIBUTES_KEY, | ||
LoroNodeMapping, | ||
type LoroNodeMapping, | ||
} from "./lib"; | ||
@@ -23,3 +23,3 @@ export { LoroCursorPlugin } from "./cursor-plugin"; | ||
loroUndoPluginKey, | ||
LoroUndoPluginProps, | ||
type LoroUndoPluginProps, | ||
undo, | ||
@@ -26,0 +26,0 @@ redo, |
@@ -6,5 +6,5 @@ import { simpleDiff } from "lib0/diff"; | ||
import { | ||
Delta, | ||
type Delta, | ||
Loro, | ||
LoroEventBatch, | ||
type LoroEventBatch, | ||
LoroList, | ||
@@ -14,7 +14,7 @@ LoroMap, | ||
LoroTree, | ||
Value, | ||
type Value, | ||
isContainer, | ||
} from "loro-crdt"; | ||
import { EditorState } from "prosemirror-state"; | ||
import { Attrs, Mark, Node, Schema } from "prosemirror-model"; | ||
import { type Attrs, Mark, Node, Schema } from "prosemirror-model"; | ||
@@ -21,0 +21,0 @@ type LoroChildrenListType = LoroList<LoroMap<LoroNodeContainerType> | LoroText>; |
@@ -1,6 +0,6 @@ | ||
import { Loro, LoroEventBatch } from "loro-crdt"; | ||
import { Loro, type LoroEventBatch } from "loro-crdt"; | ||
import { | ||
Plugin, | ||
PluginKey, | ||
StateField, | ||
type StateField, | ||
EditorState, | ||
@@ -11,4 +11,4 @@ } from "prosemirror-state"; | ||
import { | ||
LoroDocType, | ||
LoroNodeMapping, | ||
type LoroDocType, | ||
type LoroNodeMapping, | ||
clearChangedNodes, | ||
@@ -18,2 +18,3 @@ createNodeFromLoroObj, | ||
} from "./lib"; | ||
import { configLoroTextStyle } from "./text-style"; | ||
@@ -57,7 +58,11 @@ export const loroSyncPluginKey = new PluginKey<LoroSyncPluginState>("loro-sync"); | ||
state: { | ||
init: (config, editorState): LoroSyncPluginState => ({ | ||
doc: props.doc, | ||
mapping: props.mapping ?? new Map(), | ||
changedBy: "local" | ||
}), | ||
init: (config, editorState): LoroSyncPluginState => { | ||
configLoroTextStyle(props.doc, editorState.schema); | ||
return { | ||
doc: props.doc, | ||
mapping: props.mapping ?? new Map(), | ||
changedBy: "local" | ||
} | ||
}, | ||
apply: (tr, state, oldEditorState, newEditorState) => { | ||
@@ -74,3 +79,3 @@ const meta = tr.getMeta( | ||
case "doc-changed": | ||
updateLoroToPmState(state.doc as LoroDocType, state.mapping, oldEditorState, newEditorState); | ||
updateLoroToPmState(state.doc as LoroDocType, state.mapping, newEditorState); | ||
break; | ||
@@ -77,0 +82,0 @@ case "update-state": |
import type { Cursor } from "loro-crdt"; | ||
import { Loro, UndoManager } from "loro-crdt"; | ||
import { | ||
type Command, | ||
EditorState, | ||
Plugin, | ||
PluginKey, | ||
StateField, | ||
type StateField, | ||
TextSelection, | ||
Transaction, | ||
} from "prosemirror-state"; | ||
@@ -17,2 +17,3 @@ import { EditorView } from "prosemirror-view"; | ||
import { loroSyncPluginKey } from "./sync-plugin"; | ||
import { configLoroTextStyle } from "./text-style"; | ||
@@ -45,2 +46,4 @@ export interface LoroUndoPluginProps { | ||
init: (config, editorState): LoroUndoPluginState => { | ||
configLoroTextStyle(props.doc, editorState.schema); | ||
undoManager.addExcludeOriginPrefix("sys:init"); | ||
@@ -182,36 +185,24 @@ return { | ||
export function undo( | ||
state: EditorState, | ||
dispatch: (tr: Transaction) => void, | ||
): boolean { | ||
export const undo: Command = (state, dispatch): boolean => { | ||
const undoState = loroUndoPluginKey.getState(state); | ||
if (!undoState || !undoState.undoManager.canUndo()) { | ||
if (!undoState) { | ||
return false; | ||
} | ||
if (!undoState.undoManager.undo()) { | ||
const emptyTr = state.tr; | ||
dispatch(emptyTr); | ||
return false; | ||
if (dispatch) { | ||
return undoState.undoManager.undo(); | ||
} else { | ||
return undoState.undoManager.canUndo(); | ||
} | ||
}; | ||
return true; | ||
} | ||
export function redo( | ||
state: EditorState, | ||
dispatch: (tr: Transaction) => void, | ||
): boolean { | ||
export const redo: Command = (state, dispatch): boolean => { | ||
const undoState = loroUndoPluginKey.getState(state); | ||
if (!undoState || !undoState.undoManager.canRedo()) { | ||
if (!undoState) { | ||
return false; | ||
} | ||
if (!undoState.undoManager.redo()) { | ||
const emptyTr = state.tr; | ||
dispatch(emptyTr); | ||
return false; | ||
if (dispatch) { | ||
return undoState.undoManager.redo(); | ||
} else { | ||
return undoState.undoManager.canRedo(); | ||
} | ||
return true; | ||
} | ||
}; |
import { describe, assert, expect, test } from "vitest"; | ||
import { Node, Schema, NodeSpec, MarkSpec } from "prosemirror-model"; | ||
import { Node, Schema, type NodeSpec, type MarkSpec } from "prosemirror-model"; | ||
import { EditorState } from "prosemirror-state"; | ||
@@ -8,4 +8,4 @@ import { Loro, LoroText } from "loro-crdt"; | ||
import { | ||
LoroDocType, | ||
LoroNodeMapping, | ||
type LoroDocType, | ||
type LoroNodeMapping, | ||
ROOT_DOC_KEY, | ||
@@ -202,3 +202,3 @@ clearChangedNodes, | ||
const mapping: LoroNodeMapping = new Map(); | ||
updateLoroToPmState(loroDoc, mapping, editorState, editorState); | ||
updateLoroToPmState(loroDoc, mapping, editorState); | ||
expect(loroDoc.toJSON()).toEqual(exampleLoroContent); | ||
@@ -217,3 +217,3 @@ }); | ||
updateLoroToPmState(loroDoc, mapping, editorState, editorState); | ||
updateLoroToPmState(loroDoc, mapping, editorState); | ||
expect(loroDoc.toJSON()).toEqual({ | ||
@@ -234,3 +234,3 @@ [ROOT_DOC_KEY]: { | ||
updateLoroToPmState(loroDoc, mapping, editorState, editorState); | ||
updateLoroToPmState(loroDoc, mapping, editorState); | ||
expect(loroDoc.toJSON()).toEqual({ | ||
@@ -257,3 +257,3 @@ [ROOT_DOC_KEY]: { | ||
updateLoroToPmState(loroDoc, mapping, editorState, editorState); | ||
updateLoroToPmState(loroDoc, mapping, editorState); | ||
expect(loroDoc.toJSON()).toEqual({ | ||
@@ -295,3 +295,3 @@ [ROOT_DOC_KEY]: { | ||
updateLoroToPmState(loroDoc, mapping, editorState, editorState); | ||
updateLoroToPmState(loroDoc, mapping, editorState); | ||
expect(loroDoc.toJSON()).toEqual({ | ||
@@ -352,3 +352,3 @@ [ROOT_DOC_KEY]: { | ||
updateLoroToPmState(loroDoc, mapping, editorState, editorState); | ||
updateLoroToPmState(loroDoc, mapping, editorState); | ||
expect(loroDoc.toJSON()).toEqual({ | ||
@@ -405,3 +405,3 @@ [ROOT_DOC_KEY]: { | ||
const mapping: LoroNodeMapping = new Map(); | ||
updateLoroToPmState(loroDoc, mapping, _editorState, _editorState); | ||
updateLoroToPmState(loroDoc, mapping, _editorState); | ||
@@ -408,0 +408,0 @@ const node = createNodeFromLoroObj( |
@@ -1,2 +0,2 @@ | ||
import { Schema, NodeSpec, MarkSpec } from "prosemirror-model"; | ||
import { Schema, type NodeSpec, type MarkSpec } from "prosemirror-model"; | ||
@@ -3,0 +3,0 @@ const nodes: { [key: string]: NodeSpec } = { |
import { Schema } from "prosemirror-model"; | ||
import { EditorState } from "prosemirror-state"; | ||
import { | ||
LoroNode, | ||
LoroNodeMapping, | ||
type LoroNode, | ||
type LoroNodeMapping, | ||
getLoroMapAttributes, | ||
@@ -7,0 +7,0 @@ getLoroMapChildren, |
@@ -25,5 +25,5 @@ { | ||
/* Modules */ | ||
"module": "commonjs" /* Specify what module code is generated. */, | ||
"module": "esnext" /* Specify what module code is generated. */, | ||
"rootDir": "./", /* Specify the root folder within your source files. */ | ||
// "moduleResolution": "node10", /* Specify how TypeScript looks up a file from a given module specifier. */ | ||
"moduleResolution": "Bundler", /* Specify how TypeScript looks up a file from a given module specifier. */ | ||
// "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */ | ||
@@ -73,3 +73,3 @@ // "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */ | ||
// "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */ | ||
// "verbatimModuleSyntax": true, /* Do not transform or elide any imports or exports not marked as type-only, ensuring they are written in the output file's format based on the 'module' setting. */ | ||
"verbatimModuleSyntax": true, /* Do not transform or elide any imports or exports not marked as type-only, ensuring they are written in the output file's format based on the 'module' setting. */ | ||
// "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */ | ||
@@ -76,0 +76,0 @@ "esModuleInterop": true /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */, |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
295590
27
3986