// 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; } }; }