85 lines
3.1 KiB
JavaScript
85 lines
3.1 KiB
JavaScript
// 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;
|
|
}
|
|
};
|
|
}
|