Isolate RNG drafts and fix image editor lifecycle
Some checks failed
Deploy Sokko G / deploy (push) Failing after 2s

This commit is contained in:
Shinuwa 2026-09-11 20:28:07 +02:00
parent 7c0b72f914
commit b470a34b2a
7 changed files with 297 additions and 50 deletions

View file

@ -0,0 +1,85 @@
// Rôle : monte les éditeurs réels sous StrictMode et contrôle les décodages concurrents.
/* global URL */
import { createElement, StrictMode, useLayoutEffect, useState } from "react";
import { createRoot } from "react-dom/client";
import { flushSync } from "react-dom";
import { ImageViewer } from "../../website/src/components/ImageViewer.jsx";
import { ToolboxCoverEditor } from "../../website/src/features/toolboxes/ToolboxCoverEditor.jsx";
import { RngSimulatorModule } from "../../website/src/features/toolboxes/modules/RngSimulatorModule.jsx";
import { normalizeRngSimulatorData } from "../../website/src/features/toolboxes/storage/toolboxStorage.js";
export function mountEditorProbe(element, kind, initialProps) {
const root = createRoot(element);
const snapshots = [];
const saves = [];
let updateProps;
const components = { viewer: ImageViewer, cover: ToolboxCoverEditor, rng: RngSimulatorModule };
function Probe() {
const [props, setProps] = useState(initialProps);
updateProps = setProps;
useLayoutEffect(() => {
snapshots.push(Array.from(element.querySelectorAll("input"), (input) => input.value));
});
const context = {
getModuleData: () => props.data,
normalizeRngSimulatorData,
setModuleData: (_toolbox, _module, data) => {
saves.push(data);
setProps((current) => ({ ...current, data }));
},
uid: () => "new-rate"
};
return createElement(components[kind], {
toolboxId: "probe", moduleId: "rng", context,
onClose: () => {}, onSave: (value) => saves.push(value),
setEditing: (editing) => setProps((current) => ({ ...current, editing })),
...props
});
}
flushSync(() => root.render(createElement(StrictMode, null, createElement(Probe))));
return {
snapshots, saves,
update(patch) {
snapshots.length = 0;
flushSync(() => updateProps((props) => ({ ...props, ...patch })));
},
unmount: () => flushSync(() => root.unmount())
};
}
export function controlImageDecoding() {
const originalDecode = globalThis.createImageBitmap;
const originalCreate = URL.createObjectURL;
const originalRevoke = URL.revokeObjectURL;
const pending = [];
const created = [];
const revoked = [];
const closed = [];
globalThis.createImageBitmap = (file) => new Promise((resolve, reject) => {
pending.push({ file, resolve, reject });
});
URL.createObjectURL = (file) => {
const url = originalCreate(file);
created.push(url);
return url;
};
URL.revokeObjectURL = (url) => {
revoked.push(url);
originalRevoke(url);
};
return {
pending, created, revoked, closed,
async resolve(index) {
const bitmap = await originalDecode(pending[index].file);
const close = bitmap.close.bind(bitmap);
bitmap.close = () => { closed.push(index); close(); };
pending[index].resolve(bitmap);
},
reject: (index) => pending[index].reject(new Error("decode failed")),
restore() {
globalThis.createImageBitmap = originalDecode;
URL.createObjectURL = originalCreate;
URL.revokeObjectURL = originalRevoke;
}
};
}