Avoid repeated canvas scans during drag registration
Quality / quality (ubuntu-latest) (push) Failing after 1s
Quality / quality (windows-latest) (push) Canceled after 0s

This commit is contained in:
Clintchiz committed 2026-09-05 18:14:51 +05:30
1 parent d41eda7050
commit c023a98052
3 files changed
+49 -20

No files matched your search

+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "@wrnexus/block-editor", "name": "@wrnexus/block-editor",
"version": "0.1.7", "version": "0.1.8",
"type": "module", "type": "module",
"description": "Hydrated accessible editor runtime for WRNexus block documents.", "description": "Hydrated accessible editor runtime for WRNexus block documents.",
"exports": { "exports": {
+16 -19
View File
@@ -119,38 +119,35 @@ export function mountBlockEditor(root: HTMLElement, options: MountEditorOptions)
}); });
}, },
}); });
const elements = [...root.querySelectorAll<HTMLElement>(
"[data-block-id][data-block-parent][data-block-slot]",
)];
const groupSizes = new Map<string, number>();
const registrations = elements.map(element => {
const parentId = element.dataset.blockParent!;
const slot = element.dataset.blockSlot!;
const group = JSON.stringify([parentId, slot]);
const index = groupSizes.get(group) ?? 0;
groupSizes.set(group, index + 1);
groups.set(group, { parentId, slot });
return { element, group, index };
});
for (const element of root.querySelectorAll<HTMLElement>("[data-block-slot-target][data-block-parent]")) { for (const element of root.querySelectorAll<HTMLElement>("[data-block-slot-target][data-block-parent]")) {
const parentId = element.dataset.blockParent!; const parentId = element.dataset.blockParent!;
const slot = element.dataset.blockSlotTarget!; const slot = element.dataset.blockSlotTarget!;
const hasChildren = [...root.querySelectorAll<HTMLElement>("[data-block-id][data-block-parent][data-block-slot]")]
.some(child => child.dataset.blockParent === parentId && child.dataset.blockSlot === slot);
if (hasChildren) continue;
const group = JSON.stringify([parentId, slot]); const group = JSON.stringify([parentId, slot]);
if (groupSizes.has(group)) continue;
groups.set(group, { parentId, slot }); groups.set(group, { parentId, slot });
cleanups.push(manager.registerDropZone({ id: `wrn-slot:${group}`, group, index: 0, element })); cleanups.push(manager.registerDropZone({ id: `wrn-slot:${group}`, group, index: 0, element }));
} }
for (const element of root.querySelectorAll<HTMLElement>( for (const { element, group, index } of registrations) {
"[data-block-id][data-block-parent][data-block-slot]",
)) {
const id = element.dataset.blockId!; const id = element.dataset.blockId!;
const parent = element.dataset.blockParent!;
const slot = element.dataset.blockSlot!;
const group = JSON.stringify([parent, slot]);
groups.set(group, { parentId: parent, slot });
const siblings = [
...root.querySelectorAll<HTMLElement>(
"[data-block-id][data-block-parent][data-block-slot]",
),
].filter(
(candidate) =>
candidate.dataset.blockParent === parent && candidate.dataset.blockSlot === slot,
);
const handle = element.querySelector<HTMLElement>("[data-block-handle]") ?? undefined; const handle = element.querySelector<HTMLElement>("[data-block-handle]") ?? undefined;
cleanups.push( cleanups.push(
manager.registerSortable({ manager.registerSortable({
id, id,
group, group,
index: siblings.indexOf(element), index,
element, element,
handle, handle,
type: element.dataset.blockType, type: element.dataset.blockType,
@@ -74,6 +74,38 @@ function fixture(onMove: MountEditorOptions["onMove"] = () => false) {
}; };
} }
test("large canvas registration scans blocks once and preserves interleaved slot order", () => {
const f = fixture();
f.root.replaceChildren();
for (let i = 0; i < 300; i++) {
const node = f.document.createElement("div");
node.dataset.blockId = String(i);
node.dataset.blockParent = `parent:${i % 3}`;
node.dataset.blockSlot = "content";
f.root.append(node);
}
for (let i = 0; i < 4; i++) {
const slot = f.document.createElement("div");
slot.dataset.blockParent = `parent:${i}`;
slot.dataset.blockSlotTarget = "content";
f.root.append(slot);
}
const query = f.root.querySelectorAll.bind(f.root);
let scans = 0;
f.root.querySelectorAll = ((selector: string) => {
if (selector === "[data-block-id][data-block-parent][data-block-slot]") scans++;
return query(selector);
}) as typeof f.root.querySelectorAll;
f.editor.refresh();
const backend = f.backends.at(-1)!;
expect(scans).toBe(1);
expect(backend.registrations.map(({ id, group, index }) => ({ id, group, index }))).toEqual(
Array.from({ length: 300 }, (_, i) => ({ id: String(i), group: JSON.stringify([`parent:${i % 3}`, "content"]), index: Math.floor(i / 3) })),
);
expect(backend.zones.map(zone => zone.group)).toEqual([JSON.stringify(["parent:3", "content"])]);
f.editor.destroy();
});
test("cancelled optimistic moves restore original DOM nodes across containers", async () => { test("cancelled optimistic moves restore original DOM nodes across containers", async () => {
const f = fixture(); const f = fixture();
const a = f.root.querySelector('[data-block-id="a"]')!; const a = f.root.querySelector('[data-block-id="a"]')!;