feat(writekit): rename @robonen/editor to @robonen/writekit

Rename the rich-text editor package and all Editor* exports to Writekit*;
remove the old vue/editor tree.
This commit is contained in:
2026-06-15 16:54:06 +07:00
parent 55e78786d6
commit 263c32002f
149 changed files with 1563 additions and 1748 deletions
+57
View File
@@ -0,0 +1,57 @@
/**
* Attribute values are JSON-serializable so documents round-trip losslessly and
* a CRDT adapter can map them onto its own primitives without special-casing.
*/
export type AttrValue
= | string
| number
| boolean
| null
| readonly AttrValue[]
| { readonly [key: string]: AttrValue };
export type Attrs = Readonly<Record<string, AttrValue>>;
/**
* Structural equality for two attribute values. Order-insensitive for object
* keys, deep for arrays/objects. Used by mark/attr deduplication and tests.
*/
export function attrValueEq(a: AttrValue | undefined, b: AttrValue | undefined): boolean {
if (a === b)
return true;
if (a === null || b === null || a === undefined || b === undefined)
return a === b;
const aArr = Array.isArray(a);
const bArr = Array.isArray(b);
if (aArr || bArr) {
if (!aArr || !bArr || a.length !== b.length)
return false;
return a.every((v, i) => attrValueEq(v, b[i]));
}
if (typeof a === 'object' && typeof b === 'object')
return attrsEq(a as Attrs, b as Attrs);
return false;
}
/**
* Structural equality for attribute bags. `undefined` and `{}` are equivalent
* so `{ type: 'bold' }` equals `{ type: 'bold', attrs: {} }`.
*/
export function attrsEq(a?: Attrs, b?: Attrs): boolean {
if (a === b)
return true;
const aKeys = a ? Object.keys(a) : [];
const bKeys = b ? Object.keys(b) : [];
if (aKeys.length !== bKeys.length)
return false;
return aKeys.every(key => attrValueEq(a![key], b?.[key]));
}