fix(web): lecteur CBZ/CBR mode vertical — capturer naturalWidth/naturalHeight avant neutralisation de currentTarget par React (régression #37)
This commit is contained in:
@ -217,9 +217,10 @@ export function CbzReader({
|
||||
loading="lazy"
|
||||
style={verticalImageStyle(item.page)}
|
||||
onLoad={(event) => {
|
||||
const { naturalWidth, naturalHeight } = event.currentTarget;
|
||||
setImageSizes((current) => ({
|
||||
...current,
|
||||
[item.page]: { width: event.currentTarget.naturalWidth, height: event.currentTarget.naturalHeight }
|
||||
[item.page]: { width: naturalWidth, height: naturalHeight }
|
||||
}));
|
||||
}}
|
||||
onError={() => setPageError(`Page ${item.page} indisponible.`)}
|
||||
|
||||
94
apps/web/src/reader/CbzReaderNaturalWidth.test.tsx
Normal file
94
apps/web/src/reader/CbzReaderNaturalWidth.test.tsx
Normal file
@ -0,0 +1,94 @@
|
||||
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||
|
||||
const hookState = vi.hoisted(() => ({
|
||||
stateIndex: 0,
|
||||
states: [] as unknown[],
|
||||
updates: [] as unknown[][]
|
||||
}));
|
||||
|
||||
vi.mock("react", async () => {
|
||||
const actual = await vi.importActual<typeof import("react")>("react");
|
||||
return {
|
||||
...actual,
|
||||
useCallback: (callback: unknown) => callback,
|
||||
useEffect: () => undefined,
|
||||
useRef: (current: unknown) => ({ current }),
|
||||
useState: (initial: unknown) => {
|
||||
const index = hookState.stateIndex;
|
||||
hookState.stateIndex += 1;
|
||||
hookState.updates[index] = [];
|
||||
return [
|
||||
hookState.states[index] ?? initial,
|
||||
(next: unknown) => {
|
||||
hookState.updates[index].push(next);
|
||||
}
|
||||
];
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
vi.mock("../api/client", () => ({
|
||||
api: {
|
||||
cbzPages: vi.fn().mockResolvedValue({ bookId: 2, pageCount: 1, pages: [{ page: 1, name: "page-1.jpg" }] }),
|
||||
cbzPageUrl: (bookId: number, page: number) => `/books/${bookId}/pages/${page}`
|
||||
}
|
||||
}));
|
||||
|
||||
import { CbzReader } from "./CbzReader";
|
||||
|
||||
type ElementLike = {
|
||||
type: unknown;
|
||||
props?: Record<string, unknown> & { children?: unknown };
|
||||
};
|
||||
|
||||
function isElementLike(value: unknown): value is ElementLike {
|
||||
return Boolean(value && typeof value === "object" && "type" in value);
|
||||
}
|
||||
|
||||
function findElementsByType(node: unknown, type: string): ElementLike[] {
|
||||
if (Array.isArray(node)) return node.flatMap((child) => findElementsByType(child, type));
|
||||
if (!isElementLike(node)) return [];
|
||||
|
||||
const matches = node.type === type ? [node] : [];
|
||||
return [...matches, ...findElementsByType(node.props?.children, type)];
|
||||
}
|
||||
|
||||
describe("CbzReader vertical image load", () => {
|
||||
beforeEach(() => {
|
||||
hookState.stateIndex = 0;
|
||||
hookState.updates = [];
|
||||
hookState.states = [
|
||||
{ bookId: 2, pageCount: 1, pages: [{ page: 1, name: "page-1.jpg" }] },
|
||||
undefined,
|
||||
undefined,
|
||||
0,
|
||||
0,
|
||||
{ width: 800, height: 1200 },
|
||||
null,
|
||||
{}
|
||||
];
|
||||
});
|
||||
|
||||
it("records vertical image dimensions before React clears the load event target", () => {
|
||||
const tree = CbzReader({
|
||||
bookId: 2,
|
||||
page: 1,
|
||||
zoom: 100,
|
||||
mode: "vertical",
|
||||
onPageCommit: vi.fn(),
|
||||
onControlsChange: vi.fn()
|
||||
});
|
||||
const image = findElementsByType(tree, "img")[0];
|
||||
const onLoad = image.props?.onLoad as (event: { currentTarget: { naturalWidth: number; naturalHeight: number } | null }) => void;
|
||||
const event: { currentTarget: { naturalWidth: number; naturalHeight: number } | null } = { currentTarget: { naturalWidth: 480, naturalHeight: 960 } };
|
||||
|
||||
onLoad(event);
|
||||
event.currentTarget = null;
|
||||
|
||||
let nextSizes: unknown;
|
||||
expect(() => {
|
||||
nextSizes = (hookState.updates[7][0] as (current: Record<number, unknown>) => unknown)({});
|
||||
}).not.toThrow();
|
||||
expect(nextSizes).toEqual({ 1: { width: 480, height: 960 } });
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user