merge: fix/37-reader-webtoon-cbz-naturalwidth dans develop (naturalWidth capturé avant neutralisation currentTarget)
This commit is contained in:
@ -217,9 +217,10 @@ export function CbzReader({
|
|||||||
loading="lazy"
|
loading="lazy"
|
||||||
style={verticalImageStyle(item.page)}
|
style={verticalImageStyle(item.page)}
|
||||||
onLoad={(event) => {
|
onLoad={(event) => {
|
||||||
|
const { naturalWidth, naturalHeight } = event.currentTarget;
|
||||||
setImageSizes((current) => ({
|
setImageSizes((current) => ({
|
||||||
...current,
|
...current,
|
||||||
[item.page]: { width: event.currentTarget.naturalWidth, height: event.currentTarget.naturalHeight }
|
[item.page]: { width: naturalWidth, height: naturalHeight }
|
||||||
}));
|
}));
|
||||||
}}
|
}}
|
||||||
onError={() => setPageError(`Page ${item.page} indisponible.`)}
|
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