Clean partial editor mounts and failed refreshes
This commit is contained in:
1 parent
3da88510df
commit
d41eda7050
3 files changed
+39
-10
No files matched your search
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@wrnexus/block-editor",
|
"name": "@wrnexus/block-editor",
|
||||||
"version": "0.1.6",
|
"version": "0.1.7",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"description": "Hydrated accessible editor runtime for WRNexus block documents.",
|
"description": "Hydrated accessible editor runtime for WRNexus block documents.",
|
||||||
"exports": {
|
"exports": {
|
||||||
|
|||||||
@@ -31,8 +31,20 @@ export function mountBlockEditor(root: HTMLElement, options: MountEditorOptions)
|
|||||||
live.style.cssText =
|
live.style.cssText =
|
||||||
"position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0";
|
"position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0";
|
||||||
root.append(live);
|
root.append(live);
|
||||||
|
const destroy = () => {
|
||||||
|
if (destroyed) return;
|
||||||
|
destroyed = true;
|
||||||
|
generation++;
|
||||||
|
try {
|
||||||
|
cleanups.forEach((cleanup) => cleanup());
|
||||||
|
} finally {
|
||||||
|
cleanups = [];
|
||||||
|
try { manager?.destroy(); } finally { live.remove(); }
|
||||||
|
}
|
||||||
|
};
|
||||||
const refresh = () => {
|
const refresh = () => {
|
||||||
if (destroyed) return;
|
if (destroyed) return;
|
||||||
|
try {
|
||||||
const currentGeneration = ++generation;
|
const currentGeneration = ++generation;
|
||||||
cleanups.forEach((cleanup) => cleanup());
|
cleanups.forEach((cleanup) => cleanup());
|
||||||
cleanups = [];
|
cleanups = [];
|
||||||
@@ -145,18 +157,13 @@ export function mountBlockEditor(root: HTMLElement, options: MountEditorOptions)
|
|||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
} catch (error) {
|
||||||
|
try { destroy(); } finally { throw error; }
|
||||||
|
}
|
||||||
};
|
};
|
||||||
refresh();
|
refresh();
|
||||||
return {
|
return {
|
||||||
refresh,
|
refresh,
|
||||||
destroy() {
|
destroy,
|
||||||
if (destroyed) return;
|
|
||||||
destroyed = true;
|
|
||||||
generation++;
|
|
||||||
cleanups.forEach((cleanup) => cleanup());
|
|
||||||
cleanups = [];
|
|
||||||
manager?.destroy();
|
|
||||||
live.remove();
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -9,6 +9,28 @@ const code = new Bun.Transpiler({ loader: "ts" })
|
|||||||
.replace(/^import .*;\s*$/gm, "")
|
.replace(/^import .*;\s*$/gm, "")
|
||||||
.replace("export function mountBlockEditor", "function mountBlockEditor");
|
.replace("export function mountBlockEditor", "function mountBlockEditor");
|
||||||
|
|
||||||
|
test("partial registration failure cleans the backend and live region on mount and refresh", () => {
|
||||||
|
for (const failingMount of [1, 2]) {
|
||||||
|
const window = new Window(), root = window.document.createElement("div");
|
||||||
|
window.document.body.append(root);
|
||||||
|
root.innerHTML = '<div data-block-id="a" data-block-parent="root" data-block-slot="content"></div><div data-block-id="b" data-block-parent="root" data-block-slot="content"></div>';
|
||||||
|
let mounts = 0, destroyed = 0, cleaned = 0;
|
||||||
|
const mount = new Function("createDndManager", code + ";return mountBlockEditor;")(() => {
|
||||||
|
const number = ++mounts; let registrations = 0;
|
||||||
|
return { registerSortable() { if (++registrations === 2 && number === failingMount) throw new Error("registration failed"); return () => { cleaned++; }; }, destroy() { destroyed++; } };
|
||||||
|
});
|
||||||
|
let editor: MountedEditor | undefined;
|
||||||
|
if (failingMount === 1) expect(() => mount(root, { onMove() {} })).toThrow("registration failed");
|
||||||
|
else { editor = mount(root, { onMove() {} }); expect(() => editor!.refresh()).toThrow("registration failed"); }
|
||||||
|
expect(root.querySelector('[role="status"]')).toBeNull();
|
||||||
|
expect(root.querySelectorAll('[data-block-id]')).toHaveLength(2);
|
||||||
|
expect(destroyed).toBe(failingMount);
|
||||||
|
expect(cleaned).toBe(failingMount === 1 ? 1 : 3);
|
||||||
|
editor?.destroy(); editor?.refresh();
|
||||||
|
expect(destroyed).toBe(failingMount);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
function fixture(onMove: MountEditorOptions["onMove"] = () => false) {
|
function fixture(onMove: MountEditorOptions["onMove"] = () => false) {
|
||||||
const window = new Window();
|
const window = new Window();
|
||||||
const document = window.document;
|
const document = window.document;
|
||||||
|
|||||||
Reference in new issue
Block a user