@lazycatcloud/vue-media-preview 0.0.0-stage → 0.1.0-preview.34
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.
- package/LICENSE +21 -0
- package/README.md +107 -2
- package/dist/components/MediaPreview.vue.d.ts +171 -0
- package/dist/components/PreviewStage.vue.d.ts +147 -0
- package/dist/components/VirtualTimeline.vue.d.ts +42 -0
- package/dist/components/video/VideoControls.vue.d.ts +21 -0
- package/dist/components/video/VideoIcon.vue.d.ts +14 -0
- package/dist/core/errors.d.ts +1 -0
- package/dist/core/gestures/edgePaging.d.ts +5 -0
- package/dist/core/gestures/pointerGesture.d.ts +5 -0
- package/dist/core/gestures/pressHold.d.ts +5 -0
- package/dist/core/gestures/wheelZoom.d.ts +2 -0
- package/dist/core/math.d.ts +11 -0
- package/dist/core/resources/imageLimits.d.ts +11 -0
- package/dist/core/resources/imagePolicy.d.ts +14 -0
- package/dist/core/resources/imageRequest.d.ts +15 -0
- package/dist/core/resources/imageStore.d.ts +30 -0
- package/dist/core/resources/imageTransport.d.ts +9 -0
- package/dist/core/resources/initialImage.d.ts +11 -0
- package/dist/core/resources/usePreviewResources.d.ts +13 -0
- package/dist/core/timeline/layout.d.ts +28 -0
- package/dist/core/transition/anchor.d.ts +12 -0
- package/dist/core/transition/geometry.d.ts +27 -0
- package/dist/core/transition/rect.d.ts +2 -0
- package/dist/core/transition/sharedTransition.d.ts +12 -0
- package/dist/core/transition/sourceViewport.d.ts +3 -0
- package/dist/core/types.d.ts +69 -0
- package/dist/core/usePreviewPager.d.ts +26 -0
- package/dist/core/usePreviewViewport.d.ts +29 -0
- package/dist/core/video/captureVideoFrame.d.ts +3 -0
- package/dist/core/video/useVideoPlayback.d.ts +46 -0
- package/dist/core/video/useVideoSource.d.ts +5 -0
- package/dist/index.d.ts +17 -0
- package/dist/renderers/ImageCanvasRenderer.vue.d.ts +71 -0
- package/dist/renderers/LivePhotoRenderer.vue.d.ts +94 -0
- package/dist/renderers/VideoDomRenderer.vue.d.ts +166 -0
- package/dist/vue-media-preview.cjs +1 -0
- package/dist/vue-media-preview.css +1 -0
- package/dist/vue-media-preview.js +2418 -0
- package/docs/testing.md +140 -0
- package/docs/ui-alignment.md +44 -0
- package/docs/vue-media-preview.md +191 -0
- package/package.json +68 -4
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 LazycatCloud
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,3 +1,108 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Vue Media Preview
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
面向懒猫相册的 Vue 3 媒体预览组件库。当前测试版包含日期时间线 Demo,以及卡片展开、Canvas 图片预览、跟手翻页、缩放平移和收回卡片的完整链路。
|
|
4
|
+
|
|
5
|
+
## 直接体验
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
pnpm install
|
|
9
|
+
pnpm dev
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
- 移动端效果:<http://localhost:2391/?view=mobile>
|
|
13
|
+
- 万张图库场景:<http://localhost:2391/?view=mobile&count=10000>,在“我的”中定位第 5000 张。
|
|
14
|
+
- 桌面端效果:<http://localhost:2391/?view=desktop>
|
|
15
|
+
- 默认入口根据屏幕宽度和 UA 选择界面。
|
|
16
|
+
- 手机连接同一局域网后,使用启动输出中的 Network 地址。
|
|
17
|
+
- 点击“添加”可用自己的照片或视频测试;文件只通过浏览器 Blob URL 使用,不上传服务端,刷新后清除。视频自动提取首帧作为卡片封面。
|
|
18
|
+
|
|
19
|
+
Demo 内置 48 个日期分组条目,复用 16 份图片、视频和实况素材。所有演示资源已放在 `demo/public/media/`,打开时不依赖外网图片服务。
|
|
20
|
+
|
|
21
|
+
## 已包含的交互
|
|
22
|
+
|
|
23
|
+
- **容器展开 / 共享元素转场**:图片从卡片的位置、裁切和圆角连续展开到完整预览;关闭时收回当前图片对应的卡片。
|
|
24
|
+
- **Canvas 图片**:当前画面优先,再预取邻页;下载可取消并有并发、流量和像素保护,原图状态以真实解码结果为准。
|
|
25
|
+
- **三页翻页轨道**:当前项及相邻两项,拖动跟手,松手根据距离和速度翻页或回弹,首尾有阻尼。
|
|
26
|
+
- **海量列表**:日期分组虚拟时间线、分页事件、按 ID 定位收回;列表追加/重排保留当前媒体,删除当前项切到邻项。
|
|
27
|
+
- **手势**:单击工具栏、双击缩放、双指缩放、放大后平移、越过水平边缘切页并同步缩回 1 倍、适配比例下拉关闭;图片和内联视频均支持缩放。
|
|
28
|
+
- **桌面操作**:左右方向键、Escape、`+` / `-` / `0`;Ctrl / Command + 滚轮缩放,放大后普通滚轮平移。
|
|
29
|
+
- **媒体**:图片 Canvas;视频使用原生 video 与自定义相册控制层,包含居中播放、播放/暂停、时间与缓冲进度、拖动定位、重播、声音开关和全屏;实况 Canvas 封面与视频切换。离开当前项暂停视频,退出释放组件资源。
|
|
30
|
+
- **外壳**:移动端与桌面 Demo、工具栏插槽、收藏状态、详情、图片导入、失败重试、预览键盘操作和减少动态效果设置。
|
|
31
|
+
|
|
32
|
+
## 验证与构建
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
pnpm format:check
|
|
36
|
+
pnpm test
|
|
37
|
+
pnpm type-check
|
|
38
|
+
pnpm build
|
|
39
|
+
pnpm preview
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
`pnpm preview` 在 2392 端口运行 `demo/dist` 的生产构建。
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
pnpm pack --pack-destination .delivery
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
生成的组件包包含 ESM、CommonJS、类型声明和 CSS。相册可通过本地 tgz 安装。
|
|
49
|
+
|
|
50
|
+
## 接入
|
|
51
|
+
|
|
52
|
+
安装当前预览版:
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
pnpm add @lazycatcloud/vue-media-preview@next vue
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
```ts
|
|
59
|
+
import { MediaPreview } from '@lazycatcloud/vue-media-preview'
|
|
60
|
+
import '@lazycatcloud/vue-media-preview/style.css'
|
|
61
|
+
import type { PreviewMedia, PreviewAnchor } from '@lazycatcloud/vue-media-preview'
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
`MediaPreview` 负责完整预览会话,`PreviewStage` 提供单媒体缩放、平移、旋转能力。转场定位、业务动作和资源地址由接入方提供。
|
|
65
|
+
|
|
66
|
+
详见 [接入与架构](docs/vue-media-preview.md) 和 [测试说明](docs/testing.md)。
|
|
67
|
+
|
|
68
|
+
大原图通过独立适屏资源预览;默认不直接解码超过 32MiB 或 2400 万像素的原图,未实现瓦片式超大图。真实相册业务与特殊格式边界见接入文档。
|
|
69
|
+
|
|
70
|
+
## npm 发布
|
|
71
|
+
|
|
72
|
+
沿用 `vue-router-stack` 的 Makefile 发布入口,默认发布到 npm 官方源。先安装依赖并检查发布内容:
|
|
73
|
+
|
|
74
|
+
```bash
|
|
75
|
+
pnpm install --frozen-lockfile
|
|
76
|
+
make npm-publish-dry-run
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
预演会执行类型检查、测试、库与 Demo 构建,并显示包内容,不上传包、不修改版本。
|
|
80
|
+
发布包包含 `dist/`、`docs/`、README、MIT LICENSE 和包元数据。
|
|
81
|
+
|
|
82
|
+
登录有 `@lazycatcloud` 发布权限的 npm 账号后发布当前版本:
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
npm login --registry https://registry.npmjs.org/
|
|
86
|
+
make npm-publish
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
当前 `0.1.0-preview.*` 版本默认使用 `next` 标签;Makefile 对正式版本默认使用 `latest`。
|
|
90
|
+
直接运行 `npm publish` 也会先检查、测试和构建,包配置默认标签为 `next`,正式发布时需显式指定 `--tag latest`。
|
|
91
|
+
|
|
92
|
+
后续递增预览版本并发布:
|
|
93
|
+
|
|
94
|
+
```bash
|
|
95
|
+
make npm-release-preview
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
首次转为正式版可执行 `make npm-release VERSION=0.1.0 NPM_TAG=latest`;
|
|
99
|
+
后续正式版本使用 `make npm-release-patch`、`make npm-release-minor` 或 `make npm-release-major`。
|
|
100
|
+
版本更新默认不创建 Git 提交或标签;发布成功后手动提交版本变更。
|
|
101
|
+
需要验证码时附加 `NPM_OTP=123456`,可通过 `NPM_REGISTRY`、`NPM_ACCESS`、`NPM_TAG` 覆盖发布目标。
|
|
102
|
+
这些参数同样适用于预演命令;账号凭据通过 npm 登录管理,不写入仓库。
|
|
103
|
+
|
|
104
|
+
## 代码约定
|
|
105
|
+
|
|
106
|
+
TypeScript、Vue 模板、CSS 和测试统一采用 2 空格缩进、双引号和无分号风格,由 `.prettierrc.json` 与 `.editorconfig` 固定。运行 `pnpm format` 整理格式,`pnpm format:check` 检查;生成产物、交付包和复制的图标/媒体资源不参与格式化。
|
|
107
|
+
|
|
108
|
+
资源模块位于 `src/core/resources/`:`imageLimits.ts` 集中固定预算,`imagePolicy.ts` 定义可配置策略和清晰度协议,`imageRequest.ts` 生成请求计划,`imageStore.ts` 管理队列和缓存,`usePreviewResources.ts` 管理当前页原图状态。渲染组件负责资源生命周期与绘制;预览会话保留转场、手势与界面编排。多语句模板事件使用具名处理函数,避免无分号格式下产生解析歧义。
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
import type { VideoSourceLoader } from "../core/video/useVideoSource";
|
|
2
|
+
import type { ImagePolicy, ImageSourceResolver, OriginalStatus } from "../core/resources/imagePolicy";
|
|
3
|
+
import type { LivePhotoStatus, PreviewAnchor, PreviewMedia, PreviewPhase } from "../core/types";
|
|
4
|
+
type __VLS_Props = {
|
|
5
|
+
items: PreviewMedia[];
|
|
6
|
+
mobile?: boolean;
|
|
7
|
+
teleportDisabled?: boolean;
|
|
8
|
+
keyboardEnabled?: boolean;
|
|
9
|
+
gesturesEnabled?: boolean;
|
|
10
|
+
persistentChrome?: boolean;
|
|
11
|
+
videoLoader?: VideoSourceLoader;
|
|
12
|
+
resourcePolicy?: ImagePolicy;
|
|
13
|
+
resolveImageSource?: ImageSourceResolver;
|
|
14
|
+
hasMore?: boolean;
|
|
15
|
+
appearance?: "dark" | "album";
|
|
16
|
+
closeDuration?: number;
|
|
17
|
+
transitionDuration?: number;
|
|
18
|
+
resolveAnchor?: (media: PreviewMedia) => PreviewAnchor | Promise<PreviewAnchor>;
|
|
19
|
+
};
|
|
20
|
+
/** Synchronize a host-owned window or jump directly from its filmstrip. */
|
|
21
|
+
declare function goTo(index: number): void;
|
|
22
|
+
declare function open(index?: number): Promise<void>;
|
|
23
|
+
declare function close(): Promise<void>;
|
|
24
|
+
declare function toggleFullscreen(): Promise<void>;
|
|
25
|
+
declare var __VLS_24: {
|
|
26
|
+
media: PreviewMedia;
|
|
27
|
+
index: number;
|
|
28
|
+
total: number;
|
|
29
|
+
scale: number;
|
|
30
|
+
controls: {
|
|
31
|
+
close: typeof close;
|
|
32
|
+
setChromeVisible: (visible: boolean) => void;
|
|
33
|
+
goTo: typeof goTo;
|
|
34
|
+
previous: () => void;
|
|
35
|
+
next: () => void;
|
|
36
|
+
rotate: (delta?: number) => void;
|
|
37
|
+
reset: () => void;
|
|
38
|
+
zoomIn: () => void;
|
|
39
|
+
zoomOut: () => void;
|
|
40
|
+
original: () => void;
|
|
41
|
+
fullscreen: typeof toggleFullscreen;
|
|
42
|
+
togglePlayback: () => void;
|
|
43
|
+
toggleLive: () => void;
|
|
44
|
+
toggleDetail: () => void;
|
|
45
|
+
};
|
|
46
|
+
originalStatus: OriginalStatus;
|
|
47
|
+
originalReason: string;
|
|
48
|
+
livePlaying: boolean;
|
|
49
|
+
liveStatus: LivePhotoStatus;
|
|
50
|
+
};
|
|
51
|
+
type __VLS_Slots = {} & {
|
|
52
|
+
toolbar?: (props: typeof __VLS_24) => any;
|
|
53
|
+
};
|
|
54
|
+
declare const __VLS_base: import("vue").DefineComponent<__VLS_WithDefaults<__VLS_TypePropsToOption<__VLS_Props>, {
|
|
55
|
+
mobile: boolean;
|
|
56
|
+
teleportDisabled: boolean;
|
|
57
|
+
keyboardEnabled: boolean;
|
|
58
|
+
gesturesEnabled: boolean;
|
|
59
|
+
persistentChrome: boolean;
|
|
60
|
+
videoLoader: VideoSourceLoader;
|
|
61
|
+
resourcePolicy: () => ImagePolicy;
|
|
62
|
+
resolveImageSource: ImageSourceResolver;
|
|
63
|
+
hasMore: boolean;
|
|
64
|
+
appearance: string;
|
|
65
|
+
closeDuration: number;
|
|
66
|
+
transitionDuration: number;
|
|
67
|
+
resolveAnchor: () => {
|
|
68
|
+
kind: "unavailable";
|
|
69
|
+
};
|
|
70
|
+
}>, {
|
|
71
|
+
currentIndex: import("vue").Ref<number>;
|
|
72
|
+
phase: import("vue").Ref<PreviewPhase>;
|
|
73
|
+
element: import("vue").Ref<HTMLElement | undefined>;
|
|
74
|
+
mediaElement: () => HTMLImageElement | HTMLVideoElement | undefined;
|
|
75
|
+
canvasElement: () => HTMLCanvasElement;
|
|
76
|
+
close: typeof close;
|
|
77
|
+
setChromeVisible: (visible: boolean) => void;
|
|
78
|
+
goTo: typeof goTo;
|
|
79
|
+
previous: () => void;
|
|
80
|
+
next: () => void;
|
|
81
|
+
rotate: (delta?: number) => void;
|
|
82
|
+
reset: () => void;
|
|
83
|
+
zoomIn: () => void;
|
|
84
|
+
zoomOut: () => void;
|
|
85
|
+
original: () => void;
|
|
86
|
+
fullscreen: typeof toggleFullscreen;
|
|
87
|
+
togglePlayback: () => void;
|
|
88
|
+
toggleLive: () => void;
|
|
89
|
+
toggleDetail: () => void;
|
|
90
|
+
open: typeof open;
|
|
91
|
+
}, unknown, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
92
|
+
error: (error: Error, media: PreviewMedia) => void;
|
|
93
|
+
open: (index: number) => void;
|
|
94
|
+
closing: () => void;
|
|
95
|
+
change: (index: number) => void;
|
|
96
|
+
close: () => void;
|
|
97
|
+
ready: (index: number, quality: "thumbnail" | "screen" | "full") => void;
|
|
98
|
+
originalState: (media: PreviewMedia, status: OriginalStatus, reason: string) => void;
|
|
99
|
+
opened: (index: number) => void;
|
|
100
|
+
loadMore: (index: number) => void;
|
|
101
|
+
phaseChange: (phase: PreviewPhase) => void;
|
|
102
|
+
chromeChange: (visible: boolean) => void;
|
|
103
|
+
}, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<__VLS_WithDefaults<__VLS_TypePropsToOption<__VLS_Props>, {
|
|
104
|
+
mobile: boolean;
|
|
105
|
+
teleportDisabled: boolean;
|
|
106
|
+
keyboardEnabled: boolean;
|
|
107
|
+
gesturesEnabled: boolean;
|
|
108
|
+
persistentChrome: boolean;
|
|
109
|
+
videoLoader: VideoSourceLoader;
|
|
110
|
+
resourcePolicy: () => ImagePolicy;
|
|
111
|
+
resolveImageSource: ImageSourceResolver;
|
|
112
|
+
hasMore: boolean;
|
|
113
|
+
appearance: string;
|
|
114
|
+
closeDuration: number;
|
|
115
|
+
transitionDuration: number;
|
|
116
|
+
resolveAnchor: () => {
|
|
117
|
+
kind: "unavailable";
|
|
118
|
+
};
|
|
119
|
+
}>>> & {
|
|
120
|
+
onError?: ((error: Error, media: PreviewMedia) => any) | undefined;
|
|
121
|
+
onReady?: ((index: number, quality: "thumbnail" | "screen" | "full") => any) | undefined;
|
|
122
|
+
onOriginalState?: ((media: PreviewMedia, status: OriginalStatus, reason: string) => any) | undefined;
|
|
123
|
+
onChange?: ((index: number) => any) | undefined;
|
|
124
|
+
onClose?: (() => any) | undefined;
|
|
125
|
+
onOpen?: ((index: number) => any) | undefined;
|
|
126
|
+
onClosing?: (() => any) | undefined;
|
|
127
|
+
onOpened?: ((index: number) => any) | undefined;
|
|
128
|
+
onLoadMore?: ((index: number) => any) | undefined;
|
|
129
|
+
onPhaseChange?: ((phase: PreviewPhase) => any) | undefined;
|
|
130
|
+
onChromeChange?: ((visible: boolean) => any) | undefined;
|
|
131
|
+
}, {
|
|
132
|
+
resourcePolicy: ImagePolicy;
|
|
133
|
+
videoLoader: VideoSourceLoader;
|
|
134
|
+
mobile: boolean;
|
|
135
|
+
teleportDisabled: boolean;
|
|
136
|
+
keyboardEnabled: boolean;
|
|
137
|
+
gesturesEnabled: boolean;
|
|
138
|
+
persistentChrome: boolean;
|
|
139
|
+
resolveImageSource: ImageSourceResolver;
|
|
140
|
+
hasMore: boolean;
|
|
141
|
+
appearance: "dark" | "album";
|
|
142
|
+
closeDuration: number;
|
|
143
|
+
transitionDuration: number;
|
|
144
|
+
resolveAnchor: (media: PreviewMedia) => PreviewAnchor | Promise<PreviewAnchor>;
|
|
145
|
+
}, {}>;
|
|
146
|
+
declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
|
|
147
|
+
declare const _default: typeof __VLS_export;
|
|
148
|
+
export default _default;
|
|
149
|
+
type __VLS_TypePropsToOption<T> = {
|
|
150
|
+
[K in keyof T]-?: {} extends Pick<T, K> ? {
|
|
151
|
+
type: import('vue').PropType<Required<T>[K]>;
|
|
152
|
+
} : {
|
|
153
|
+
type: import('vue').PropType<T[K]>;
|
|
154
|
+
required: true;
|
|
155
|
+
};
|
|
156
|
+
};
|
|
157
|
+
type __VLS_WithDefaults<P, D> = {
|
|
158
|
+
[K in keyof Pick<P, keyof P>]: K extends keyof D ? __VLS_PrettifyLocal<P[K] & {
|
|
159
|
+
default: D[K];
|
|
160
|
+
}> : P[K];
|
|
161
|
+
};
|
|
162
|
+
type __VLS_WithSlots<T, S> = T & {
|
|
163
|
+
new (): {
|
|
164
|
+
$slots: S;
|
|
165
|
+
};
|
|
166
|
+
};
|
|
167
|
+
type __VLS_PrettifyLocal<T> = (T extends any ? {
|
|
168
|
+
[K in keyof T]: T[K];
|
|
169
|
+
} : {
|
|
170
|
+
[K in keyof T as K]: T[K];
|
|
171
|
+
}) & {};
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
import type { VideoSourceLoader } from "../core/video/useVideoSource";
|
|
2
|
+
import type { ImagePolicy, ImageQuality, ImageSourceResolver, OriginalStatus } from "../core/resources/imagePolicy";
|
|
3
|
+
import type { InitialImage } from "../core/resources/initialImage";
|
|
4
|
+
import type { LivePhotoStatus, PreviewMedia } from "../core/types";
|
|
5
|
+
type __VLS_Props = {
|
|
6
|
+
media: PreviewMedia;
|
|
7
|
+
videoLoader?: VideoSourceLoader;
|
|
8
|
+
livePlaying?: boolean;
|
|
9
|
+
active?: boolean;
|
|
10
|
+
requestVersion?: number;
|
|
11
|
+
loadEnabled?: boolean;
|
|
12
|
+
resourcePolicy?: ImagePolicy;
|
|
13
|
+
resolveSource?: ImageSourceResolver;
|
|
14
|
+
inactiveResetDuration?: number;
|
|
15
|
+
disabled?: boolean;
|
|
16
|
+
externalGestures?: boolean;
|
|
17
|
+
controlsVisible?: boolean;
|
|
18
|
+
teleportControls?: boolean;
|
|
19
|
+
controlsTarget?: string;
|
|
20
|
+
rendering?: boolean;
|
|
21
|
+
paging?: boolean;
|
|
22
|
+
initialImage?: InitialImage;
|
|
23
|
+
quality?: ImageQuality;
|
|
24
|
+
};
|
|
25
|
+
declare const __VLS_export: import("vue").DefineComponent<__VLS_WithDefaults<__VLS_TypePropsToOption<__VLS_Props>, {
|
|
26
|
+
videoLoader: VideoSourceLoader;
|
|
27
|
+
livePlaying: boolean;
|
|
28
|
+
active: boolean;
|
|
29
|
+
inactiveResetDuration: number;
|
|
30
|
+
loadEnabled: boolean;
|
|
31
|
+
requestVersion: number;
|
|
32
|
+
resourcePolicy: () => ImagePolicy;
|
|
33
|
+
resolveSource: ImageSourceResolver;
|
|
34
|
+
disabled: boolean;
|
|
35
|
+
externalGestures: boolean;
|
|
36
|
+
controlsVisible: boolean;
|
|
37
|
+
teleportControls: boolean;
|
|
38
|
+
controlsTarget: string;
|
|
39
|
+
quality: string;
|
|
40
|
+
initialImage: () => InitialImage;
|
|
41
|
+
rendering: boolean;
|
|
42
|
+
paging: boolean;
|
|
43
|
+
}>, {
|
|
44
|
+
onPointerDown: (event: PointerEvent, origin?: DOMRect) => boolean;
|
|
45
|
+
onPointerMove: (event: PointerEvent) => void;
|
|
46
|
+
onPointerUp: (event: PointerEvent) => void;
|
|
47
|
+
onPointerCancel: (event: PointerEvent) => void;
|
|
48
|
+
onWheel: (event: WheelEvent) => void;
|
|
49
|
+
readiness: import("vue").Ref<"loading" | "ready">;
|
|
50
|
+
core: import("../index.ts").PreviewViewportCore;
|
|
51
|
+
rotateBy: (delta?: number) => void;
|
|
52
|
+
resetTransform: (duration?: number) => void;
|
|
53
|
+
zoomIn: () => void;
|
|
54
|
+
zoomOut: () => void;
|
|
55
|
+
togglePlayback: () => void;
|
|
56
|
+
toggleFullscreen: () => Promise<void>;
|
|
57
|
+
captureFrame: () => {
|
|
58
|
+
image: HTMLCanvasElement | HTMLImageElement | HTMLVideoElement;
|
|
59
|
+
scale: number;
|
|
60
|
+
};
|
|
61
|
+
}, unknown, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
62
|
+
error: (error: Error) => void;
|
|
63
|
+
close: () => void;
|
|
64
|
+
ready: (quality: "thumbnail" | "screen" | "full") => void;
|
|
65
|
+
originalState: (status: OriginalStatus, reason: string) => void;
|
|
66
|
+
liveState: (status: LivePhotoStatus) => void;
|
|
67
|
+
liveEnded: () => void;
|
|
68
|
+
tap: () => void;
|
|
69
|
+
doubleTap: () => void;
|
|
70
|
+
scale: (level: number) => void;
|
|
71
|
+
swipeDownProgress: (progress: number) => void;
|
|
72
|
+
previous: () => void;
|
|
73
|
+
next: () => void;
|
|
74
|
+
pageDrag: (offset: number) => void;
|
|
75
|
+
pageRelease: (offset: number, velocity: number) => void;
|
|
76
|
+
}, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<__VLS_WithDefaults<__VLS_TypePropsToOption<__VLS_Props>, {
|
|
77
|
+
videoLoader: VideoSourceLoader;
|
|
78
|
+
livePlaying: boolean;
|
|
79
|
+
active: boolean;
|
|
80
|
+
inactiveResetDuration: number;
|
|
81
|
+
loadEnabled: boolean;
|
|
82
|
+
requestVersion: number;
|
|
83
|
+
resourcePolicy: () => ImagePolicy;
|
|
84
|
+
resolveSource: ImageSourceResolver;
|
|
85
|
+
disabled: boolean;
|
|
86
|
+
externalGestures: boolean;
|
|
87
|
+
controlsVisible: boolean;
|
|
88
|
+
teleportControls: boolean;
|
|
89
|
+
controlsTarget: string;
|
|
90
|
+
quality: string;
|
|
91
|
+
initialImage: () => InitialImage;
|
|
92
|
+
rendering: boolean;
|
|
93
|
+
paging: boolean;
|
|
94
|
+
}>>> & {
|
|
95
|
+
onError?: ((error: Error) => any) | undefined;
|
|
96
|
+
onReady?: ((quality: "thumbnail" | "screen" | "full") => any) | undefined;
|
|
97
|
+
onOriginalState?: ((status: OriginalStatus, reason: string) => any) | undefined;
|
|
98
|
+
onLiveState?: ((status: LivePhotoStatus) => any) | undefined;
|
|
99
|
+
onLiveEnded?: (() => any) | undefined;
|
|
100
|
+
onClose?: (() => any) | undefined;
|
|
101
|
+
onTap?: (() => any) | undefined;
|
|
102
|
+
onDoubleTap?: (() => any) | undefined;
|
|
103
|
+
onScale?: ((level: number) => any) | undefined;
|
|
104
|
+
onSwipeDownProgress?: ((progress: number) => any) | undefined;
|
|
105
|
+
onPrevious?: (() => any) | undefined;
|
|
106
|
+
onNext?: (() => any) | undefined;
|
|
107
|
+
onPageDrag?: ((offset: number) => any) | undefined;
|
|
108
|
+
onPageRelease?: ((offset: number, velocity: number) => any) | undefined;
|
|
109
|
+
}, {
|
|
110
|
+
active: boolean;
|
|
111
|
+
quality: ImageQuality;
|
|
112
|
+
rendering: boolean;
|
|
113
|
+
requestVersion: number;
|
|
114
|
+
loadEnabled: boolean;
|
|
115
|
+
resourcePolicy: ImagePolicy;
|
|
116
|
+
resolveSource: ImageSourceResolver;
|
|
117
|
+
initialImage: InitialImage;
|
|
118
|
+
disabled: boolean;
|
|
119
|
+
videoLoader: VideoSourceLoader;
|
|
120
|
+
controlsVisible: boolean;
|
|
121
|
+
teleportControls: boolean;
|
|
122
|
+
controlsTarget: string;
|
|
123
|
+
livePlaying: boolean;
|
|
124
|
+
inactiveResetDuration: number;
|
|
125
|
+
externalGestures: boolean;
|
|
126
|
+
paging: boolean;
|
|
127
|
+
}, {}>;
|
|
128
|
+
declare const _default: typeof __VLS_export;
|
|
129
|
+
export default _default;
|
|
130
|
+
type __VLS_TypePropsToOption<T> = {
|
|
131
|
+
[K in keyof T]-?: {} extends Pick<T, K> ? {
|
|
132
|
+
type: import('vue').PropType<Required<T>[K]>;
|
|
133
|
+
} : {
|
|
134
|
+
type: import('vue').PropType<T[K]>;
|
|
135
|
+
required: true;
|
|
136
|
+
};
|
|
137
|
+
};
|
|
138
|
+
type __VLS_WithDefaults<P, D> = {
|
|
139
|
+
[K in keyof Pick<P, keyof P>]: K extends keyof D ? __VLS_PrettifyLocal<P[K] & {
|
|
140
|
+
default: D[K];
|
|
141
|
+
}> : P[K];
|
|
142
|
+
};
|
|
143
|
+
type __VLS_PrettifyLocal<T> = (T extends any ? {
|
|
144
|
+
[K in keyof T]: T[K];
|
|
145
|
+
} : {
|
|
146
|
+
[K in keyof T as K]: T[K];
|
|
147
|
+
}) & {};
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import type { TimelineGroup } from "../core/timeline/layout";
|
|
2
|
+
import type { PreviewAnchor } from "../core/types";
|
|
3
|
+
declare const __VLS_export: <T extends {
|
|
4
|
+
id: string;
|
|
5
|
+
}>(__VLS_props: NonNullable<Awaited<typeof __VLS_setup>>["props"], __VLS_ctx?: __VLS_PrettifyLocal<Pick<NonNullable<Awaited<typeof __VLS_setup>>, "attrs" | "emit" | "slots">>, __VLS_exposed?: NonNullable<Awaited<typeof __VLS_setup>>["expose"], __VLS_setup?: Promise<{
|
|
6
|
+
props: import("vue").PublicProps & __VLS_PrettifyLocal<{
|
|
7
|
+
groups: TimelineGroup<T>[];
|
|
8
|
+
scrollElement: () => HTMLElement;
|
|
9
|
+
mobile?: boolean;
|
|
10
|
+
hasMore?: boolean;
|
|
11
|
+
} & {
|
|
12
|
+
onLoadMore?: (() => any) | undefined;
|
|
13
|
+
onDate?: ((key: string) => any) | undefined;
|
|
14
|
+
}> & (typeof globalThis extends {
|
|
15
|
+
__VLS_PROPS_FALLBACK: infer P;
|
|
16
|
+
} ? P : {});
|
|
17
|
+
expose: (exposed: import("vue").ShallowUnwrapRef<{
|
|
18
|
+
resolveAnchor: (id: string) => Promise<PreviewAnchor>;
|
|
19
|
+
rendered: import("vue").ComputedRef<number>;
|
|
20
|
+
total: import("vue").ComputedRef<number>;
|
|
21
|
+
}>) => void;
|
|
22
|
+
attrs: any;
|
|
23
|
+
slots: {
|
|
24
|
+
item(props: {
|
|
25
|
+
item: T;
|
|
26
|
+
}): unknown;
|
|
27
|
+
header(props: {
|
|
28
|
+
group: TimelineGroup<T>;
|
|
29
|
+
index: number;
|
|
30
|
+
}): unknown;
|
|
31
|
+
};
|
|
32
|
+
emit: ((evt: "loadMore") => void) & ((evt: "date", key: string) => void);
|
|
33
|
+
}>) => import("vue").VNode & {
|
|
34
|
+
__ctx?: NonNullable<Awaited<typeof __VLS_setup>>;
|
|
35
|
+
};
|
|
36
|
+
declare const _default: typeof __VLS_export;
|
|
37
|
+
export default _default;
|
|
38
|
+
type __VLS_PrettifyLocal<T> = (T extends any ? {
|
|
39
|
+
[K in keyof T]: T[K];
|
|
40
|
+
} : {
|
|
41
|
+
[K in keyof T as K]: T[K];
|
|
42
|
+
}) & {};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { useVideoPlayback } from "../../core/video/useVideoPlayback";
|
|
2
|
+
type __VLS_Props = {
|
|
3
|
+
playback: ReturnType<typeof useVideoPlayback>;
|
|
4
|
+
fullscreen: boolean;
|
|
5
|
+
canFullscreen: boolean;
|
|
6
|
+
};
|
|
7
|
+
declare const __VLS_export: import("vue").DefineComponent<__VLS_TypePropsToOption<__VLS_Props>, unknown, unknown, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
8
|
+
fullscreen: () => void;
|
|
9
|
+
}, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<__VLS_TypePropsToOption<__VLS_Props>>> & {
|
|
10
|
+
onFullscreen?: (() => any) | undefined;
|
|
11
|
+
}, {}, {}>;
|
|
12
|
+
declare const _default: typeof __VLS_export;
|
|
13
|
+
export default _default;
|
|
14
|
+
type __VLS_TypePropsToOption<T> = {
|
|
15
|
+
[K in keyof T]-?: {} extends Pick<T, K> ? {
|
|
16
|
+
type: import('vue').PropType<Required<T>[K]>;
|
|
17
|
+
} : {
|
|
18
|
+
type: import('vue').PropType<T[K]>;
|
|
19
|
+
required: true;
|
|
20
|
+
};
|
|
21
|
+
};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
type __VLS_Props = {
|
|
2
|
+
name: "play" | "pause" | "replay" | "fullscreen" | "exit" | "volume" | "muted";
|
|
3
|
+
};
|
|
4
|
+
declare const __VLS_export: import("vue").DefineComponent<__VLS_TypePropsToOption<__VLS_Props>, unknown, unknown, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<__VLS_TypePropsToOption<__VLS_Props>>>, {}, {}>;
|
|
5
|
+
declare const _default: typeof __VLS_export;
|
|
6
|
+
export default _default;
|
|
7
|
+
type __VLS_TypePropsToOption<T> = {
|
|
8
|
+
[K in keyof T]-?: {} extends Pick<T, K> ? {
|
|
9
|
+
type: import('vue').PropType<Required<T>[K]>;
|
|
10
|
+
} : {
|
|
11
|
+
type: import('vue').PropType<T[K]>;
|
|
12
|
+
required: true;
|
|
13
|
+
};
|
|
14
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function asError(error: unknown): Error;
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { PreviewPoint } from "../types";
|
|
2
|
+
export type GestureMode = "idle" | "pending" | "hold" | "pan" | "page" | "dismiss" | "pinch";
|
|
3
|
+
export declare function distance(a: PreviewPoint, b: PreviewPoint): number;
|
|
4
|
+
export declare function midpoint(a: PreviewPoint, b: PreviewPoint): PreviewPoint;
|
|
5
|
+
export declare function chooseGesture(dx: number, dy: number, level: number): GestureMode;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { PreviewDirection, PreviewPoint, PreviewRotation, PreviewSize } from "./types";
|
|
2
|
+
export declare function clamp(value: number, min: number, max: number): number;
|
|
3
|
+
export declare function round(value: number, fractionDigits?: number): number;
|
|
4
|
+
export declare function containScale(source: PreviewSize, viewport: PreviewSize): number;
|
|
5
|
+
export declare function normalizeRotation(rotation: number): PreviewRotation;
|
|
6
|
+
export declare function rotateSize(size: PreviewSize, rotation: PreviewRotation): PreviewSize;
|
|
7
|
+
export declare function getDistance(touches: TouchList): number;
|
|
8
|
+
export declare function getCenter(touches: TouchList): PreviewPoint;
|
|
9
|
+
export declare function getDirection(offsetX: number, offsetY: number): PreviewDirection;
|
|
10
|
+
export declare function getTransform(offsetX: number, offsetY: number, scale: number): string;
|
|
11
|
+
export declare function easeOutCubic(progress: number): number;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/** Resource budgets shared by transport, caching and Canvas renderers. */
|
|
2
|
+
export declare const imageLimits: {
|
|
3
|
+
readonly maxDecodedPixels: 24000000;
|
|
4
|
+
readonly maxCanvasPixels: 6000000;
|
|
5
|
+
readonly maxDevicePixelRatio: 2.5;
|
|
6
|
+
readonly maxOriginalBytes: number;
|
|
7
|
+
readonly maxPreviewBytes: number;
|
|
8
|
+
readonly cacheBytes: number;
|
|
9
|
+
readonly cacheEntries: 24;
|
|
10
|
+
readonly concurrency: 3;
|
|
11
|
+
};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { PreviewMedia, PreviewSize } from "../types";
|
|
2
|
+
export declare const imageQualities: readonly ["thumbnail", "screen", "full"];
|
|
3
|
+
export type ImageQuality = (typeof imageQualities)[number];
|
|
4
|
+
export type OriginalStatus = "idle" | "loading" | "ready" | "error" | "blocked";
|
|
5
|
+
export interface ImagePolicy {
|
|
6
|
+
maxOriginalPixels: number;
|
|
7
|
+
maxOriginalBytes: number;
|
|
8
|
+
maxPreviewBytes: number;
|
|
9
|
+
}
|
|
10
|
+
export declare const defaultImagePolicy: ImagePolicy;
|
|
11
|
+
export type ImageSourceResolver = (media: PreviewMedia, quality: ImageQuality, targetWidth: number) => string;
|
|
12
|
+
export declare const defaultImageSource: ImageSourceResolver;
|
|
13
|
+
export declare function originalAllowed(media: PreviewMedia, policy: ImagePolicy): boolean;
|
|
14
|
+
export declare function smartZoom(media: PreviewSize, viewport: PreviewSize): number;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { ImagePolicy, ImageQuality, ImageSourceResolver, OriginalStatus } from "./imagePolicy";
|
|
2
|
+
import type { PreviewMedia } from "../types";
|
|
3
|
+
interface ImageSource {
|
|
4
|
+
url: string;
|
|
5
|
+
quality: ImageQuality;
|
|
6
|
+
rank: number;
|
|
7
|
+
}
|
|
8
|
+
interface ImageRequest {
|
|
9
|
+
sources: ImageSource[];
|
|
10
|
+
originalStatus: OriginalStatus;
|
|
11
|
+
originalReason: string;
|
|
12
|
+
}
|
|
13
|
+
/** Decide resource tiers and safety before the renderer acquires any transport leases. */
|
|
14
|
+
export declare function planImageRequest(media: PreviewMedia, requestedQuality: ImageQuality, policy: ImagePolicy, resolveSource: ImageSourceResolver, targetWidth: number): ImageRequest;
|
|
15
|
+
export {};
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { ImageLoader } from "./imageTransport";
|
|
2
|
+
export interface ImageLease {
|
|
3
|
+
ready: Promise<HTMLImageElement>;
|
|
4
|
+
release: () => void;
|
|
5
|
+
}
|
|
6
|
+
export interface ImageRequestOptions {
|
|
7
|
+
priority?: number;
|
|
8
|
+
maxBytes?: number;
|
|
9
|
+
}
|
|
10
|
+
/** Shared ownership, bounded fetch/decode concurrency and cancellation of unowned requests. */
|
|
11
|
+
export declare class ImageStore {
|
|
12
|
+
private budget;
|
|
13
|
+
private concurrency;
|
|
14
|
+
private loader;
|
|
15
|
+
private entries;
|
|
16
|
+
private active;
|
|
17
|
+
private cancelled;
|
|
18
|
+
constructor(budget?: number, concurrency?: number, loader?: ImageLoader);
|
|
19
|
+
get stats(): {
|
|
20
|
+
active: number;
|
|
21
|
+
queued: number;
|
|
22
|
+
entries: number;
|
|
23
|
+
bytes: number;
|
|
24
|
+
cancelled: number;
|
|
25
|
+
};
|
|
26
|
+
acquire(url: string, options?: ImageRequestOptions): ImageLease;
|
|
27
|
+
private pump;
|
|
28
|
+
private trim;
|
|
29
|
+
}
|
|
30
|
+
export declare const previewImageStore: ImageStore;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export declare class ImageLimitError extends Error {
|
|
2
|
+
constructor(message: string);
|
|
3
|
+
}
|
|
4
|
+
export interface ImageLoadOptions {
|
|
5
|
+
signal: AbortSignal;
|
|
6
|
+
readonly maxBytes: number;
|
|
7
|
+
}
|
|
8
|
+
export type ImageLoader = (url: string, options: ImageLoadOptions) => Promise<HTMLImageElement>;
|
|
9
|
+
export declare const loadImage: ImageLoader;
|