@ai-markdown/core 3.4.0 → 3.4.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.
|
@@ -413,7 +413,11 @@ interface ImageGeometry {
|
|
|
413
413
|
}
|
|
414
414
|
export declare const initialImageTransform: () => ImageTransform;
|
|
415
415
|
export declare function imageTransformStyle(transform: ImageTransform): string;
|
|
416
|
-
|
|
416
|
+
/** Scales by `ratio` about a viewport point, keeping the image point under it in place, within `limits`. */
|
|
417
|
+
export declare function zoomImage(transform: ImageTransform, ratio: number, geometry: ImageGeometry, centerX?: number, centerY?: number, touch?: boolean, limits?: {
|
|
418
|
+
min: number;
|
|
419
|
+
max: number;
|
|
420
|
+
}): ImageTransform;
|
|
417
421
|
/**
|
|
418
422
|
* The zoom factor for one wheel event. A full notch (100 pixels) is one 1.5x
|
|
419
423
|
* step, and a smaller delta a proportional part of it.
|
|
@@ -421,13 +425,14 @@ export declare function zoomImage(transform: ImageTransform, ratio: number, geom
|
|
|
421
425
|
* pages, not pixels: three lines or one page count as a notch.
|
|
422
426
|
* - `pinch` is a trackpad pinch, which arrives as a wheel event with the
|
|
423
427
|
* control key set and small deltas. It scales continuously with the delta.
|
|
428
|
+
* - `step` is what a full notch adds to the scale factor: 0.5 makes it 1.5x.
|
|
424
429
|
*/
|
|
425
|
-
export declare function imageWheelRatio(delta: number, mode?: number, pinch?: boolean): number;
|
|
430
|
+
export declare function imageWheelRatio(delta: number, mode?: number, pinch?: boolean, step?: number): number;
|
|
426
431
|
/** Snap a moved image back inside the viewport, taking quarter turns into account. */
|
|
427
432
|
export declare function reboundImage(transform: ImageTransform, geometry: ImageGeometry, bounds: {
|
|
428
433
|
left: number;
|
|
429
434
|
top: number;
|
|
430
|
-
}): ImageTransform;
|
|
435
|
+
}, minScale?: number): ImageTransform;
|
|
431
436
|
/** Upstream pinch center weights each finger by how far it moved. */
|
|
432
437
|
export declare function imagePinchCenter(oldA: {
|
|
433
438
|
x: number;
|
|
@@ -464,6 +469,14 @@ interface ImagePreviewState {
|
|
|
464
469
|
status: ImageLoadStatus;
|
|
465
470
|
/** A drag or a pinch is in progress: the image follows the pointer without a transition. */
|
|
466
471
|
moving: boolean;
|
|
472
|
+
/** The image can be dragged and pinched (the `movable` option). */
|
|
473
|
+
movable: boolean;
|
|
474
|
+
/** Viewport point the preview grows out of and shrinks back into: the anchor of the image shown when it opened,
|
|
475
|
+
* then of the image shown when it closes. Undefined means the centre of the viewport. */
|
|
476
|
+
origin: {
|
|
477
|
+
x: number;
|
|
478
|
+
y: number;
|
|
479
|
+
} | undefined;
|
|
467
480
|
canPrevious: boolean;
|
|
468
481
|
canNext: boolean;
|
|
469
482
|
canZoomIn: boolean;
|
|
@@ -475,12 +488,46 @@ interface ImagePreviewHost {
|
|
|
475
488
|
geometry(): ImageGeometry | undefined;
|
|
476
489
|
/** Runs the callback before the next paint and returns a cancel function. `requestAnimationFrame` in a browser. */
|
|
477
490
|
frame(callback: () => void): () => void;
|
|
491
|
+
/** Where the image registered under `id` sits on the page, as a viewport point: the centre of its thumbnail.
|
|
492
|
+
* Undefined when it has none or it is out of view. Asked when the preview opens and again when it closes. */
|
|
493
|
+
anchor?(id: object): {
|
|
494
|
+
x: number;
|
|
495
|
+
y: number;
|
|
496
|
+
} | undefined;
|
|
478
497
|
}
|
|
479
498
|
interface ImagePreviewOptions {
|
|
480
499
|
/** How long the leaving style stays up, in milliseconds. Zero closes at once. A function is read at each close,
|
|
481
500
|
* so a host can answer zero while the user prefers reduced motion. Default 300. */
|
|
482
501
|
closeDuration?: number | (() => number);
|
|
502
|
+
/** What one zoom step adds to the scale factor: the toolbar, a double click and a full wheel notch multiply or
|
|
503
|
+
* divide by `1 + scaleStep`. Default 0.5. */
|
|
504
|
+
scaleStep?: number;
|
|
505
|
+
/** Smallest scale the toolbar and the wheel reach, and the one a pinch returns to. Default 1. */
|
|
506
|
+
minScale?: number;
|
|
507
|
+
/** Largest scale. Default 50. */
|
|
508
|
+
maxScale?: number;
|
|
509
|
+
/** Whether the image can be dragged and pinched. Default true. */
|
|
510
|
+
movable?: boolean;
|
|
511
|
+
/** Whether the wheel and a trackpad pinch zoom. Default true. */
|
|
512
|
+
wheel?: boolean;
|
|
513
|
+
/** The preview started to open (true) or to close (false). */
|
|
514
|
+
onOpenChange?(open: boolean, info: {
|
|
515
|
+
current: number;
|
|
516
|
+
item: ImageGalleryItem | undefined;
|
|
517
|
+
}): void;
|
|
518
|
+
/** An opening or a closing ran to its end. One that was interrupted, by reopening while it closed or by
|
|
519
|
+
* `dispose`, reports nothing. */
|
|
520
|
+
afterOpenChange?(open: boolean): void;
|
|
521
|
+
/** The user moved to another image of the gallery. */
|
|
522
|
+
onChange?(current: number, previous: number): void;
|
|
523
|
+
/** The transform changed. A drag or a wheel burst reports once per frame, with the last action. */
|
|
524
|
+
onTransform?(info: {
|
|
525
|
+
transform: ImageTransform;
|
|
526
|
+
action: ImagePreviewAction;
|
|
527
|
+
}): void;
|
|
483
528
|
}
|
|
529
|
+
/** What changed the transform, as reported to `onTransform`. */
|
|
530
|
+
type ImagePreviewAction = 'zoomIn' | 'zoomOut' | 'rotateLeft' | 'rotateRight' | 'flipX' | 'flipY' | 'wheel' | 'doubleClick' | 'move' | 'pinch' | 'rebound' | 'prev' | 'next';
|
|
484
531
|
interface ImagePointer {
|
|
485
532
|
/** Pointer id: one drag, or one finger of a pinch. */
|
|
486
533
|
id: number;
|
|
@@ -507,8 +554,10 @@ interface ImagePointer {
|
|
|
507
554
|
* else is published at once. Each update is applied to the current state, so
|
|
508
555
|
* several in one frame add up.
|
|
509
556
|
* - Switching images resets the transform. Zoom is limited to 1x to 50x in
|
|
510
|
-
* 1.5x steps
|
|
511
|
-
* viewport centre for the toolbar.
|
|
557
|
+
* 1.5x steps unless the options say otherwise, about the pointer for the
|
|
558
|
+
* wheel and a double click, about the viewport centre for the toolbar.
|
|
559
|
+
* - The `on…` options report what the user did; they are called after the
|
|
560
|
+
* state that reflects it has been published.
|
|
512
561
|
*/
|
|
513
562
|
export declare function createImagePreviewController(host: ImagePreviewHost, publish: (state: ImagePreviewState) => void, options?: ImagePreviewOptions): {
|
|
514
563
|
state: () => ImagePreviewState;
|
|
@@ -536,7 +585,7 @@ export declare function createImagePreviewController(host: ImagePreviewHost, pub
|
|
|
536
585
|
mode?: number;
|
|
537
586
|
pinch?: boolean;
|
|
538
587
|
}): boolean;
|
|
539
|
-
/** Returns to the
|
|
588
|
+
/** Returns to the starting size, or zooms one step about the point when already there. */
|
|
540
589
|
doubleClick(x: number, y: number): void;
|
|
541
590
|
/** True when the key was used: prevent the default action. Left and right move through a gallery. */
|
|
542
591
|
key(key: string): boolean;
|
|
@@ -565,4 +614,4 @@ export interface CodeBlockOptions {
|
|
|
565
614
|
/** Text of the code block, as overrides of the English defaults. A function is called on every render. */
|
|
566
615
|
labels?: LabelsOption<CodeBlockLabels>;
|
|
567
616
|
}
|
|
568
|
-
export type { CodeBlockInput, CodeBlockLabels, CodeBlockSnapshot, CodeFrame, CodeSource, DiagramEngine, DiagramError, DiagramLabels, DiagramRequest, DiagramState, DiagramView, ImageActionIconName, ImageGallery, ImageGalleryItem, ImageGeometry, ImageIconName, ImageLabels, ImageLoadStatus, ImagePointer, ImagePreviewHost, ImagePreviewOptions, ImagePreviewPhase, ImagePreviewState, ImageTransform, LabelsOption, MermaidInitTarget, TableExportReason, TableLabels, TableProjection };
|
|
617
|
+
export type { CodeBlockInput, CodeBlockLabels, CodeBlockSnapshot, CodeFrame, CodeSource, DiagramEngine, DiagramError, DiagramLabels, DiagramRequest, DiagramState, DiagramView, ImageActionIconName, ImageGallery, ImageGalleryItem, ImageGeometry, ImageIconName, ImageLabels, ImageLoadStatus, ImagePointer, ImagePreviewAction, ImagePreviewHost, ImagePreviewOptions, ImagePreviewPhase, ImagePreviewState, ImageTransform, LabelsOption, MermaidInitTarget, TableExportReason, TableLabels, TableProjection };
|
|
@@ -413,7 +413,11 @@ interface ImageGeometry {
|
|
|
413
413
|
}
|
|
414
414
|
export declare const initialImageTransform: () => ImageTransform;
|
|
415
415
|
export declare function imageTransformStyle(transform: ImageTransform): string;
|
|
416
|
-
|
|
416
|
+
/** Scales by `ratio` about a viewport point, keeping the image point under it in place, within `limits`. */
|
|
417
|
+
export declare function zoomImage(transform: ImageTransform, ratio: number, geometry: ImageGeometry, centerX?: number, centerY?: number, touch?: boolean, limits?: {
|
|
418
|
+
min: number;
|
|
419
|
+
max: number;
|
|
420
|
+
}): ImageTransform;
|
|
417
421
|
/**
|
|
418
422
|
* The zoom factor for one wheel event. A full notch (100 pixels) is one 1.5x
|
|
419
423
|
* step, and a smaller delta a proportional part of it.
|
|
@@ -421,13 +425,14 @@ export declare function zoomImage(transform: ImageTransform, ratio: number, geom
|
|
|
421
425
|
* pages, not pixels: three lines or one page count as a notch.
|
|
422
426
|
* - `pinch` is a trackpad pinch, which arrives as a wheel event with the
|
|
423
427
|
* control key set and small deltas. It scales continuously with the delta.
|
|
428
|
+
* - `step` is what a full notch adds to the scale factor: 0.5 makes it 1.5x.
|
|
424
429
|
*/
|
|
425
|
-
export declare function imageWheelRatio(delta: number, mode?: number, pinch?: boolean): number;
|
|
430
|
+
export declare function imageWheelRatio(delta: number, mode?: number, pinch?: boolean, step?: number): number;
|
|
426
431
|
/** Snap a moved image back inside the viewport, taking quarter turns into account. */
|
|
427
432
|
export declare function reboundImage(transform: ImageTransform, geometry: ImageGeometry, bounds: {
|
|
428
433
|
left: number;
|
|
429
434
|
top: number;
|
|
430
|
-
}): ImageTransform;
|
|
435
|
+
}, minScale?: number): ImageTransform;
|
|
431
436
|
/** Upstream pinch center weights each finger by how far it moved. */
|
|
432
437
|
export declare function imagePinchCenter(oldA: {
|
|
433
438
|
x: number;
|
|
@@ -464,6 +469,14 @@ interface ImagePreviewState {
|
|
|
464
469
|
status: ImageLoadStatus;
|
|
465
470
|
/** A drag or a pinch is in progress: the image follows the pointer without a transition. */
|
|
466
471
|
moving: boolean;
|
|
472
|
+
/** The image can be dragged and pinched (the `movable` option). */
|
|
473
|
+
movable: boolean;
|
|
474
|
+
/** Viewport point the preview grows out of and shrinks back into: the anchor of the image shown when it opened,
|
|
475
|
+
* then of the image shown when it closes. Undefined means the centre of the viewport. */
|
|
476
|
+
origin: {
|
|
477
|
+
x: number;
|
|
478
|
+
y: number;
|
|
479
|
+
} | undefined;
|
|
467
480
|
canPrevious: boolean;
|
|
468
481
|
canNext: boolean;
|
|
469
482
|
canZoomIn: boolean;
|
|
@@ -475,12 +488,46 @@ interface ImagePreviewHost {
|
|
|
475
488
|
geometry(): ImageGeometry | undefined;
|
|
476
489
|
/** Runs the callback before the next paint and returns a cancel function. `requestAnimationFrame` in a browser. */
|
|
477
490
|
frame(callback: () => void): () => void;
|
|
491
|
+
/** Where the image registered under `id` sits on the page, as a viewport point: the centre of its thumbnail.
|
|
492
|
+
* Undefined when it has none or it is out of view. Asked when the preview opens and again when it closes. */
|
|
493
|
+
anchor?(id: object): {
|
|
494
|
+
x: number;
|
|
495
|
+
y: number;
|
|
496
|
+
} | undefined;
|
|
478
497
|
}
|
|
479
498
|
interface ImagePreviewOptions {
|
|
480
499
|
/** How long the leaving style stays up, in milliseconds. Zero closes at once. A function is read at each close,
|
|
481
500
|
* so a host can answer zero while the user prefers reduced motion. Default 300. */
|
|
482
501
|
closeDuration?: number | (() => number);
|
|
502
|
+
/** What one zoom step adds to the scale factor: the toolbar, a double click and a full wheel notch multiply or
|
|
503
|
+
* divide by `1 + scaleStep`. Default 0.5. */
|
|
504
|
+
scaleStep?: number;
|
|
505
|
+
/** Smallest scale the toolbar and the wheel reach, and the one a pinch returns to. Default 1. */
|
|
506
|
+
minScale?: number;
|
|
507
|
+
/** Largest scale. Default 50. */
|
|
508
|
+
maxScale?: number;
|
|
509
|
+
/** Whether the image can be dragged and pinched. Default true. */
|
|
510
|
+
movable?: boolean;
|
|
511
|
+
/** Whether the wheel and a trackpad pinch zoom. Default true. */
|
|
512
|
+
wheel?: boolean;
|
|
513
|
+
/** The preview started to open (true) or to close (false). */
|
|
514
|
+
onOpenChange?(open: boolean, info: {
|
|
515
|
+
current: number;
|
|
516
|
+
item: ImageGalleryItem | undefined;
|
|
517
|
+
}): void;
|
|
518
|
+
/** An opening or a closing ran to its end. One that was interrupted, by reopening while it closed or by
|
|
519
|
+
* `dispose`, reports nothing. */
|
|
520
|
+
afterOpenChange?(open: boolean): void;
|
|
521
|
+
/** The user moved to another image of the gallery. */
|
|
522
|
+
onChange?(current: number, previous: number): void;
|
|
523
|
+
/** The transform changed. A drag or a wheel burst reports once per frame, with the last action. */
|
|
524
|
+
onTransform?(info: {
|
|
525
|
+
transform: ImageTransform;
|
|
526
|
+
action: ImagePreviewAction;
|
|
527
|
+
}): void;
|
|
483
528
|
}
|
|
529
|
+
/** What changed the transform, as reported to `onTransform`. */
|
|
530
|
+
type ImagePreviewAction = 'zoomIn' | 'zoomOut' | 'rotateLeft' | 'rotateRight' | 'flipX' | 'flipY' | 'wheel' | 'doubleClick' | 'move' | 'pinch' | 'rebound' | 'prev' | 'next';
|
|
484
531
|
interface ImagePointer {
|
|
485
532
|
/** Pointer id: one drag, or one finger of a pinch. */
|
|
486
533
|
id: number;
|
|
@@ -507,8 +554,10 @@ interface ImagePointer {
|
|
|
507
554
|
* else is published at once. Each update is applied to the current state, so
|
|
508
555
|
* several in one frame add up.
|
|
509
556
|
* - Switching images resets the transform. Zoom is limited to 1x to 50x in
|
|
510
|
-
* 1.5x steps
|
|
511
|
-
* viewport centre for the toolbar.
|
|
557
|
+
* 1.5x steps unless the options say otherwise, about the pointer for the
|
|
558
|
+
* wheel and a double click, about the viewport centre for the toolbar.
|
|
559
|
+
* - The `on…` options report what the user did; they are called after the
|
|
560
|
+
* state that reflects it has been published.
|
|
512
561
|
*/
|
|
513
562
|
export declare function createImagePreviewController(host: ImagePreviewHost, publish: (state: ImagePreviewState) => void, options?: ImagePreviewOptions): {
|
|
514
563
|
state: () => ImagePreviewState;
|
|
@@ -536,7 +585,7 @@ export declare function createImagePreviewController(host: ImagePreviewHost, pub
|
|
|
536
585
|
mode?: number;
|
|
537
586
|
pinch?: boolean;
|
|
538
587
|
}): boolean;
|
|
539
|
-
/** Returns to the
|
|
588
|
+
/** Returns to the starting size, or zooms one step about the point when already there. */
|
|
540
589
|
doubleClick(x: number, y: number): void;
|
|
541
590
|
/** True when the key was used: prevent the default action. Left and right move through a gallery. */
|
|
542
591
|
key(key: string): boolean;
|
|
@@ -565,4 +614,4 @@ export interface CodeBlockOptions {
|
|
|
565
614
|
/** Text of the code block, as overrides of the English defaults. A function is called on every render. */
|
|
566
615
|
labels?: LabelsOption<CodeBlockLabels>;
|
|
567
616
|
}
|
|
568
|
-
export type { CodeBlockInput, CodeBlockLabels, CodeBlockSnapshot, CodeFrame, CodeSource, DiagramEngine, DiagramError, DiagramLabels, DiagramRequest, DiagramState, DiagramView, ImageActionIconName, ImageGallery, ImageGalleryItem, ImageGeometry, ImageIconName, ImageLabels, ImageLoadStatus, ImagePointer, ImagePreviewHost, ImagePreviewOptions, ImagePreviewPhase, ImagePreviewState, ImageTransform, LabelsOption, MermaidInitTarget, TableExportReason, TableLabels, TableProjection };
|
|
617
|
+
export type { CodeBlockInput, CodeBlockLabels, CodeBlockSnapshot, CodeFrame, CodeSource, DiagramEngine, DiagramError, DiagramLabels, DiagramRequest, DiagramState, DiagramView, ImageActionIconName, ImageGallery, ImageGalleryItem, ImageGeometry, ImageIconName, ImageLabels, ImageLoadStatus, ImagePointer, ImagePreviewAction, ImagePreviewHost, ImagePreviewOptions, ImagePreviewPhase, ImagePreviewState, ImageTransform, LabelsOption, MermaidInitTarget, TableExportReason, TableLabels, TableProjection };
|
package/dist/components/index.js
CHANGED
|
@@ -694,9 +694,14 @@ function imageTransformStyle(transform) {
|
|
|
694
694
|
const { x, y, scale, rotate, flipX, flipY } = transform;
|
|
695
695
|
return `translate3d(${x}px, ${y}px, 0) scale3d(${flipX ? "-" : ""}${scale}, ${flipY ? "-" : ""}${scale}, 1) rotate(${rotate}deg)`;
|
|
696
696
|
}
|
|
697
|
-
|
|
697
|
+
const DEFAULT_SCALE_LIMITS = {
|
|
698
|
+
min: 1,
|
|
699
|
+
max: 50
|
|
700
|
+
};
|
|
701
|
+
function zoomImage(transform, ratio, geometry, centerX = geometry.viewportWidth / 2, centerY = geometry.viewportHeight / 2, touch = false, limits = DEFAULT_SCALE_LIMITS) {
|
|
698
702
|
if (!Number.isFinite(ratio) || ratio <= 0) return transform;
|
|
699
|
-
const
|
|
703
|
+
const floor = touch ? .01 : limits.min;
|
|
704
|
+
const scale = Math.min(limits.max, Math.max(floor, transform.scale * ratio));
|
|
700
705
|
const difference = scale / transform.scale - 1;
|
|
701
706
|
let x = transform.x - difference * (centerX - transform.x - geometry.left - geometry.width / 2);
|
|
702
707
|
let y = transform.y - difference * (centerY - transform.y - geometry.top - geometry.height / 2);
|
|
@@ -708,19 +713,19 @@ function zoomImage(transform, ratio, geometry, centerX = geometry.viewportWidth
|
|
|
708
713
|
scale
|
|
709
714
|
};
|
|
710
715
|
}
|
|
711
|
-
function imageWheelRatio(delta, mode = 0, pinch = false) {
|
|
716
|
+
function imageWheelRatio(delta, mode = 0, pinch = false, step = .5) {
|
|
712
717
|
if (!Number.isFinite(delta) || delta === 0) return 1;
|
|
713
|
-
if (pinch) return Math.min(1
|
|
718
|
+
if (pinch) return Math.min(1 + step, Math.max(1 / (1 + step), Math.exp(-delta / 100)));
|
|
714
719
|
const pixels = mode === 1 ? delta * 100 / 3 : mode === 2 ? delta * 100 : delta;
|
|
715
|
-
const ratio = 1 + Math.min(Math.abs(pixels / 100), 1) *
|
|
720
|
+
const ratio = 1 + Math.min(Math.abs(pixels / 100), 1) * step;
|
|
716
721
|
return pixels > 0 ? 1 / ratio : ratio;
|
|
717
722
|
}
|
|
718
|
-
function reboundImage(transform, geometry, bounds) {
|
|
719
|
-
if (transform.scale <
|
|
723
|
+
function reboundImage(transform, geometry, bounds, minScale = 1) {
|
|
724
|
+
if (transform.scale < minScale) return {
|
|
720
725
|
...transform,
|
|
721
726
|
x: 0,
|
|
722
727
|
y: 0,
|
|
723
|
-
scale:
|
|
728
|
+
scale: minScale
|
|
724
729
|
};
|
|
725
730
|
const rotated = transform.rotate % 180 !== 0;
|
|
726
731
|
const width = (rotated ? geometry.height : geometry.width) * transform.scale;
|
|
@@ -752,9 +757,8 @@ function imagePinchCenter(oldA, oldB, a, b) {
|
|
|
752
757
|
y: oldA.y + ratio * (oldB.y - oldA.y)
|
|
753
758
|
};
|
|
754
759
|
}
|
|
755
|
-
const ZOOM_STEP = 1.5;
|
|
756
|
-
const MAX_SCALE = 50;
|
|
757
760
|
const CLOSE_MS = 300;
|
|
761
|
+
const positive = (value, fallback) => typeof value === "number" && Number.isFinite(value) && value > 0 ? value : fallback;
|
|
758
762
|
const closedState = Object.freeze({
|
|
759
763
|
phase: "closed",
|
|
760
764
|
items: Object.freeze([]),
|
|
@@ -763,19 +767,34 @@ const closedState = Object.freeze({
|
|
|
763
767
|
transform: initialImageTransform(),
|
|
764
768
|
status: "loading",
|
|
765
769
|
moving: false,
|
|
770
|
+
movable: true,
|
|
771
|
+
origin: void 0,
|
|
766
772
|
canPrevious: false,
|
|
767
773
|
canNext: false,
|
|
768
774
|
canZoomIn: false,
|
|
769
775
|
canZoomOut: false
|
|
770
776
|
});
|
|
771
777
|
function createImagePreviewController(host, publish, options = {}) {
|
|
778
|
+
const limits = {
|
|
779
|
+
min: positive(options.minScale, 1),
|
|
780
|
+
max: 0
|
|
781
|
+
};
|
|
782
|
+
limits.max = Math.max(limits.min, positive(options.maxScale, 50));
|
|
783
|
+
const baseScale = Math.min(limits.max, Math.max(limits.min, 1));
|
|
784
|
+
const scaleStep = positive(options.scaleStep, .5);
|
|
785
|
+
const movable = options.movable ?? true;
|
|
786
|
+
const wheelZoom = options.wheel ?? true;
|
|
772
787
|
let phase = "closed";
|
|
773
788
|
let items = [];
|
|
774
789
|
let selected;
|
|
775
790
|
let current = -1;
|
|
776
|
-
let transform =
|
|
791
|
+
let transform = {
|
|
792
|
+
...initialImageTransform(),
|
|
793
|
+
scale: baseScale
|
|
794
|
+
};
|
|
777
795
|
let status = "loading";
|
|
778
796
|
let moving = false;
|
|
797
|
+
let origin;
|
|
779
798
|
let unsubscribe;
|
|
780
799
|
let cancelPublish;
|
|
781
800
|
let cancelOpening;
|
|
@@ -794,23 +813,40 @@ function createImagePreviewController(host, publish, options = {}) {
|
|
|
794
813
|
transform,
|
|
795
814
|
status,
|
|
796
815
|
moving,
|
|
816
|
+
movable,
|
|
817
|
+
origin,
|
|
797
818
|
canPrevious: current > 0,
|
|
798
819
|
canNext: current < items.length - 1,
|
|
799
|
-
canZoomIn: ready && transform.scale <
|
|
800
|
-
canZoomOut: ready && transform.scale >
|
|
820
|
+
canZoomIn: ready && transform.scale < limits.max,
|
|
821
|
+
canZoomOut: ready && transform.scale > limits.min
|
|
801
822
|
};
|
|
802
823
|
};
|
|
824
|
+
let reported;
|
|
825
|
+
const flush = () => {
|
|
826
|
+
publish(snapshot());
|
|
827
|
+
const action = reported;
|
|
828
|
+
reported = void 0;
|
|
829
|
+
if (action) options.onTransform?.({
|
|
830
|
+
transform,
|
|
831
|
+
action
|
|
832
|
+
});
|
|
833
|
+
};
|
|
803
834
|
const emit = () => {
|
|
804
835
|
cancelPublish?.();
|
|
805
836
|
cancelPublish = void 0;
|
|
806
|
-
|
|
837
|
+
flush();
|
|
807
838
|
};
|
|
808
839
|
const emitNextFrame = () => {
|
|
809
840
|
cancelPublish ??= host.frame(() => {
|
|
810
841
|
cancelPublish = void 0;
|
|
811
|
-
|
|
842
|
+
flush();
|
|
812
843
|
});
|
|
813
844
|
};
|
|
845
|
+
const apply = (next, action) => {
|
|
846
|
+
if (next.x === transform.x && next.y === transform.y && next.scale === transform.scale && next.rotate === transform.rotate && next.flipX === transform.flipX && next.flipY === transform.flipY) return;
|
|
847
|
+
transform = next;
|
|
848
|
+
reported = action;
|
|
849
|
+
};
|
|
814
850
|
const endGesture = () => {
|
|
815
851
|
pointers.clear();
|
|
816
852
|
grip = void 0;
|
|
@@ -818,22 +854,26 @@ function createImagePreviewController(host, publish, options = {}) {
|
|
|
818
854
|
moving = false;
|
|
819
855
|
};
|
|
820
856
|
const startImage = () => {
|
|
821
|
-
transform =
|
|
857
|
+
transform = {
|
|
858
|
+
...initialImageTransform(),
|
|
859
|
+
scale: baseScale
|
|
860
|
+
};
|
|
861
|
+
reported = void 0;
|
|
822
862
|
status = "loading";
|
|
823
863
|
endGesture();
|
|
824
864
|
};
|
|
825
|
-
const zoom = (ratio, x, y, touch = false) => {
|
|
865
|
+
const zoom = (action, ratio, x, y, touch = false) => {
|
|
826
866
|
const box = host.geometry();
|
|
827
|
-
if (box && status === "ready")
|
|
867
|
+
if (box && status === "ready") apply(zoomImage(transform, ratio, box, x, y, touch, limits), action);
|
|
828
868
|
};
|
|
829
869
|
const rebound = () => {
|
|
830
|
-
if (transform.scale <
|
|
831
|
-
|
|
870
|
+
if (transform.scale < limits.min) {
|
|
871
|
+
apply({
|
|
832
872
|
...transform,
|
|
833
873
|
x: 0,
|
|
834
874
|
y: 0,
|
|
835
|
-
scale:
|
|
836
|
-
};
|
|
875
|
+
scale: limits.min
|
|
876
|
+
}, "rebound");
|
|
837
877
|
return;
|
|
838
878
|
}
|
|
839
879
|
const box = host.geometry();
|
|
@@ -841,18 +881,28 @@ function createImagePreviewController(host, publish, options = {}) {
|
|
|
841
881
|
const turned = transform.rotate % 180 !== 0;
|
|
842
882
|
const width = (turned ? box.height : box.width) * transform.scale;
|
|
843
883
|
const height = (turned ? box.width : box.height) * transform.scale;
|
|
844
|
-
|
|
884
|
+
apply(reboundImage(transform, box, {
|
|
845
885
|
left: box.left + box.width / 2 + transform.x - width / 2,
|
|
846
886
|
top: box.top + box.height / 2 + transform.y - height / 2
|
|
847
|
-
});
|
|
887
|
+
}, limits.min), "rebound");
|
|
888
|
+
};
|
|
889
|
+
const anchorOf = (id) => {
|
|
890
|
+
const point = host.anchor?.(id);
|
|
891
|
+
return point && Number.isFinite(point.x) && Number.isFinite(point.y) ? {
|
|
892
|
+
x: point.x,
|
|
893
|
+
y: point.y
|
|
894
|
+
} : void 0;
|
|
848
895
|
};
|
|
849
896
|
const finishClosing = () => {
|
|
850
897
|
closeTimer = void 0;
|
|
851
898
|
phase = "closed";
|
|
852
899
|
items = [];
|
|
853
900
|
selected = void 0;
|
|
901
|
+
origin = void 0;
|
|
854
902
|
current = -1;
|
|
903
|
+
reported = void 0;
|
|
855
904
|
emit();
|
|
905
|
+
options.afterOpenChange?.(false);
|
|
856
906
|
};
|
|
857
907
|
const close = () => {
|
|
858
908
|
if (phase === "closed" || phase === "closing") return;
|
|
@@ -861,20 +911,36 @@ function createImagePreviewController(host, publish, options = {}) {
|
|
|
861
911
|
unsubscribe?.();
|
|
862
912
|
unsubscribe = void 0;
|
|
863
913
|
endGesture();
|
|
914
|
+
reported = void 0;
|
|
915
|
+
origin = selected ? anchorOf(selected) : void 0;
|
|
864
916
|
phase = "closing";
|
|
917
|
+
const info = {
|
|
918
|
+
current,
|
|
919
|
+
item: items[current]
|
|
920
|
+
};
|
|
865
921
|
const duration = typeof options.closeDuration === "function" ? options.closeDuration() : options.closeDuration ?? CLOSE_MS;
|
|
866
922
|
if (duration > 0) {
|
|
867
923
|
emit();
|
|
868
924
|
closeTimer = setTimeout(finishClosing, duration);
|
|
869
|
-
|
|
925
|
+
options.onOpenChange?.(false, info);
|
|
926
|
+
} else try {
|
|
927
|
+
options.onOpenChange?.(false, info);
|
|
928
|
+
} finally {
|
|
929
|
+
if (phase === "closing") finishClosing();
|
|
930
|
+
}
|
|
870
931
|
};
|
|
871
932
|
const go = (delta) => {
|
|
872
933
|
const target = current + delta;
|
|
873
934
|
if (phase === "closed" || phase === "closing" || target < 0 || target >= items.length || target === current) return;
|
|
935
|
+
const previous = current;
|
|
936
|
+
const { x, y, scale, rotate, flipX, flipY } = transform;
|
|
937
|
+
const transformed = x !== 0 || y !== 0 || scale !== baseScale || rotate !== 0 || flipX || flipY;
|
|
874
938
|
current = target;
|
|
875
939
|
selected = items[target].id;
|
|
876
940
|
startImage();
|
|
941
|
+
if (transformed) reported = delta < 0 ? "prev" : "next";
|
|
877
942
|
emit();
|
|
943
|
+
options.onChange?.(current, previous);
|
|
878
944
|
};
|
|
879
945
|
const follow = (gallery) => {
|
|
880
946
|
const next = gallery.items();
|
|
@@ -898,6 +964,7 @@ function createImagePreviewController(host, publish, options = {}) {
|
|
|
898
964
|
items = list;
|
|
899
965
|
current = index;
|
|
900
966
|
selected = id;
|
|
967
|
+
origin = anchorOf(id);
|
|
901
968
|
startImage();
|
|
902
969
|
unsubscribe = gallery.subscribe(() => follow(gallery));
|
|
903
970
|
if (phase === "open") {
|
|
@@ -905,15 +972,26 @@ function createImagePreviewController(host, publish, options = {}) {
|
|
|
905
972
|
return true;
|
|
906
973
|
}
|
|
907
974
|
cancelOpening = void 0;
|
|
975
|
+
const starting = phase !== "opening";
|
|
908
976
|
phase = "opening";
|
|
909
977
|
emit();
|
|
910
978
|
cancelOpening = host.frame(() => {
|
|
979
|
+
const measured = selected ? anchorOf(selected) : void 0;
|
|
980
|
+
if (measured?.x !== origin?.x || measured?.y !== origin?.y) {
|
|
981
|
+
origin = measured;
|
|
982
|
+
emit();
|
|
983
|
+
}
|
|
911
984
|
cancelOpening = host.frame(() => {
|
|
912
985
|
cancelOpening = void 0;
|
|
913
986
|
phase = "open";
|
|
914
987
|
emit();
|
|
988
|
+
options.afterOpenChange?.(true);
|
|
915
989
|
});
|
|
916
990
|
});
|
|
991
|
+
if (starting) options.onOpenChange?.(true, {
|
|
992
|
+
current,
|
|
993
|
+
item: items[current]
|
|
994
|
+
});
|
|
917
995
|
return true;
|
|
918
996
|
},
|
|
919
997
|
close,
|
|
@@ -924,24 +1002,24 @@ function createImagePreviewController(host, publish, options = {}) {
|
|
|
924
1002
|
if (name === "prev") return go(-1);
|
|
925
1003
|
if (name === "next") return go(1);
|
|
926
1004
|
if (status !== "ready") return;
|
|
927
|
-
if (name === "zoomIn") zoom(
|
|
928
|
-
else if (name === "zoomOut") zoom(1 /
|
|
929
|
-
else if (name === "rotateLeft")
|
|
1005
|
+
if (name === "zoomIn") zoom(name, 1 + scaleStep);
|
|
1006
|
+
else if (name === "zoomOut") zoom(name, 1 / (1 + scaleStep));
|
|
1007
|
+
else if (name === "rotateLeft") apply({
|
|
930
1008
|
...transform,
|
|
931
1009
|
rotate: transform.rotate - 90
|
|
932
|
-
};
|
|
933
|
-
else if (name === "rotateRight")
|
|
1010
|
+
}, name);
|
|
1011
|
+
else if (name === "rotateRight") apply({
|
|
934
1012
|
...transform,
|
|
935
1013
|
rotate: transform.rotate + 90
|
|
936
|
-
};
|
|
937
|
-
else if (name === "flipX")
|
|
1014
|
+
}, name);
|
|
1015
|
+
else if (name === "flipX") apply({
|
|
938
1016
|
...transform,
|
|
939
1017
|
flipX: !transform.flipX
|
|
940
|
-
};
|
|
941
|
-
else if (name === "flipY")
|
|
1018
|
+
}, name);
|
|
1019
|
+
else if (name === "flipY") apply({
|
|
942
1020
|
...transform,
|
|
943
1021
|
flipY: !transform.flipY
|
|
944
|
-
};
|
|
1022
|
+
}, name);
|
|
945
1023
|
emit();
|
|
946
1024
|
},
|
|
947
1025
|
loaded() {
|
|
@@ -956,7 +1034,7 @@ function createImagePreviewController(host, publish, options = {}) {
|
|
|
956
1034
|
emit();
|
|
957
1035
|
},
|
|
958
1036
|
pointerDown(pointer) {
|
|
959
|
-
if (phase !== "open" && phase !== "opening" || status !== "ready") return false;
|
|
1037
|
+
if (!movable || phase !== "open" && phase !== "opening" || status !== "ready") return false;
|
|
960
1038
|
if (pointer.button !== void 0 && pointer.button !== 0) return false;
|
|
961
1039
|
if (pointers.size >= 2 && !pointers.has(pointer.id)) return false;
|
|
962
1040
|
pointers.set(pointer.id, {
|
|
@@ -983,12 +1061,12 @@ function createImagePreviewController(host, publish, options = {}) {
|
|
|
983
1061
|
const [a, b] = [...pointers.values()];
|
|
984
1062
|
const span = Math.hypot(before[0].x - before[1].x, before[0].y - before[1].y);
|
|
985
1063
|
const center = imagePinchCenter(before[0], before[1], a, b);
|
|
986
|
-
if (span > 0) zoom(Math.hypot(a.x - b.x, a.y - b.y) / span, center.x, center.y, true);
|
|
987
|
-
} else if (grip)
|
|
1064
|
+
if (span > 0) zoom("pinch", Math.hypot(a.x - b.x, a.y - b.y) / span, center.x, center.y, true);
|
|
1065
|
+
} else if (grip) apply({
|
|
988
1066
|
...transform,
|
|
989
1067
|
x: pointer.x - grip.x,
|
|
990
1068
|
y: pointer.y - grip.y
|
|
991
|
-
};
|
|
1069
|
+
}, "move");
|
|
992
1070
|
displaced = true;
|
|
993
1071
|
emitNextFrame();
|
|
994
1072
|
},
|
|
@@ -1008,20 +1086,20 @@ function createImagePreviewController(host, publish, options = {}) {
|
|
|
1008
1086
|
emit();
|
|
1009
1087
|
},
|
|
1010
1088
|
wheel(input) {
|
|
1011
|
-
if (phase !== "open" || status !== "ready" || !input.deltaY) return false;
|
|
1012
|
-
zoom(imageWheelRatio(input.deltaY, input.mode, input.pinch), input.x, input.y);
|
|
1089
|
+
if (!wheelZoom || phase !== "open" || status !== "ready" || !input.deltaY) return false;
|
|
1090
|
+
zoom("wheel", imageWheelRatio(input.deltaY, input.mode, input.pinch, scaleStep), input.x, input.y);
|
|
1013
1091
|
emitNextFrame();
|
|
1014
1092
|
return true;
|
|
1015
1093
|
},
|
|
1016
1094
|
doubleClick(x, y) {
|
|
1017
1095
|
if (phase !== "open" || status !== "ready") return;
|
|
1018
|
-
if (transform.scale !==
|
|
1096
|
+
if (transform.scale !== baseScale) apply({
|
|
1019
1097
|
...transform,
|
|
1020
1098
|
x: 0,
|
|
1021
1099
|
y: 0,
|
|
1022
|
-
scale:
|
|
1023
|
-
};
|
|
1024
|
-
else zoom(
|
|
1100
|
+
scale: baseScale
|
|
1101
|
+
}, "doubleClick");
|
|
1102
|
+
else zoom("doubleClick", 1 + scaleStep, x, y);
|
|
1025
1103
|
emit();
|
|
1026
1104
|
},
|
|
1027
1105
|
key(key) {
|
|
@@ -1041,7 +1119,9 @@ function createImagePreviewController(host, publish, options = {}) {
|
|
|
1041
1119
|
phase = "closed";
|
|
1042
1120
|
items = [];
|
|
1043
1121
|
selected = void 0;
|
|
1122
|
+
origin = void 0;
|
|
1044
1123
|
current = -1;
|
|
1124
|
+
reported = void 0;
|
|
1045
1125
|
}
|
|
1046
1126
|
};
|
|
1047
1127
|
}
|