@automerge/automerge-codemirror
Advanced tools
Comparing version 0.0.10 to 0.0.11
import { Patch, Prop } from "@automerge/automerge"; | ||
import { EditorSelection } from "@codemirror/state"; | ||
import { EditorView } from "@codemirror/view"; | ||
export default function (view: EditorView, selection: EditorSelection, target: Prop[], patches: Patch[]): void; | ||
export declare const applyAmPatchesToCm: (view: EditorView, target: Prop[], patches: Patch[]) => void; |
@@ -1,4 +0,5 @@ | ||
import { ChangeSet, } from "@codemirror/state"; | ||
import { ChangeSet } from "@codemirror/state"; | ||
import { reconcileAnnotationType } from "./plugin"; | ||
export default function (view, selection, target, patches) { | ||
export const applyAmPatchesToCm = (view, target, patches) => { | ||
let selection = view.state.selection; | ||
for (const patch of patches) { | ||
@@ -19,3 +20,3 @@ const changeSpec = handlePatch(patch, target, view.state); | ||
}); | ||
} | ||
}; | ||
function handlePatch(patch, target, state) { | ||
@@ -22,0 +23,0 @@ if (patch.action === "insert") { |
@@ -1,7 +0,5 @@ | ||
import { next as am } from "@automerge/automerge"; | ||
import { next as A } from "@automerge/automerge"; | ||
import { DocHandle } from "@automerge/automerge-repo"; | ||
import { Heads } from "@automerge/automerge"; | ||
import { EditorState, Transaction } from "@codemirror/state"; | ||
import { type Field } from "./plugin"; | ||
type Update = (atHeads: Heads, change: (doc: am.Doc<unknown>) => void) => Heads | undefined; | ||
export default function (field: Field, update: Update, transactions: Transaction[], state: EditorState): Heads | undefined; | ||
export {}; | ||
import { Transaction } from "@codemirror/state"; | ||
export declare const applyCmTransactionsToAmHandle: (handle: DocHandle<unknown>, path: A.Prop[], transactions: Transaction[]) => A.Heads | undefined; |
@@ -1,26 +0,19 @@ | ||
import { next as am } from "@automerge/automerge"; | ||
export default function (field, update, transactions, state) { | ||
const { lastHeads, path } = state.field(field); | ||
// We don't want to call `automerge.updateAt` if there are no changes. | ||
// Otherwise later on `automerge.diff` will return empty patches that result in a no-op but still mess up the selection. | ||
let hasChanges = false; | ||
for (const tr of transactions) { | ||
if (!tr.changes.empty) { | ||
tr.changes.iterChanges(() => { | ||
hasChanges = true; | ||
}); | ||
} | ||
import { next as A } from "@automerge/automerge"; | ||
import { isReconcileTx } from "./plugin"; | ||
export const applyCmTransactionsToAmHandle = (handle, path, transactions) => { | ||
const transactionsWithChanges = transactions.filter(tr => !isReconcileTx(tr) && !tr.changes.empty); | ||
if (transactionsWithChanges.length === 0) { | ||
return; | ||
} | ||
if (!hasChanges) { | ||
return undefined; | ||
} | ||
const newHeads = update(lastHeads, (doc) => { | ||
for (const tr of transactions) { | ||
tr.changes.iterChanges((fromA, toA, _fromB, _toB, inserted) => { | ||
am.splice(doc, path, fromA, toA - fromA, inserted.toString()); | ||
handle.change((doc) => { | ||
transactionsWithChanges.forEach(tr => { | ||
tr.changes.iterChanges((fromA, toA, fromB, _toB, inserted) => { | ||
// We are cloning the path as `am.splice` calls `.unshift` on it, modifying it in place, | ||
// causing the path to be broken on subsequent changes | ||
A.splice(doc, path.slice(), fromB, toA - fromA, inserted.toString()); | ||
}); | ||
} | ||
}); | ||
}); | ||
return newHeads; | ||
} | ||
return A.getHeads(handle.docSync()); | ||
}; | ||
//# sourceMappingURL=codeMirrorToAm.js.map |
@@ -1,2 +0,1 @@ | ||
export { plugin } from "./plugin"; | ||
export { PatchSemaphore } from "./PatchSemaphore"; | ||
export { automergeSyncPlugin } from "./plugin"; |
@@ -1,3 +0,2 @@ | ||
export { plugin } from "./plugin"; | ||
export { PatchSemaphore } from "./PatchSemaphore"; | ||
export { automergeSyncPlugin } from "./plugin"; | ||
//# sourceMappingURL=index.js.map |
@@ -1,20 +0,19 @@ | ||
import { EditorState, StateEffect, StateField, Transaction, TransactionSpec } from "@codemirror/state"; | ||
import { Doc, Heads, Prop } from "@automerge/automerge"; | ||
export type Value = { | ||
lastHeads: Heads; | ||
path: Prop[]; | ||
unreconciledTransactions: Transaction[]; | ||
import { next as A } from "@automerge/automerge"; | ||
import { EditorView, ViewPlugin, ViewUpdate } from "@codemirror/view"; | ||
import { Transaction } from "@codemirror/state"; | ||
import { DocHandle } from "@automerge/automerge-repo"; | ||
export declare const reconcileAnnotationType: import("@codemirror/state").AnnotationType<unknown>; | ||
export declare const isReconcileTx: (tr: Transaction) => boolean; | ||
type AutomergeSyncPluginConfig = { | ||
handle: DocHandle<any>; | ||
path: A.Prop[]; | ||
}; | ||
type UpdateHeads = { | ||
newHeads: Heads; | ||
}; | ||
export declare const effectType: import("@codemirror/state").StateEffectType<UpdateHeads>; | ||
export declare function updateHeads(newHeads: Heads): StateEffect<UpdateHeads>; | ||
export declare function getLastHeads(state: EditorState, field: Field): Heads; | ||
export declare function getPath(state: EditorState, field: Field): Prop[]; | ||
export type Field = StateField<Value>; | ||
export declare function plugin<T>(doc: Doc<T>, path: Prop[]): StateField<Value>; | ||
export declare const reconcileAnnotationType: import("@codemirror/state").AnnotationType<unknown>; | ||
export declare function isReconcileTx(tr: Transaction): boolean; | ||
export declare function makeReconcile(tr: TransactionSpec): void; | ||
export declare const automergeSyncPlugin: ({ handle, path, }: AutomergeSyncPluginConfig) => ViewPlugin<{ | ||
view: EditorView; | ||
reconciledHeads: A.Heads; | ||
isProcessingCmTransaction: boolean; | ||
update(update: ViewUpdate): void; | ||
onChange: () => void; | ||
destroy(): void; | ||
}>; | ||
export {}; |
@@ -1,68 +0,52 @@ | ||
import { Annotation, StateEffect, StateField, } from "@codemirror/state"; | ||
import * as automerge from "@automerge/automerge"; | ||
export const effectType = StateEffect.define({}); | ||
export function updateHeads(newHeads) { | ||
return effectType.of({ newHeads }); | ||
} | ||
export function getLastHeads(state, field) { | ||
return state.field(field).lastHeads; | ||
} | ||
export function getPath(state, field) { | ||
return state.field(field).path; | ||
} | ||
export function plugin(doc, path) { | ||
return StateField.define({ | ||
create() { | ||
return { | ||
lastHeads: automerge.getHeads(doc), | ||
unreconciledTransactions: [], | ||
path: path.slice(), | ||
}; | ||
}, | ||
update(value, tr) { | ||
const result = { | ||
lastHeads: value.lastHeads, | ||
unreconciledTransactions: value.unreconciledTransactions.slice(), | ||
path: path.slice(), | ||
}; | ||
let clearUnreconciled = false; | ||
for (const effect of tr.effects) { | ||
if (effect.is(effectType)) { | ||
result.lastHeads = effect.value.newHeads; | ||
clearUnreconciled = true; | ||
} | ||
import { next as A } from "@automerge/automerge"; | ||
import { ViewPlugin } from "@codemirror/view"; | ||
import { Annotation } from "@codemirror/state"; | ||
import { applyCmTransactionsToAmHandle } from "./codeMirrorToAm"; | ||
import { applyAmPatchesToCm } from "./amToCodemirror"; | ||
export const reconcileAnnotationType = Annotation.define(); | ||
export const isReconcileTx = (tr) => !!tr.annotation(reconcileAnnotationType); | ||
export const automergeSyncPlugin = ({ handle, path, }) => { | ||
if (!handle.isReady) { | ||
throw new Error("ensure the handle is ready before initializing the automergeSyncPlugin"); | ||
} | ||
return ViewPlugin.fromClass(class { | ||
view; | ||
reconciledHeads = A.getHeads(handle.docSync()); | ||
isProcessingCmTransaction = false; | ||
constructor(view) { | ||
this.view = view; | ||
this.onChange = this.onChange.bind(this); | ||
handle.on("change", this.onChange); | ||
} | ||
update(update) { | ||
// start processing codemirror transaction | ||
// changes that are created through the transaction are ignored in the change listener on the handle | ||
this.isProcessingCmTransaction = true; | ||
const newHeads = applyCmTransactionsToAmHandle(handle, path, update.transactions); | ||
if (newHeads) { | ||
this.reconciledHeads = newHeads; | ||
} | ||
if (clearUnreconciled) { | ||
result.unreconciledTransactions = []; | ||
// finish processing transaction | ||
this.isProcessingCmTransaction = false; | ||
} | ||
onChange = () => { | ||
// ignore changes that where triggered while processing a codemirror transaction | ||
if (this.isProcessingCmTransaction) { | ||
return; | ||
} | ||
else { | ||
if (!isReconcileTx(tr)) { | ||
result.unreconciledTransactions.push(tr); | ||
} | ||
const currentHeads = A.getHeads(handle.docSync()); | ||
if (A.equals(currentHeads, this.reconciledHeads)) { | ||
return; | ||
} | ||
return result; | ||
}, | ||
// get the diff between the reconciled heads and the new heads | ||
// and apply that to the codemirror doc | ||
const patches = A.diff(handle.docSync(), this.reconciledHeads, currentHeads); | ||
applyAmPatchesToCm(this.view, path, patches); | ||
this.reconciledHeads = currentHeads; | ||
}; | ||
destroy() { | ||
handle.off("change", this.onChange); | ||
} | ||
}); | ||
} | ||
export const reconcileAnnotationType = Annotation.define(); | ||
export function isReconcileTx(tr) { | ||
return !!tr.annotation(reconcileAnnotationType); | ||
} | ||
export function makeReconcile(tr) { | ||
if (tr.annotations != null) { | ||
if (tr.annotations instanceof Array) { | ||
tr.annotations = [...tr.annotations, reconcileAnnotationType.of({})]; | ||
} | ||
else { | ||
tr.annotations = [tr.annotations, reconcileAnnotationType.of({})]; | ||
} | ||
} | ||
else { | ||
tr.annotations = [reconcileAnnotationType.of({})]; | ||
} | ||
//return { | ||
//...tr, | ||
//annotations: reconcileAnnotationType.of({}) | ||
//} | ||
} | ||
}; | ||
//# sourceMappingURL=plugin.js.map |
{ | ||
"name": "@automerge/automerge-codemirror", | ||
"version": "0.0.10", | ||
"version": "0.0.11", | ||
"main": "dist/index.js", | ||
@@ -8,2 +8,3 @@ "license": "MIT", | ||
"build": "yarn tsc -p tsconfig.build.json", | ||
"watch": "yarn tsc-watch -p tsconfig.build.json", | ||
"lint": "eslint .", | ||
@@ -18,3 +19,3 @@ "prettier": "prettier '**/*.{ts,tsx,}' --check", | ||
"dependencies": { | ||
"@automerge/automerge": "^2.1.7", | ||
"@automerge/automerge": "^2.1.9", | ||
"@codemirror/state": "^6.3.0", | ||
@@ -27,2 +28,3 @@ "@codemirror/view": "^6.21.3", | ||
"@cypress/react18": "^2.0.0", | ||
"@types/react": "^18.2.79", | ||
"@typescript-eslint/eslint-plugin": "^5.60.0", | ||
@@ -37,2 +39,3 @@ "@typescript-eslint/parser": "^5.60.0", | ||
"react-dom": "^18.2.0", | ||
"tsc-watch": "^6.2.0", | ||
"typescript": "^5.1.3", | ||
@@ -39,0 +42,0 @@ "vite": "^4.3.9", |
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
No README
QualityPackage does not have a README. This may indicate a failed publish or a low quality package.
Found 1 instance in 1 package
1
33
10306
17
183
1
Updated@automerge/automerge@^2.1.9