leafthrough 0.0.0-stage → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,42 @@
1
+ import * as THREE from 'three';
2
+ import type { Engine } from '../engine.js';
3
+ import type { ResolvedSettings } from '../options.js';
4
+ export interface PlainEngineContext {
5
+ /** Receives pointer input; covers the pages. */
6
+ hitArea: HTMLElement;
7
+ settings: ResolvedSettings;
8
+ pageCount: number;
9
+ /** Where the magazine opens, in the engine's own position units. */
10
+ position: number;
11
+ }
12
+ /**
13
+ * The plain view's engine: nothing moves, the pages just change. Positions mean what they
14
+ * do in the 3D engines (spread: sheets turned to the left; single: pages turned). The
15
+ * controller shows the pages themselves.
16
+ */
17
+ export declare class PlainEngine implements Engine {
18
+ readonly group: THREE.Group<THREE.Object3DEventMap>;
19
+ readonly maxPosition: number;
20
+ private readonly spread;
21
+ private readonly settings;
22
+ private readonly hitArea;
23
+ private readonly abort;
24
+ private current;
25
+ private dirty;
26
+ private press;
27
+ constructor(ctx: PlainEngineContext);
28
+ get position(): number;
29
+ get turning(): boolean;
30
+ pagesInView(): {
31
+ from: number;
32
+ to: number;
33
+ };
34
+ get activeSide(): "both" | "left" | "right";
35
+ update(): boolean;
36
+ flip(forward: boolean): boolean;
37
+ jumpTo(position: number): void;
38
+ setPageTexture(): void;
39
+ dispose(): void;
40
+ private clamp;
41
+ private bindInput;
42
+ }
@@ -0,0 +1,27 @@
1
+ import { type CSSProperties } from 'react';
2
+ import { LeafThrough as Magazine, type GoToOptions } from './LeafThrough.js';
3
+ import { type LeafThroughOptions } from './options.js';
4
+ export type * from './options.js';
5
+ export interface LeafThroughProps extends LeafThroughOptions {
6
+ className?: string;
7
+ style?: CSSProperties;
8
+ }
9
+ export interface LeafThroughHandle {
10
+ next(): boolean;
11
+ prev(): boolean;
12
+ goTo(page: number, options?: GoToOptions): void;
13
+ readonly page: number;
14
+ readonly pageCount: number;
15
+ /** The underlying instance, or null before mount. */
16
+ readonly instance: Magazine | null;
17
+ }
18
+ /**
19
+ * React component (React 18+). Give it a size with `className` or `style`; without a height
20
+ * it takes its height from its width.
21
+ *
22
+ * ```tsx
23
+ * const ref = useRef<LeafThroughHandle>(null)
24
+ * <LeafThrough ref={ref} pages={pages} style={{ height: '80vh' }} onPageChange={(d) => setPage(d.page)} />
25
+ * ```
26
+ */
27
+ export declare const LeafThrough: import("react").ForwardRefExoticComponent<LeafThroughProps & import("react").RefAttributes<LeafThroughHandle>>;
package/dist/react.js ADDED
@@ -0,0 +1,60 @@
1
+ "use client";
2
+ import {
3
+ LeafThrough,
4
+ defaultPageLabel
5
+ } from "./chunk-DQL4R32K.js";
6
+
7
+ // src/react.tsx
8
+ import { forwardRef, useEffect, useImperativeHandle, useRef } from "react";
9
+ import { jsx } from "react/jsx-runtime";
10
+ var LeafThrough2 = forwardRef(function LeafThrough3({ className, style, ...options }, ref) {
11
+ const element = useRef(null);
12
+ const instance = useRef(null);
13
+ const latest = useRef(options);
14
+ latest.current = options;
15
+ const callbacks = useRef({
16
+ onPageChange: (detail) => latest.current.onPageChange?.(detail),
17
+ onReady: () => latest.current.onReady?.(),
18
+ onPageLoad: (page) => latest.current.onPageLoad?.(page),
19
+ onError: (error, page) => {
20
+ const handler = latest.current.onError;
21
+ if (handler) handler(error, page);
22
+ else console.warn("[leafthrough]", error);
23
+ },
24
+ formatPageLabel: (detail) => latest.current.formatPageLabel?.(detail) ?? defaultPageLabel(detail)
25
+ }).current;
26
+ useEffect(() => {
27
+ const magazine = new LeafThrough(element.current, { ...latest.current, ...callbacks });
28
+ instance.current = magazine;
29
+ return () => {
30
+ magazine.dispose();
31
+ instance.current = null;
32
+ };
33
+ }, []);
34
+ useEffect(() => {
35
+ instance.current?.setOptions({ ...options, ...callbacks });
36
+ });
37
+ useImperativeHandle(
38
+ ref,
39
+ () => ({
40
+ next: () => instance.current?.next() ?? false,
41
+ prev: () => instance.current?.prev() ?? false,
42
+ goTo: (page, goToOptions) => instance.current?.goTo(page, goToOptions),
43
+ get page() {
44
+ return instance.current?.page ?? options.startPage ?? 0;
45
+ },
46
+ get pageCount() {
47
+ return options.pages.length;
48
+ },
49
+ get instance() {
50
+ return instance.current;
51
+ }
52
+ }),
53
+ [options.pages.length, options.startPage]
54
+ );
55
+ return /* @__PURE__ */ jsx("div", { ref: element, className, style });
56
+ });
57
+ export {
58
+ LeafThrough2 as LeafThrough
59
+ };
60
+ //# sourceMappingURL=react.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/react.tsx"],"sourcesContent":["'use client'\n\nimport { forwardRef, useEffect, useImperativeHandle, useRef, type CSSProperties } from 'react'\nimport { LeafThrough as Magazine, type GoToOptions } from './LeafThrough.js'\nimport { defaultPageLabel, type LeafThroughOptions, type PageChangeDetail } from './options.js'\n\nexport type * from './options.js'\n\nexport interface LeafThroughProps extends LeafThroughOptions {\n className?: string\n style?: CSSProperties\n}\n\nexport interface LeafThroughHandle {\n next(): boolean\n prev(): boolean\n goTo(page: number, options?: GoToOptions): void\n readonly page: number\n readonly pageCount: number\n /** The underlying instance, or null before mount. */\n readonly instance: Magazine | null\n}\n\n/**\n * React component (React 18+). Give it a size with `className` or `style`; without a height\n * it takes its height from its width.\n *\n * ```tsx\n * const ref = useRef<LeafThroughHandle>(null)\n * <LeafThrough ref={ref} pages={pages} style={{ height: '80vh' }} onPageChange={(d) => setPage(d.page)} />\n * ```\n */\nexport const LeafThrough = forwardRef<LeafThroughHandle, LeafThroughProps>(function LeafThrough(\n { className, style, ...options },\n ref,\n) {\n const element = useRef<HTMLDivElement>(null)\n const instance = useRef<Magazine | null>(null)\n // callbacks change every render; route them through a ref so they never cause a rebuild\n const latest = useRef(options)\n latest.current = options\n\n const callbacks = useRef({\n onPageChange: (detail: PageChangeDetail) => latest.current.onPageChange?.(detail),\n onReady: () => latest.current.onReady?.(),\n onPageLoad: (page: number) => latest.current.onPageLoad?.(page),\n onError: (error: unknown, page?: number) => {\n const handler = latest.current.onError\n if (handler) handler(error, page)\n else console.warn('[leafthrough]', error)\n },\n formatPageLabel: (detail: PageChangeDetail) => latest.current.formatPageLabel?.(detail) ?? defaultPageLabel(detail),\n }).current\n\n useEffect(() => {\n const magazine = new Magazine(element.current!, { ...latest.current, ...callbacks })\n instance.current = magazine\n return () => {\n magazine.dispose()\n instance.current = null\n }\n }, [])\n\n // Props are the whole state, so a prop that's removed goes back to its default.\n // Everything is compared by value, so inline objects and arrays don't rebuild anything.\n useEffect(() => {\n instance.current?.setOptions({ ...options, ...callbacks })\n })\n\n useImperativeHandle(\n ref,\n () => ({\n next: () => instance.current?.next() ?? false,\n prev: () => instance.current?.prev() ?? false,\n goTo: (page, goToOptions) => instance.current?.goTo(page, goToOptions),\n get page() {\n return instance.current?.page ?? options.startPage ?? 0\n },\n get pageCount() {\n return options.pages.length\n },\n get instance() {\n return instance.current\n },\n }),\n [options.pages.length, options.startPage],\n )\n\n return <div ref={element} className={className} style={style} />\n})\n\n"],"mappings":";;;;;;;AAEA,SAAS,YAAY,WAAW,qBAAqB,cAAkC;AAsF9E;AAxDF,IAAMA,eAAc,WAAgD,SAASA,aAClF,EAAE,WAAW,OAAO,GAAG,QAAQ,GAC/B,KACA;AACA,QAAM,UAAU,OAAuB,IAAI;AAC3C,QAAM,WAAW,OAAwB,IAAI;AAE7C,QAAM,SAAS,OAAO,OAAO;AAC7B,SAAO,UAAU;AAEjB,QAAM,YAAY,OAAO;AAAA,IACvB,cAAc,CAAC,WAA6B,OAAO,QAAQ,eAAe,MAAM;AAAA,IAChF,SAAS,MAAM,OAAO,QAAQ,UAAU;AAAA,IACxC,YAAY,CAAC,SAAiB,OAAO,QAAQ,aAAa,IAAI;AAAA,IAC9D,SAAS,CAAC,OAAgB,SAAkB;AAC1C,YAAM,UAAU,OAAO,QAAQ;AAC/B,UAAI,QAAS,SAAQ,OAAO,IAAI;AAAA,UAC3B,SAAQ,KAAK,iBAAiB,KAAK;AAAA,IAC1C;AAAA,IACA,iBAAiB,CAAC,WAA6B,OAAO,QAAQ,kBAAkB,MAAM,KAAK,iBAAiB,MAAM;AAAA,EACpH,CAAC,EAAE;AAEH,YAAU,MAAM;AACd,UAAM,WAAW,IAAI,YAAS,QAAQ,SAAU,EAAE,GAAG,OAAO,SAAS,GAAG,UAAU,CAAC;AACnF,aAAS,UAAU;AACnB,WAAO,MAAM;AACX,eAAS,QAAQ;AACjB,eAAS,UAAU;AAAA,IACrB;AAAA,EACF,GAAG,CAAC,CAAC;AAIL,YAAU,MAAM;AACd,aAAS,SAAS,WAAW,EAAE,GAAG,SAAS,GAAG,UAAU,CAAC;AAAA,EAC3D,CAAC;AAED;AAAA,IACE;AAAA,IACA,OAAO;AAAA,MACL,MAAM,MAAM,SAAS,SAAS,KAAK,KAAK;AAAA,MACxC,MAAM,MAAM,SAAS,SAAS,KAAK,KAAK;AAAA,MACxC,MAAM,CAAC,MAAM,gBAAgB,SAAS,SAAS,KAAK,MAAM,WAAW;AAAA,MACrE,IAAI,OAAO;AACT,eAAO,SAAS,SAAS,QAAQ,QAAQ,aAAa;AAAA,MACxD;AAAA,MACA,IAAI,YAAY;AACd,eAAO,QAAQ,MAAM;AAAA,MACvB;AAAA,MACA,IAAI,WAAW;AACb,eAAO,SAAS;AAAA,MAClB;AAAA,IACF;AAAA,IACA,CAAC,QAAQ,MAAM,QAAQ,QAAQ,SAAS;AAAA,EAC1C;AAEA,SAAO,oBAAC,SAAI,KAAK,SAAS,WAAsB,OAAc;AAChE,CAAC;","names":["LeafThrough"]}
@@ -0,0 +1,76 @@
1
+ import * as THREE from 'three';
2
+ import type { Engine, EngineContext } from '../engine.js';
3
+ /**
4
+ * One page at a time: turned pages swing round the spine and roll up behind the magazine.
5
+ */
6
+ export declare class SingleEngine implements Engine {
7
+ readonly group: THREE.Group<THREE.Object3DEventMap>;
8
+ readonly maxPosition: number;
9
+ private readonly settings;
10
+ private readonly halfHeight;
11
+ private readonly liftHeight;
12
+ private readonly camera;
13
+ private readonly canvas;
14
+ private readonly hitArea;
15
+ private readonly metrics;
16
+ private readonly geometry;
17
+ private readonly sheets;
18
+ private readonly count;
19
+ private readonly radiusSpacing;
20
+ private readonly catchUp;
21
+ private readonly fallDelay;
22
+ private readonly fallDuration;
23
+ private readonly abort;
24
+ private current;
25
+ private turned;
26
+ private flights;
27
+ private drag;
28
+ private press;
29
+ private hold;
30
+ private touch;
31
+ private dirty;
32
+ private last;
33
+ private readonly raycaster;
34
+ private readonly ndc;
35
+ private readonly floor;
36
+ private readonly hit;
37
+ private readonly spine;
38
+ constructor(ctx: EngineContext);
39
+ get position(): number;
40
+ get turning(): boolean;
41
+ readonly activeSide = "both";
42
+ pagesInView(): {
43
+ from: number;
44
+ to: number;
45
+ };
46
+ private pileTop;
47
+ setPageTexture(page: number, texture: THREE.Texture): void;
48
+ dispose(): void;
49
+ private randomWobble;
50
+ private seconds;
51
+ private pileHeight;
52
+ private pileReach;
53
+ private paced;
54
+ private closing;
55
+ private shutting;
56
+ private inFlight;
57
+ private busy;
58
+ private floorPoint;
59
+ private grab;
60
+ private canTurn;
61
+ private sheetAt;
62
+ private commit;
63
+ private fly;
64
+ flip(forward: boolean): boolean;
65
+ jumpTo(position: number): void;
66
+ private bindInput;
67
+ private moved;
68
+ private cancelHold;
69
+ private holdTick;
70
+ private release;
71
+ private settleBack;
72
+ update(now: number): boolean;
73
+ private pileEdge;
74
+ private applyUniforms;
75
+ private shapeTurn;
76
+ }
@@ -0,0 +1,23 @@
1
+ import * as THREE from 'three';
2
+ import type { ResolvedSettings } from '../options.js';
3
+ import { type SheetMesh, type SheetShading, type SheetUniforms } from '../paper/paperMaterial.js';
4
+ export declare function createSingleGeometry(aspect: number): THREE.BufferGeometry;
5
+ export interface SingleSheetUniforms extends SheetUniforms {
6
+ uPileLift: THREE.IUniform<THREE.Vector3>;
7
+ uPileReach: THREE.IUniform<THREE.Vector2>;
8
+ uConeTaper: THREE.IUniform<number>;
9
+ uTailCurl: THREE.IUniform<THREE.Vector4>;
10
+ uTailBend: THREE.IUniform<number>;
11
+ uCone: THREE.IUniform<THREE.Vector3>;
12
+ uFlipRotation: THREE.IUniform<THREE.Vector2>;
13
+ uTrim: THREE.IUniform<THREE.Vector3>;
14
+ uFront: THREE.IUniform<THREE.Texture>;
15
+ uBack: THREE.IUniform<THREE.Texture>;
16
+ uPattern: THREE.IUniform<THREE.Texture>;
17
+ uSpineContact: THREE.IUniform<THREE.Vector3>;
18
+ uLightDirection: THREE.IUniform<THREE.Vector3>;
19
+ }
20
+ export declare function createSingleSheet(geometry: THREE.BufferGeometry, front: THREE.Texture, back: THREE.Texture, pattern: THREE.Texture, settings: ResolvedSettings, shading: SheetShading): {
21
+ mesh: SheetMesh;
22
+ uniforms: SingleSheetUniforms;
23
+ };
@@ -0,0 +1,64 @@
1
+ import * as THREE from 'three';
2
+ import type { Engine, EngineContext } from '../engine.js';
3
+ /**
4
+ * The open magazine: sheets rotate over the spine, bending as they go. Horizontal drag
5
+ * drives the turn; where the hand is around the spine tilts the fold.
6
+ */
7
+ export declare class SpreadEngine implements Engine {
8
+ readonly group: THREE.Group<THREE.Object3DEventMap>;
9
+ readonly maxPosition: number;
10
+ private readonly settings;
11
+ private readonly halfHeight;
12
+ private readonly camera;
13
+ private readonly canvas;
14
+ private readonly hitArea;
15
+ private readonly metrics;
16
+ private readonly geometry;
17
+ private readonly sheets;
18
+ private readonly abort;
19
+ private readonly shading;
20
+ private current;
21
+ private flights;
22
+ private drag;
23
+ private press;
24
+ private hold;
25
+ private hover;
26
+ private hovered;
27
+ private leader;
28
+ private dirty;
29
+ private last;
30
+ private readonly raycaster;
31
+ private readonly ndc;
32
+ private readonly floor;
33
+ private readonly hit;
34
+ private readonly spine;
35
+ constructor(ctx: EngineContext);
36
+ get position(): number;
37
+ get turning(): boolean;
38
+ pagesInView(): {
39
+ from: number;
40
+ to: number;
41
+ };
42
+ get activeSide(): "both" | "left" | "right";
43
+ setPageTexture(page: number, texture: THREE.Texture): void;
44
+ dispose(): void;
45
+ private randomWobble;
46
+ private seconds;
47
+ private arcLimit;
48
+ private restingArc;
49
+ private inFlight;
50
+ private sheetAt;
51
+ private curveFor;
52
+ private setCurve;
53
+ private commit;
54
+ private fly;
55
+ flip(forward: boolean): boolean;
56
+ jumpTo(position: number): void;
57
+ private bindInput;
58
+ private moved;
59
+ private cancelHold;
60
+ private holdTick;
61
+ private release;
62
+ update(now: number): boolean;
63
+ private applyUniforms;
64
+ }
@@ -0,0 +1,23 @@
1
+ import * as THREE from 'three';
2
+ import type { ResolvedSettings } from '../options.js';
3
+ import { type SheetMesh, type SheetShading, type SheetUniforms } from '../paper/paperMaterial.js';
4
+ export declare function createSpreadGeometry(aspect: number): THREE.BufferGeometry;
5
+ export interface SpreadSheetUniforms extends SheetUniforms {
6
+ uFlipProgress: THREE.IUniform<number>;
7
+ uWrinkleSide: THREE.IUniform<number>;
8
+ uBendAngle: THREE.IUniform<number>;
9
+ uFold: THREE.IUniform<THREE.Vector2>;
10
+ uCurl: THREE.IUniform<THREE.Vector2>;
11
+ uFlipRotation: THREE.IUniform<THREE.Vector2>;
12
+ uDirection: THREE.IUniform<number>;
13
+ uStackLift: THREE.IUniform<number>;
14
+ uFront: THREE.IUniform<THREE.Texture>;
15
+ uBack: THREE.IUniform<THREE.Texture>;
16
+ uPattern: THREE.IUniform<THREE.Texture>;
17
+ uSpineContact: THREE.IUniform<THREE.Vector3>;
18
+ uLightDirection: THREE.IUniform<THREE.Vector3>;
19
+ }
20
+ export declare function createSpreadSheet(geometry: THREE.BufferGeometry, front: THREE.Texture, back: THREE.Texture, pattern: THREE.Texture, settings: ResolvedSettings, shading: SheetShading): {
21
+ mesh: SheetMesh;
22
+ uniforms: SpreadSheetUniforms;
23
+ };
@@ -0,0 +1,19 @@
1
+ import { LeafThrough } from './LeafThrough.js';
2
+ import type { LeafThroughOptions } from './options.js';
3
+ export { LeafThrough };
4
+ export type * from './options.js';
5
+ export interface LeafThroughActionOptions extends LeafThroughOptions {
6
+ /** Called with the instance, for `next()`, `prev()` and `goTo()`. */
7
+ onInit?: (magazine: LeafThrough) => void;
8
+ }
9
+ /**
10
+ * Svelte action (Svelte 4 and 5). Give the element a size.
11
+ *
12
+ * ```svelte
13
+ * <div style="height: 80vh" use:leafThrough={{ pages, onPageChange: (d) => (page = d.page) }} />
14
+ * ```
15
+ */
16
+ export declare function leafThrough(node: HTMLElement, options: LeafThroughActionOptions): {
17
+ update(next: LeafThroughActionOptions): void;
18
+ destroy(): void;
19
+ };
package/dist/svelte.js ADDED
@@ -0,0 +1,24 @@
1
+ import {
2
+ LeafThrough
3
+ } from "./chunk-DQL4R32K.js";
4
+
5
+ // src/svelte.ts
6
+ function leafThrough(node, options) {
7
+ const { onInit, ...rest } = options;
8
+ const magazine = new LeafThrough(node, rest);
9
+ onInit?.(magazine);
10
+ return {
11
+ update(next) {
12
+ const { onInit: _ignored, ...nextRest } = next;
13
+ magazine.setOptions(nextRest);
14
+ },
15
+ destroy() {
16
+ magazine.dispose();
17
+ }
18
+ };
19
+ }
20
+ export {
21
+ LeafThrough,
22
+ leafThrough
23
+ };
24
+ //# sourceMappingURL=svelte.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/svelte.ts"],"sourcesContent":["import { LeafThrough } from './LeafThrough.js'\nimport type { LeafThroughOptions } from './options.js'\n\nexport { LeafThrough }\nexport type * from './options.js'\n\nexport interface LeafThroughActionOptions extends LeafThroughOptions {\n /** Called with the instance, for `next()`, `prev()` and `goTo()`. */\n onInit?: (magazine: LeafThrough) => void\n}\n\n/**\n * Svelte action (Svelte 4 and 5). Give the element a size.\n *\n * ```svelte\n * <div style=\"height: 80vh\" use:leafThrough={{ pages, onPageChange: (d) => (page = d.page) }} />\n * ```\n */\nexport function leafThrough(node: HTMLElement, options: LeafThroughActionOptions) {\n const { onInit, ...rest } = options\n const magazine = new LeafThrough(node, rest)\n onInit?.(magazine)\n return {\n update(next: LeafThroughActionOptions) {\n const { onInit: _ignored, ...nextRest } = next\n magazine.setOptions(nextRest)\n },\n destroy() {\n magazine.dispose()\n },\n }\n}\n"],"mappings":";;;;;AAkBO,SAAS,YAAY,MAAmB,SAAmC;AAChF,QAAM,EAAE,QAAQ,GAAG,KAAK,IAAI;AAC5B,QAAM,WAAW,IAAI,YAAY,MAAM,IAAI;AAC3C,WAAS,QAAQ;AACjB,SAAO;AAAA,IACL,OAAO,MAAgC;AACrC,YAAM,EAAE,QAAQ,UAAU,GAAG,SAAS,IAAI;AAC1C,eAAS,WAAW,QAAQ;AAAA,IAC9B;AAAA,IACA,UAAU;AACR,eAAS,QAAQ;AAAA,IACnB;AAAA,EACF;AACF;","names":[]}
@@ -0,0 +1,54 @@
1
+ import * as THREE from 'three';
2
+ import type { PageImage } from './options.js';
3
+ export interface PageLoaderEvents {
4
+ onLoad(page: number, texture: THREE.Texture): void;
5
+ /** The page's texture was freed; show plain paper until it loads again. */
6
+ onUnload(page: number): void;
7
+ onError(page: number, error: unknown): void;
8
+ }
9
+ /**
10
+ * Loads page images into textures, nearest the visible pages first. Pages within `radius`
11
+ * of the visible ones load; pages more than twice as far unload. Pages show plain paper
12
+ * until their image arrives.
13
+ */
14
+ export declare class PageLoader {
15
+ private readonly sources;
16
+ private readonly renderer;
17
+ private radius;
18
+ private readonly events;
19
+ /** Loaded textures by page; missing pages are still loading, unloaded or failed. */
20
+ readonly textures: (THREE.Texture | undefined)[];
21
+ private readonly owned;
22
+ private readonly inFlight;
23
+ private readonly failed;
24
+ private first;
25
+ private from;
26
+ private to;
27
+ private around;
28
+ private wrap;
29
+ private waiting;
30
+ private settleFirst;
31
+ private disposed;
32
+ constructor(sources: PageImage[], renderer: THREE.WebGLRenderer, radius: number, events: PageLoaderEvents);
33
+ /**
34
+ * Starts loading around the visible pages `from`–`to`. Resolves once the `first` pages
35
+ * within reach are in (or failed).
36
+ */
37
+ start(from: number, to: number, first: number[]): Promise<void>;
38
+ /**
39
+ * Follows the reader: loads around the pages in view (`from`–`to`), the page being read
40
+ * (`around`) first, and unloads pages left far behind.
41
+ */
42
+ focus(from: number, to?: number, around?: number): void;
43
+ setWrap(wrap: boolean): void;
44
+ setRadius(radius: number): void;
45
+ /** Loads the pages that failed again. */
46
+ retry(): void;
47
+ dispose(): void;
48
+ private distance;
49
+ private pump;
50
+ private load;
51
+ private createTexture;
52
+ }
53
+ /** Loads the paper grain option into a tiling texture. */
54
+ export declare function loadGrain(source: string | HTMLImageElement | HTMLCanvasElement): Promise<THREE.Texture>;
package/dist/vue.d.ts ADDED
@@ -0,0 +1,87 @@
1
+ import { type PropType } from 'vue';
2
+ import type { LeafThroughOptions, InteractionOptions, LightingOptions, MotionOptions, PageChangeDetail, PageSource, PaperOptions } from './options.js';
3
+ export type * from './options.js';
4
+ /**
5
+ * Vue 3 component. Give it a size with a class or style; without a height it takes its
6
+ * height from its width. Exposes `next()`, `prev()`, `goTo()` and `instance` via a template ref.
7
+ *
8
+ * ```vue
9
+ * <LeafThrough :pages="pages" style="height: 80vh" @pagechange="(d) => (page = d.page)" />
10
+ * ```
11
+ */
12
+ export declare const LeafThrough: import("vue").DefineComponent<import("vue").ExtractPropTypes<{
13
+ pages: {
14
+ type: PropType<PageSource[]>;
15
+ required: true;
16
+ };
17
+ startPage: NumberConstructor;
18
+ layout: PropType<LeafThroughOptions['layout']>;
19
+ spreadQuery: StringConstructor;
20
+ pageAspect: NumberConstructor;
21
+ loop: {
22
+ type: BooleanConstructor;
23
+ default: undefined;
24
+ };
25
+ bleed: {
26
+ type: BooleanConstructor;
27
+ default: undefined;
28
+ };
29
+ paper: PropType<PaperOptions>;
30
+ lighting: PropType<LightingOptions>;
31
+ motion: PropType<MotionOptions>;
32
+ interaction: PropType<InteractionOptions>;
33
+ maxPixelRatio: NumberConstructor;
34
+ preload: NumberConstructor;
35
+ plain: {
36
+ type: BooleanConstructor;
37
+ default: undefined;
38
+ };
39
+ label: StringConstructor;
40
+ formatPageLabel: PropType<LeafThroughOptions['formatPageLabel']>;
41
+ }>, () => import("vue").VNode<import("vue").RendererNode, import("vue").RendererElement, {
42
+ [key: string]: any;
43
+ }>, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
44
+ pagechange: (_detail: PageChangeDetail) => true;
45
+ ready: () => true;
46
+ pageload: (_page: number) => true;
47
+ error: (_error: unknown, _page?: number) => true;
48
+ }, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<{
49
+ pages: {
50
+ type: PropType<PageSource[]>;
51
+ required: true;
52
+ };
53
+ startPage: NumberConstructor;
54
+ layout: PropType<LeafThroughOptions['layout']>;
55
+ spreadQuery: StringConstructor;
56
+ pageAspect: NumberConstructor;
57
+ loop: {
58
+ type: BooleanConstructor;
59
+ default: undefined;
60
+ };
61
+ bleed: {
62
+ type: BooleanConstructor;
63
+ default: undefined;
64
+ };
65
+ paper: PropType<PaperOptions>;
66
+ lighting: PropType<LightingOptions>;
67
+ motion: PropType<MotionOptions>;
68
+ interaction: PropType<InteractionOptions>;
69
+ maxPixelRatio: NumberConstructor;
70
+ preload: NumberConstructor;
71
+ plain: {
72
+ type: BooleanConstructor;
73
+ default: undefined;
74
+ };
75
+ label: StringConstructor;
76
+ formatPageLabel: PropType<LeafThroughOptions['formatPageLabel']>;
77
+ }>> & Readonly<{
78
+ onError?: ((_error: unknown, _page?: number | undefined) => any) | undefined;
79
+ onPagechange?: ((_detail: PageChangeDetail) => any) | undefined;
80
+ onPageload?: ((_page: number) => any) | undefined;
81
+ onReady?: (() => any) | undefined;
82
+ }>, {
83
+ loop: boolean;
84
+ bleed: boolean;
85
+ plain: boolean;
86
+ }, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
87
+ export default LeafThrough;
package/dist/vue.js ADDED
@@ -0,0 +1,65 @@
1
+ import {
2
+ LeafThrough
3
+ } from "./chunk-DQL4R32K.js";
4
+
5
+ // src/vue.ts
6
+ import { defineComponent, h, onBeforeUnmount, onMounted, ref, shallowRef, watch } from "vue";
7
+ var LeafThrough2 = defineComponent({
8
+ name: "LeafThrough",
9
+ props: {
10
+ pages: { type: Array, required: true },
11
+ startPage: Number,
12
+ layout: String,
13
+ spreadQuery: String,
14
+ pageAspect: Number,
15
+ loop: { type: Boolean, default: void 0 },
16
+ bleed: { type: Boolean, default: void 0 },
17
+ paper: Object,
18
+ lighting: Object,
19
+ motion: Object,
20
+ interaction: Object,
21
+ maxPixelRatio: Number,
22
+ preload: Number,
23
+ plain: { type: Boolean, default: void 0 },
24
+ label: String,
25
+ formatPageLabel: Function
26
+ },
27
+ emits: {
28
+ pagechange: (_detail) => true,
29
+ ready: () => true,
30
+ pageload: (_page) => true,
31
+ error: (_error, _page) => true
32
+ },
33
+ setup(props, { emit, expose }) {
34
+ const element = ref();
35
+ const instance = shallowRef(null);
36
+ const events = {
37
+ onPageChange: (detail) => emit("pagechange", detail),
38
+ onReady: () => emit("ready"),
39
+ onPageLoad: (page) => emit("pageload", page),
40
+ onError: (error, page) => emit("error", error, page)
41
+ };
42
+ const options = () => ({ ...props, ...events });
43
+ onMounted(() => {
44
+ instance.value = new LeafThrough(element.value, options());
45
+ });
46
+ watch(options, (next) => instance.value?.setOptions(next), { deep: true });
47
+ onBeforeUnmount(() => {
48
+ instance.value?.dispose();
49
+ instance.value = null;
50
+ });
51
+ expose({
52
+ next: () => instance.value?.next() ?? false,
53
+ prev: () => instance.value?.prev() ?? false,
54
+ goTo: (page, goToOptions) => instance.value?.goTo(page, goToOptions),
55
+ instance
56
+ });
57
+ return () => h("div", { ref: element });
58
+ }
59
+ });
60
+ var vue_default = LeafThrough2;
61
+ export {
62
+ LeafThrough2 as LeafThrough,
63
+ vue_default as default
64
+ };
65
+ //# sourceMappingURL=vue.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/vue.ts"],"sourcesContent":["import { defineComponent, h, onBeforeUnmount, onMounted, ref, shallowRef, watch, type PropType } from 'vue'\nimport { LeafThrough as Magazine, type GoToOptions } from './LeafThrough.js'\nimport type {\n LeafThroughOptions,\n InteractionOptions,\n LightingOptions,\n MotionOptions,\n PageChangeDetail,\n PageSource,\n PaperOptions,\n} from './options.js'\n\nexport type * from './options.js'\n\n/**\n * Vue 3 component. Give it a size with a class or style; without a height it takes its\n * height from its width. Exposes `next()`, `prev()`, `goTo()` and `instance` via a template ref.\n *\n * ```vue\n * <LeafThrough :pages=\"pages\" style=\"height: 80vh\" @pagechange=\"(d) => (page = d.page)\" />\n * ```\n */\nexport const LeafThrough = defineComponent({\n name: 'LeafThrough',\n props: {\n pages: { type: Array as PropType<PageSource[]>, required: true },\n startPage: Number,\n layout: String as PropType<LeafThroughOptions['layout']>,\n spreadQuery: String,\n pageAspect: Number,\n loop: { type: Boolean, default: undefined },\n bleed: { type: Boolean, default: undefined },\n paper: Object as PropType<PaperOptions>,\n lighting: Object as PropType<LightingOptions>,\n motion: Object as PropType<MotionOptions>,\n interaction: Object as PropType<InteractionOptions>,\n maxPixelRatio: Number,\n preload: Number,\n plain: { type: Boolean, default: undefined },\n label: String,\n formatPageLabel: Function as PropType<LeafThroughOptions['formatPageLabel']>,\n },\n emits: {\n pagechange: (_detail: PageChangeDetail) => true,\n ready: () => true,\n pageload: (_page: number) => true,\n error: (_error: unknown, _page?: number) => true,\n },\n setup(props, { emit, expose }) {\n const element = ref<HTMLDivElement>()\n const instance = shallowRef<Magazine | null>(null)\n\n const events = {\n onPageChange: (detail: PageChangeDetail) => emit('pagechange', detail),\n onReady: () => emit('ready'),\n onPageLoad: (page: number) => emit('pageload', page),\n onError: (error: unknown, page?: number) => emit('error', error, page),\n }\n // every prop, set or not: unset ones fall back to the magazine's defaults\n const options = (): LeafThroughOptions => ({ ...(props as unknown as LeafThroughOptions), ...events })\n\n onMounted(() => {\n instance.value = new Magazine(element.value!, options())\n })\n // compared by value, so only real changes rebuild anything\n watch(options, (next) => instance.value?.setOptions(next), { deep: true })\n onBeforeUnmount(() => {\n instance.value?.dispose()\n instance.value = null\n })\n\n expose({\n next: () => instance.value?.next() ?? false,\n prev: () => instance.value?.prev() ?? false,\n goTo: (page: number, goToOptions?: GoToOptions) => instance.value?.goTo(page, goToOptions),\n instance,\n })\n\n return () => h('div', { ref: element })\n },\n})\n\nexport default LeafThrough\n"],"mappings":";;;;;AAAA,SAAS,iBAAiB,GAAG,iBAAiB,WAAW,KAAK,YAAY,aAA4B;AAsB/F,IAAMA,eAAc,gBAAgB;AAAA,EACzC,MAAM;AAAA,EACN,OAAO;AAAA,IACL,OAAO,EAAE,MAAM,OAAiC,UAAU,KAAK;AAAA,IAC/D,WAAW;AAAA,IACX,QAAQ;AAAA,IACR,aAAa;AAAA,IACb,YAAY;AAAA,IACZ,MAAM,EAAE,MAAM,SAAS,SAAS,OAAU;AAAA,IAC1C,OAAO,EAAE,MAAM,SAAS,SAAS,OAAU;AAAA,IAC3C,OAAO;AAAA,IACP,UAAU;AAAA,IACV,QAAQ;AAAA,IACR,aAAa;AAAA,IACb,eAAe;AAAA,IACf,SAAS;AAAA,IACT,OAAO,EAAE,MAAM,SAAS,SAAS,OAAU;AAAA,IAC3C,OAAO;AAAA,IACP,iBAAiB;AAAA,EACnB;AAAA,EACA,OAAO;AAAA,IACL,YAAY,CAAC,YAA8B;AAAA,IAC3C,OAAO,MAAM;AAAA,IACb,UAAU,CAAC,UAAkB;AAAA,IAC7B,OAAO,CAAC,QAAiB,UAAmB;AAAA,EAC9C;AAAA,EACA,MAAM,OAAO,EAAE,MAAM,OAAO,GAAG;AAC7B,UAAM,UAAU,IAAoB;AACpC,UAAM,WAAW,WAA4B,IAAI;AAEjD,UAAM,SAAS;AAAA,MACb,cAAc,CAAC,WAA6B,KAAK,cAAc,MAAM;AAAA,MACrE,SAAS,MAAM,KAAK,OAAO;AAAA,MAC3B,YAAY,CAAC,SAAiB,KAAK,YAAY,IAAI;AAAA,MACnD,SAAS,CAAC,OAAgB,SAAkB,KAAK,SAAS,OAAO,IAAI;AAAA,IACvE;AAEA,UAAM,UAAU,OAA2B,EAAE,GAAI,OAAyC,GAAG,OAAO;AAEpG,cAAU,MAAM;AACd,eAAS,QAAQ,IAAI,YAAS,QAAQ,OAAQ,QAAQ,CAAC;AAAA,IACzD,CAAC;AAED,UAAM,SAAS,CAAC,SAAS,SAAS,OAAO,WAAW,IAAI,GAAG,EAAE,MAAM,KAAK,CAAC;AACzE,oBAAgB,MAAM;AACpB,eAAS,OAAO,QAAQ;AACxB,eAAS,QAAQ;AAAA,IACnB,CAAC;AAED,WAAO;AAAA,MACL,MAAM,MAAM,SAAS,OAAO,KAAK,KAAK;AAAA,MACtC,MAAM,MAAM,SAAS,OAAO,KAAK,KAAK;AAAA,MACtC,MAAM,CAAC,MAAc,gBAA8B,SAAS,OAAO,KAAK,MAAM,WAAW;AAAA,MACzF;AAAA,IACF,CAAC;AAED,WAAO,MAAM,EAAE,OAAO,EAAE,KAAK,QAAQ,CAAC;AAAA,EACxC;AACF,CAAC;AAED,IAAO,cAAQA;","names":["LeafThrough"]}