dsh-image-viewer 0.1.0-beta.10 → 0.1.0-beta.11
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/AGENTS.md +1 -1
- package/README.en.md +3 -1
- package/README.md +3 -1
- package/compatibility.json +2 -1
- package/lib/client.js +353 -263
- package/lib/client.js.map +1 -1
- package/package.json +6 -5
package/AGENTS.md
CHANGED
|
@@ -13,7 +13,7 @@ Use this guide only when the user asks to install, update, verify, or remove `ds
|
|
|
13
13
|
## Install or update
|
|
14
14
|
|
|
15
15
|
```sh
|
|
16
|
-
dsh plugin --profile web add dsh-image-viewer@0.1.0-beta.
|
|
16
|
+
dsh plugin --profile web add dsh-image-viewer@0.1.0-beta.11
|
|
17
17
|
```
|
|
18
18
|
|
|
19
19
|
DSH-Portable exposes the same standard `dsh plugin` command. Do not use a private executable path in public instructions.
|
package/README.en.md
CHANGED
|
@@ -30,6 +30,8 @@ Release checks exercise real attachments on stable and current Alpha DSH: galler
|
|
|
30
30
|
|
|
31
31
|
- Wheel zoom centered on the pointer, drag-to-pan, touch pinch, and double-click 100% view.
|
|
32
32
|
- Fit and original-size controls, original-file download, keyboard navigation, and multi-image galleries.
|
|
33
|
+
- Visible filename, dimensions and pixel-scale percentage; very wide images can reach 100%, and window resizing keeps the image within reach.
|
|
34
|
+
- Loading and retryable error states, gesture reset on image changes, and independent notes for unnamed images.
|
|
33
35
|
- One-shot region marking with each note edited beside its numbered image marker. Enter saves and collapses the note;
|
|
34
36
|
Shift+Enter adds a new line.
|
|
35
37
|
- Light and dark themes through DSH design tokens, responsive layout, focus containment, and reduced-motion support.
|
|
@@ -42,7 +44,7 @@ DSH keeps working when the plugin is absent or cannot recognize a newer image su
|
|
|
42
44
|
Install the Beta:
|
|
43
45
|
|
|
44
46
|
```sh
|
|
45
|
-
dsh plugin --profile web add dsh-image-viewer@0.1.0-beta.
|
|
47
|
+
dsh plugin --profile web add dsh-image-viewer@0.1.0-beta.11
|
|
46
48
|
```
|
|
47
49
|
|
|
48
50
|
Restart DSH manually after saving active work. The plugin never needs access to provider credentials or image-generation accounts.
|
package/README.md
CHANGED
|
@@ -30,6 +30,8 @@
|
|
|
30
30
|
|
|
31
31
|
- 以鼠标位置为中心的滚轮缩放、拖动查看、触控双指缩放和双击原始大小。
|
|
32
32
|
- 适应窗口、原始大小、原图下载、键盘切换和多图浏览。
|
|
33
|
+
- 显示图片名称、尺寸与真实像素缩放比例;超宽大图也能切换到 100%,调整窗口后保持图片可见。
|
|
34
|
+
- 图片加载中和加载失败都有明确提示,失败可重试;切换图片会重置拖拽状态,区域备注不会串到另一张未命名图片。
|
|
33
35
|
- 一次点击标记一个区域,备注直接显示在图片编号附近并自动获得输入焦点;Enter 保存并收起,Shift+Enter 换行。
|
|
34
36
|
- 使用 DSH 设计令牌适配亮色、暗色、响应式布局、焦点约束和减少动态效果设置。
|
|
35
37
|
- 提供可选的 `nativeImageViewer` 客户端服务,图片生成插件可以按需增加自己的后续操作。
|
|
@@ -41,7 +43,7 @@
|
|
|
41
43
|
安装 Beta:
|
|
42
44
|
|
|
43
45
|
```sh
|
|
44
|
-
dsh plugin --profile web add dsh-image-viewer@0.1.0-beta.
|
|
46
|
+
dsh plugin --profile web add dsh-image-viewer@0.1.0-beta.11
|
|
45
47
|
```
|
|
46
48
|
|
|
47
49
|
保存正在进行的工作后手动重启 DSH。本插件不需要供应商凭据或图片生成账户权限。
|
package/compatibility.json
CHANGED
package/lib/client.js
CHANGED
|
@@ -29,7 +29,7 @@ window.__ModuleLoader__.load({
|
|
|
29
29
|
const items = (Array.isArray(request?.items) ? request.items : []).flatMap((item, position) => {
|
|
30
30
|
if (typeof item?.src !== "string" || item.src === "") return [];
|
|
31
31
|
return [{
|
|
32
|
-
id: typeof item.id === "string" && item.id !== "" ? item.id :
|
|
32
|
+
id: typeof item.id === "string" && item.id !== "" ? item.id : item.src,
|
|
33
33
|
src: item.src,
|
|
34
34
|
name: typeof item.name === "string" && item.name !== "" ? item.name : `Image ${position + 1}`,
|
|
35
35
|
width: boundedNumber(item.width, void 0),
|
|
@@ -144,6 +144,7 @@ window.__ModuleLoader__.load({
|
|
|
144
144
|
const CSS$1 = String.raw`
|
|
145
145
|
.niv-root{position:fixed;inset:0;z-index:1000;pointer-events:auto;overflow:hidden;background:rgba(7,8,10,.68);color:var(--dsw-alias-label-primary-inverted,#fff);outline:0;backdrop-filter:blur(13px) saturate(.72);-webkit-backdrop-filter:blur(13px) saturate(.72)}
|
|
146
146
|
.niv-sr-only{position:absolute!important;width:1px!important;height:1px!important;padding:0!important;margin:-1px!important;overflow:hidden!important;clip:rect(0,0,0,0)!important;white-space:nowrap!important;border:0!important}
|
|
147
|
+
.niv-title{position:absolute;top:20px;left:24px;right:84px;display:flex;align-items:baseline;gap:12px;color:#fff;font-size:13px}.niv-title strong{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.niv-title small{flex:none;opacity:.7}.niv-load-status{position:absolute;z-index:7;display:flex;align-items:center;gap:12px;color:#fff;font-size:14px}
|
|
147
148
|
.niv-topbar{position:absolute;right:50%;bottom:22px;z-index:6;max-width:calc(100vw - 36px);padding:5px;border:1px solid rgba(255,255,255,.12);border-radius:999px;background:rgba(38,39,43,.86);box-shadow:0 10px 34px rgba(0,0,0,.3);transform:translateX(50%);backdrop-filter:blur(18px);-webkit-backdrop-filter:blur(18px)}
|
|
148
149
|
.niv-actions{display:flex;align-items:center;gap:2px;overflow-x:auto;scrollbar-width:none}.niv-actions::-webkit-scrollbar{display:none}.niv-button,.niv-download{box-sizing:border-box;display:inline-flex;align-items:center;justify-content:center;gap:6px;height:32px;padding:0 10px;border:0;border-radius:999px;background:transparent;color:rgba(255,255,255,.9);font:inherit;font-size:12px;text-decoration:none;white-space:nowrap;cursor:pointer}.niv-button:hover,.niv-download:hover,.niv-button[data-active=true]{background:rgba(255,255,255,.12)}.niv-button:focus-visible,.niv-download:focus-visible,.niv-close-floating:focus-visible{outline:2px solid rgba(255,255,255,.9);outline-offset:2px}.niv-button:disabled,.niv-download:disabled{opacity:.38;cursor:default}.niv-icon-only{width:32px;padding:0}.niv-zoom{min-width:44px;color:rgba(255,255,255,.68);font-size:12px;font-variant-numeric:tabular-nums;text-align:center}
|
|
149
150
|
.niv-close-floating{position:absolute;top:20px;right:20px;z-index:8;display:grid;place-items:center;width:42px;height:42px;padding:0;border:1px solid rgba(255,255,255,.1);border-radius:50%;background:rgba(48,49,53,.82);box-shadow:0 8px 24px rgba(0,0,0,.28);color:#fff;cursor:pointer;backdrop-filter:blur(16px);-webkit-backdrop-filter:blur(16px)}.niv-close-floating:hover{background:rgba(66,67,72,.92)}
|
|
@@ -158,6 +159,168 @@ window.__ModuleLoader__.load({
|
|
|
158
159
|
@media(max-width:760px){.niv-close-floating{top:12px;right:12px;width:40px;height:40px}.niv-workspace{padding:60px 12px 68px}.niv-image{max-width:calc(100vw - 24px);max-height:calc(100vh - 136px)}.niv-topbar{bottom:12px;max-width:calc(100vw - 24px)}.niv-button{padding:0 8px}.niv-button span.niv-label{display:none}.niv-inline-note{width:min(260px,calc(100vw - 40px))}.niv-copy-notes{display:none}}
|
|
159
160
|
@media(prefers-reduced-motion:reduce){.niv-surface{transition:none}}
|
|
160
161
|
`;
|
|
162
|
+
//#endregion
|
|
163
|
+
//#region src/image-transform.js
|
|
164
|
+
const clamp$1 = (value, min, max) => Math.min(max, Math.max(min, value));
|
|
165
|
+
const fitted = () => ({
|
|
166
|
+
zoom: 1,
|
|
167
|
+
x: 0,
|
|
168
|
+
y: 0
|
|
169
|
+
});
|
|
170
|
+
function useImageTransform(identity) {
|
|
171
|
+
const [transform, setTransform] = (0, react.useState)(fitted);
|
|
172
|
+
const [dragging, setDragging] = (0, react.useState)(false);
|
|
173
|
+
const [pixelScale, setPixelScale] = (0, react.useState)(1);
|
|
174
|
+
const stageRef = (0, react.useRef)(null), surfaceRef = (0, react.useRef)(null), imageRef = (0, react.useRef)(null);
|
|
175
|
+
const transformRef = (0, react.useRef)(transform);
|
|
176
|
+
const pointers = (0, react.useRef)(/* @__PURE__ */ new Map()), gesture = (0, react.useRef)();
|
|
177
|
+
transformRef.current = transform;
|
|
178
|
+
const resetGesture = (0, react.useCallback)(() => {
|
|
179
|
+
pointers.current.clear();
|
|
180
|
+
gesture.current = void 0;
|
|
181
|
+
setDragging(false);
|
|
182
|
+
}, []);
|
|
183
|
+
const fit = (0, react.useCallback)(() => {
|
|
184
|
+
resetGesture();
|
|
185
|
+
setTransform(fitted());
|
|
186
|
+
}, [resetGesture]);
|
|
187
|
+
(0, react.useEffect)(() => {
|
|
188
|
+
fit();
|
|
189
|
+
}, [identity, fit]);
|
|
190
|
+
const actualScale = () => imageRef.current?.naturalWidth / Math.max(1, surfaceRef.current?.offsetWidth || 1) || 1;
|
|
191
|
+
const boundedPan = (0, react.useCallback)((zoom, x, y) => {
|
|
192
|
+
const stage = stageRef.current, surface = surfaceRef.current;
|
|
193
|
+
if (!stage || !surface || zoom <= 1) return {
|
|
194
|
+
x: 0,
|
|
195
|
+
y: 0
|
|
196
|
+
};
|
|
197
|
+
const limitX = Math.max(0, (surface.offsetWidth * zoom - stage.clientWidth) / 2);
|
|
198
|
+
const limitY = Math.max(0, (surface.offsetHeight * zoom - stage.clientHeight) / 2);
|
|
199
|
+
return {
|
|
200
|
+
x: clamp$1(x, -limitX, limitX),
|
|
201
|
+
y: clamp$1(y, -limitY, limitY)
|
|
202
|
+
};
|
|
203
|
+
}, []);
|
|
204
|
+
const setZoomAt = (0, react.useCallback)((zoom, clientX, clientY) => {
|
|
205
|
+
const stage = stageRef.current;
|
|
206
|
+
if (!stage) return;
|
|
207
|
+
setTransform((current) => {
|
|
208
|
+
const next = clamp$1(zoom, .5, Math.max(8, actualScale()));
|
|
209
|
+
const box = stage.getBoundingClientRect();
|
|
210
|
+
const px = clientX - box.left - box.width / 2, py = clientY - box.top - box.height / 2;
|
|
211
|
+
const ratio = next / current.zoom;
|
|
212
|
+
return {
|
|
213
|
+
zoom: next,
|
|
214
|
+
...boundedPan(next, px - (px - current.x) * ratio, py - (py - current.y) * ratio)
|
|
215
|
+
};
|
|
216
|
+
});
|
|
217
|
+
}, [boundedPan]);
|
|
218
|
+
const actual = (0, react.useCallback)(() => {
|
|
219
|
+
if (!imageRef.current?.naturalWidth) return;
|
|
220
|
+
resetGesture();
|
|
221
|
+
setTransform({
|
|
222
|
+
zoom: actualScale(),
|
|
223
|
+
x: 0,
|
|
224
|
+
y: 0
|
|
225
|
+
});
|
|
226
|
+
}, [resetGesture]);
|
|
227
|
+
const measure = (0, react.useCallback)(() => {
|
|
228
|
+
setPixelScale(1 / actualScale());
|
|
229
|
+
setTransform((current) => ({
|
|
230
|
+
...current,
|
|
231
|
+
...boundedPan(current.zoom, current.x, current.y)
|
|
232
|
+
}));
|
|
233
|
+
}, [boundedPan]);
|
|
234
|
+
(0, react.useEffect)(() => {
|
|
235
|
+
if (!stageRef.current || !surfaceRef.current) return;
|
|
236
|
+
const observer = new ResizeObserver(measure);
|
|
237
|
+
observer.observe(stageRef.current);
|
|
238
|
+
observer.observe(surfaceRef.current);
|
|
239
|
+
measure();
|
|
240
|
+
return () => observer.disconnect();
|
|
241
|
+
}, [identity, measure]);
|
|
242
|
+
(0, react.useEffect)(() => {
|
|
243
|
+
const stage = stageRef.current;
|
|
244
|
+
if (!stage) return;
|
|
245
|
+
const wheel = (event) => {
|
|
246
|
+
event.preventDefault();
|
|
247
|
+
const delta = event.deltaY * (event.deltaMode === 1 ? 16 : event.deltaMode === 2 ? stage.clientHeight : 1);
|
|
248
|
+
setZoomAt(transformRef.current.zoom * Math.exp(-delta * .0015), event.clientX, event.clientY);
|
|
249
|
+
};
|
|
250
|
+
stage.addEventListener("wheel", wheel, { passive: false });
|
|
251
|
+
return () => stage.removeEventListener("wheel", wheel);
|
|
252
|
+
}, [identity, setZoomAt]);
|
|
253
|
+
const onPointerDown = (event) => {
|
|
254
|
+
if (event.button !== 0 || event.target.closest("button,a,input,textarea,select")) return;
|
|
255
|
+
const current = transformRef.current;
|
|
256
|
+
if (event.pointerType === "mouse" && current.zoom <= 1) return;
|
|
257
|
+
event.currentTarget.setPointerCapture(event.pointerId);
|
|
258
|
+
pointers.current.set(event.pointerId, {
|
|
259
|
+
x: event.clientX,
|
|
260
|
+
y: event.clientY
|
|
261
|
+
});
|
|
262
|
+
if (pointers.current.size === 2) {
|
|
263
|
+
const [a, b] = [...pointers.current.values()];
|
|
264
|
+
gesture.current = {
|
|
265
|
+
kind: "pinch",
|
|
266
|
+
distance: Math.hypot(a.x - b.x, a.y - b.y),
|
|
267
|
+
transform: current
|
|
268
|
+
};
|
|
269
|
+
} else gesture.current = {
|
|
270
|
+
kind: "pan",
|
|
271
|
+
x: event.clientX,
|
|
272
|
+
y: event.clientY,
|
|
273
|
+
transform: current
|
|
274
|
+
};
|
|
275
|
+
setDragging(true);
|
|
276
|
+
};
|
|
277
|
+
const onPointerMove = (event) => {
|
|
278
|
+
if (!pointers.current.has(event.pointerId)) return;
|
|
279
|
+
pointers.current.set(event.pointerId, {
|
|
280
|
+
x: event.clientX,
|
|
281
|
+
y: event.clientY
|
|
282
|
+
});
|
|
283
|
+
const start = gesture.current;
|
|
284
|
+
if (start?.kind === "pinch" && pointers.current.size >= 2) {
|
|
285
|
+
const [a, b] = [...pointers.current.values()];
|
|
286
|
+
setZoomAt(start.transform.zoom * Math.hypot(a.x - b.x, a.y - b.y) / Math.max(1, start.distance), (a.x + b.x) / 2, (a.y + b.y) / 2);
|
|
287
|
+
} else if (start?.kind === "pan") setTransform({
|
|
288
|
+
zoom: start.transform.zoom,
|
|
289
|
+
...boundedPan(start.transform.zoom, start.transform.x + event.clientX - start.x, start.transform.y + event.clientY - start.y)
|
|
290
|
+
});
|
|
291
|
+
};
|
|
292
|
+
const endPointer = (event) => {
|
|
293
|
+
pointers.current.delete(event.pointerId);
|
|
294
|
+
const remaining = [...pointers.current.values()][0];
|
|
295
|
+
if (remaining) gesture.current = {
|
|
296
|
+
kind: "pan",
|
|
297
|
+
...remaining,
|
|
298
|
+
transform: transformRef.current
|
|
299
|
+
};
|
|
300
|
+
else resetGesture();
|
|
301
|
+
};
|
|
302
|
+
return {
|
|
303
|
+
transform,
|
|
304
|
+
transformRef,
|
|
305
|
+
dragging,
|
|
306
|
+
pixelScale,
|
|
307
|
+
stageRef,
|
|
308
|
+
surfaceRef,
|
|
309
|
+
imageRef,
|
|
310
|
+
fit,
|
|
311
|
+
actual,
|
|
312
|
+
measure,
|
|
313
|
+
setZoomAt,
|
|
314
|
+
resetGesture,
|
|
315
|
+
pointerHandlers: {
|
|
316
|
+
onPointerDown,
|
|
317
|
+
onPointerMove,
|
|
318
|
+
onPointerUp: endPointer,
|
|
319
|
+
onPointerCancel: endPointer,
|
|
320
|
+
onLostPointerCapture: endPointer
|
|
321
|
+
}
|
|
322
|
+
};
|
|
323
|
+
}
|
|
161
324
|
//#endregion
|
|
162
325
|
//#region src/client.jsx
|
|
163
326
|
const name = "dsh-image-viewer";
|
|
@@ -183,7 +346,11 @@ window.__ModuleLoader__.load({
|
|
|
183
346
|
next: "Next image",
|
|
184
347
|
zoomHint: "Wheel to zoom · drag to pan · double-click for 100%",
|
|
185
348
|
preparing: "Preparing…",
|
|
186
|
-
failed: "Could not prepare this image."
|
|
349
|
+
failed: "Could not prepare this image.",
|
|
350
|
+
loading: "Loading image…",
|
|
351
|
+
loadFailed: "Image could not be loaded.",
|
|
352
|
+
retry: "Retry",
|
|
353
|
+
copyFailed: "Copy failed. Try again."
|
|
187
354
|
},
|
|
188
355
|
zh: {
|
|
189
356
|
dialog: "图片查看器",
|
|
@@ -205,7 +372,11 @@ window.__ModuleLoader__.load({
|
|
|
205
372
|
next: "下一张图片",
|
|
206
373
|
zoomHint: "滚轮缩放 · 拖动查看 · 双击切换原始大小",
|
|
207
374
|
preparing: "正在准备…",
|
|
208
|
-
failed: "暂时无法准备这张图片。"
|
|
375
|
+
failed: "暂时无法准备这张图片。",
|
|
376
|
+
loading: "正在加载图片…",
|
|
377
|
+
loadFailed: "图片加载失败。",
|
|
378
|
+
retry: "重试",
|
|
379
|
+
copyFailed: "复制失败,请重试。"
|
|
209
380
|
}
|
|
210
381
|
};
|
|
211
382
|
const fill = (value, variables) => Object.entries(variables).reduce((text, [key, replacement]) => text.replaceAll(`{${key}}`, String(replacement)), value);
|
|
@@ -281,12 +452,9 @@ window.__ModuleLoader__.load({
|
|
|
281
452
|
function ViewerOverlay({ service, t }) {
|
|
282
453
|
const request = (0, react.useSyncExternalStore)(service.subscribe, service.getSnapshot);
|
|
283
454
|
const [index, setIndex] = (0, react.useState)(0);
|
|
284
|
-
const [
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
y: 0
|
|
288
|
-
});
|
|
289
|
-
const [dragging, setDragging] = (0, react.useState)(false);
|
|
455
|
+
const [imageState, setImageState] = (0, react.useState)("loading");
|
|
456
|
+
const [attempt, setAttempt] = (0, react.useState)(0);
|
|
457
|
+
const [copyFailed, setCopyFailed] = (0, react.useState)(false);
|
|
290
458
|
const [annotating, setAnnotating] = (0, react.useState)(false);
|
|
291
459
|
const [annotationsByImage, setAnnotationsByImage] = (0, react.useState)(service.getAnnotationsSnapshot);
|
|
292
460
|
const annotationsByImageRef = (0, react.useRef)(annotationsByImage);
|
|
@@ -294,28 +462,16 @@ window.__ModuleLoader__.load({
|
|
|
294
462
|
const [focusNote, setFocusNote] = (0, react.useState)();
|
|
295
463
|
const [copied, setCopied] = (0, react.useState)(false);
|
|
296
464
|
const rootRef = (0, react.useRef)(null);
|
|
297
|
-
const stageRef = (0, react.useRef)(null);
|
|
298
|
-
const surfaceRef = (0, react.useRef)(null);
|
|
299
|
-
const imageRef = (0, react.useRef)(null);
|
|
300
|
-
const pointersRef = (0, react.useRef)(/* @__PURE__ */ new Map());
|
|
301
|
-
const gestureRef = (0, react.useRef)();
|
|
302
|
-
const transformRef = (0, react.useRef)(transform);
|
|
303
|
-
transformRef.current = transform;
|
|
304
465
|
annotationsByImageRef.current = annotationsByImage;
|
|
305
466
|
(0, react.useEffect)(() => {
|
|
306
467
|
if (request === void 0) return;
|
|
307
468
|
setIndex(request.index);
|
|
308
|
-
setTransform({
|
|
309
|
-
zoom: 1,
|
|
310
|
-
x: 0,
|
|
311
|
-
y: 0
|
|
312
|
-
});
|
|
313
|
-
setDragging(false);
|
|
314
469
|
setAnnotating(false);
|
|
315
470
|
setSelected(void 0);
|
|
316
471
|
setCopied(false);
|
|
317
472
|
}, [request?.revision]);
|
|
318
473
|
const item = request?.items[index];
|
|
474
|
+
const { transform, transformRef, dragging, pixelScale, stageRef, surfaceRef, imageRef, fit, actual, measure, setZoomAt, resetGesture, pointerHandlers } = useImageTransform(`${request?.revision}:${item?.id}:${item?.src}`);
|
|
319
475
|
const annotations = item === void 0 ? [] : annotationsByImage[item.id] ?? [];
|
|
320
476
|
const setAnnotations = (0, react.useCallback)((update) => {
|
|
321
477
|
if (item === void 0) return;
|
|
@@ -329,61 +485,16 @@ window.__ModuleLoader__.load({
|
|
|
329
485
|
service.setAnnotations(item.id, next);
|
|
330
486
|
setAnnotationsByImage(snapshot);
|
|
331
487
|
}, [item?.id, service]);
|
|
332
|
-
const boundedPan = (0, react.useCallback)((zoom, x, y) => {
|
|
333
|
-
const stage = stageRef.current;
|
|
334
|
-
const surface = surfaceRef.current;
|
|
335
|
-
if (stage === null || surface === null || zoom <= 1) return {
|
|
336
|
-
x: 0,
|
|
337
|
-
y: 0
|
|
338
|
-
};
|
|
339
|
-
const limitX = Math.max(0, (surface.offsetWidth * zoom - stage.clientWidth) / 2) + 28;
|
|
340
|
-
const limitY = Math.max(0, (surface.offsetHeight * zoom - stage.clientHeight) / 2) + 28;
|
|
341
|
-
return {
|
|
342
|
-
x: clamp(x, -limitX, limitX),
|
|
343
|
-
y: clamp(y, -limitY, limitY)
|
|
344
|
-
};
|
|
345
|
-
}, []);
|
|
346
|
-
const setZoomAt = (0, react.useCallback)((nextZoom, clientX, clientY) => {
|
|
347
|
-
const stage = stageRef.current;
|
|
348
|
-
if (stage === null) return;
|
|
349
|
-
setTransform((current) => {
|
|
350
|
-
const next = clamp(nextZoom, .5, 8);
|
|
351
|
-
const box = stage.getBoundingClientRect();
|
|
352
|
-
const px = clientX - box.left - box.width / 2;
|
|
353
|
-
const py = clientY - box.top - box.height / 2;
|
|
354
|
-
const ratio = next / current.zoom;
|
|
355
|
-
return {
|
|
356
|
-
zoom: next,
|
|
357
|
-
...boundedPan(next, px - (px - current.x) * ratio, py - (py - current.y) * ratio)
|
|
358
|
-
};
|
|
359
|
-
});
|
|
360
|
-
}, [boundedPan]);
|
|
361
|
-
const fit = (0, react.useCallback)(() => {
|
|
362
|
-
setTransform({
|
|
363
|
-
zoom: 1,
|
|
364
|
-
x: 0,
|
|
365
|
-
y: 0
|
|
366
|
-
});
|
|
367
|
-
}, []);
|
|
368
|
-
const actual = (0, react.useCallback)(() => {
|
|
369
|
-
const image = imageRef.current;
|
|
370
|
-
const surface = surfaceRef.current;
|
|
371
|
-
if (image === null || surface === null || image.naturalWidth === 0) return;
|
|
372
|
-
const zoom = clamp(image.naturalWidth / Math.max(1, surface.offsetWidth), 1, 8);
|
|
373
|
-
setTransform({
|
|
374
|
-
zoom,
|
|
375
|
-
x: 0,
|
|
376
|
-
y: 0
|
|
377
|
-
});
|
|
378
|
-
}, []);
|
|
379
488
|
(0, react.useEffect)(() => {
|
|
380
489
|
if (request === void 0) return void 0;
|
|
381
490
|
const previousOverflow = document.body.style.overflow;
|
|
382
491
|
document.body.style.overflow = "hidden";
|
|
383
492
|
rootRef.current?.focus();
|
|
384
493
|
const onKeyDown = (event) => {
|
|
494
|
+
if (event.defaultPrevented || event.isComposing) return;
|
|
385
495
|
if (event.key === "Escape") {
|
|
386
496
|
event.preventDefault();
|
|
497
|
+
event.stopPropagation();
|
|
387
498
|
if (event.target instanceof Element && event.target.closest(".niv-inline-note") !== null) {
|
|
388
499
|
setSelected(void 0);
|
|
389
500
|
return;
|
|
@@ -391,7 +502,17 @@ window.__ModuleLoader__.load({
|
|
|
391
502
|
service.close();
|
|
392
503
|
return;
|
|
393
504
|
}
|
|
394
|
-
|
|
505
|
+
if (event.ctrlKey || event.metaKey || event.altKey) return;
|
|
506
|
+
const editing = event.target instanceof Element && event.target.closest("input,textarea,select,[contenteditable=\"true\"]") !== null;
|
|
507
|
+
if (!editing && [
|
|
508
|
+
"ArrowLeft",
|
|
509
|
+
"ArrowRight",
|
|
510
|
+
"+",
|
|
511
|
+
"=",
|
|
512
|
+
"-",
|
|
513
|
+
"f",
|
|
514
|
+
"F"
|
|
515
|
+
].includes(event.key)) event.stopPropagation();
|
|
395
516
|
if (!editing && event.key === "ArrowLeft" && request.items.length > 1) {
|
|
396
517
|
event.preventDefault();
|
|
397
518
|
setIndex((value) => (value - 1 + request.items.length) % request.items.length);
|
|
@@ -413,19 +534,20 @@ window.__ModuleLoader__.load({
|
|
|
413
534
|
const controls = [...rootRef.current.querySelectorAll("button:not(:disabled),a[href],input:not(:disabled),textarea:not(:disabled),[tabindex]:not([tabindex=\"-1\"])")];
|
|
414
535
|
const first = controls[0];
|
|
415
536
|
const last = controls.at(-1);
|
|
416
|
-
if (event.shiftKey && document.activeElement === first) {
|
|
537
|
+
if (event.shiftKey && (document.activeElement === first || document.activeElement === rootRef.current)) {
|
|
417
538
|
event.preventDefault();
|
|
418
539
|
last?.focus();
|
|
419
|
-
} else if (!event.shiftKey && document.activeElement === last) {
|
|
540
|
+
} else if (!event.shiftKey && (document.activeElement === last || document.activeElement === rootRef.current)) {
|
|
420
541
|
event.preventDefault();
|
|
421
542
|
first?.focus();
|
|
422
543
|
}
|
|
423
544
|
}
|
|
424
545
|
};
|
|
425
|
-
|
|
546
|
+
const root = rootRef.current;
|
|
547
|
+
root.addEventListener("keydown", onKeyDown);
|
|
426
548
|
return () => {
|
|
427
549
|
document.body.style.overflow = previousOverflow;
|
|
428
|
-
|
|
550
|
+
root.removeEventListener("keydown", onKeyDown);
|
|
429
551
|
};
|
|
430
552
|
}, [
|
|
431
553
|
request,
|
|
@@ -443,77 +565,16 @@ window.__ModuleLoader__.load({
|
|
|
443
565
|
annotations.length
|
|
444
566
|
]);
|
|
445
567
|
(0, react.useEffect)(() => {
|
|
446
|
-
setTransform({
|
|
447
|
-
zoom: 1,
|
|
448
|
-
x: 0,
|
|
449
|
-
y: 0
|
|
450
|
-
});
|
|
451
|
-
setDragging(false);
|
|
452
568
|
setAnnotating(false);
|
|
453
569
|
setSelected(void 0);
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
stage.addEventListener("wheel", onWheel, { passive: false });
|
|
463
|
-
return () => stage.removeEventListener("wheel", onWheel);
|
|
464
|
-
}, [onWheel, request]);
|
|
465
|
-
const onPointerDown = (event) => {
|
|
466
|
-
if (event.button !== 0 || annotating) return;
|
|
467
|
-
if (event.target instanceof Element && event.target.closest("button,a,input,textarea,select")) return;
|
|
468
|
-
if (event.pointerType === "mouse" && transform.zoom <= 1) return;
|
|
469
|
-
event.currentTarget.setPointerCapture(event.pointerId);
|
|
470
|
-
pointersRef.current.set(event.pointerId, {
|
|
471
|
-
x: event.clientX,
|
|
472
|
-
y: event.clientY
|
|
473
|
-
});
|
|
474
|
-
if (pointersRef.current.size === 2) {
|
|
475
|
-
const [a, b] = [...pointersRef.current.values()];
|
|
476
|
-
gestureRef.current = {
|
|
477
|
-
kind: "pinch",
|
|
478
|
-
distance: Math.hypot(a.x - b.x, a.y - b.y),
|
|
479
|
-
transform
|
|
480
|
-
};
|
|
481
|
-
} else if (!annotating && transform.zoom > 1) {
|
|
482
|
-
gestureRef.current = {
|
|
483
|
-
kind: "pan",
|
|
484
|
-
x: event.clientX,
|
|
485
|
-
y: event.clientY,
|
|
486
|
-
transform
|
|
487
|
-
};
|
|
488
|
-
setDragging(true);
|
|
489
|
-
}
|
|
490
|
-
};
|
|
491
|
-
const onPointerMove = (event) => {
|
|
492
|
-
if (!pointersRef.current.has(event.pointerId)) return;
|
|
493
|
-
pointersRef.current.set(event.pointerId, {
|
|
494
|
-
x: event.clientX,
|
|
495
|
-
y: event.clientY
|
|
496
|
-
});
|
|
497
|
-
const gesture = gestureRef.current;
|
|
498
|
-
if (gesture?.kind === "pinch" && pointersRef.current.size >= 2) {
|
|
499
|
-
const [a, b] = [...pointersRef.current.values()];
|
|
500
|
-
const distance = Math.max(1, Math.hypot(a.x - b.x, a.y - b.y));
|
|
501
|
-
setZoomAt(gesture.transform.zoom * distance / Math.max(1, gesture.distance), (a.x + b.x) / 2, (a.y + b.y) / 2);
|
|
502
|
-
} else if (gesture?.kind === "pan") {
|
|
503
|
-
const pan = boundedPan(gesture.transform.zoom, gesture.transform.x + event.clientX - gesture.x, gesture.transform.y + event.clientY - gesture.y);
|
|
504
|
-
setTransform({
|
|
505
|
-
zoom: gesture.transform.zoom,
|
|
506
|
-
...pan
|
|
507
|
-
});
|
|
508
|
-
}
|
|
509
|
-
};
|
|
510
|
-
const endPointer = (event) => {
|
|
511
|
-
pointersRef.current.delete(event.pointerId);
|
|
512
|
-
if (pointersRef.current.size === 0) {
|
|
513
|
-
gestureRef.current = void 0;
|
|
514
|
-
setDragging(false);
|
|
515
|
-
}
|
|
516
|
-
};
|
|
570
|
+
setImageState("loading");
|
|
571
|
+
setCopyFailed(false);
|
|
572
|
+
setCopied(false);
|
|
573
|
+
}, [
|
|
574
|
+
item?.id,
|
|
575
|
+
item?.src,
|
|
576
|
+
request?.revision
|
|
577
|
+
]);
|
|
517
578
|
const addAnnotation = (event) => {
|
|
518
579
|
if (!annotating || event.target.closest(".niv-annotation")) return;
|
|
519
580
|
const bounds = surfaceRef.current?.getBoundingClientRect();
|
|
@@ -532,11 +593,13 @@ window.__ModuleLoader__.load({
|
|
|
532
593
|
const copyNotes = async () => {
|
|
533
594
|
const text = noteText(annotations, t);
|
|
534
595
|
if (text === "") return;
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
}
|
|
596
|
+
try {
|
|
597
|
+
await navigator.clipboard.writeText(text);
|
|
598
|
+
setCopied(true);
|
|
599
|
+
setCopyFailed(false);
|
|
600
|
+
} catch {
|
|
601
|
+
setCopyFailed(true);
|
|
602
|
+
}
|
|
540
603
|
};
|
|
541
604
|
if (request === void 0 || item === void 0) return null;
|
|
542
605
|
const meta = [item.width && item.height ? `${item.width} × ${item.height}` : void 0, bytesLabel(item.bytes)].filter(Boolean).join(" · ");
|
|
@@ -550,7 +613,7 @@ window.__ModuleLoader__.load({
|
|
|
550
613
|
tabIndex: -1,
|
|
551
614
|
children: [
|
|
552
615
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
553
|
-
className: "niv-title
|
|
616
|
+
className: "niv-title",
|
|
554
617
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("strong", { children: item.name }), meta !== "" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("small", { children: meta }) : null]
|
|
555
618
|
}),
|
|
556
619
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("header", {
|
|
@@ -566,7 +629,11 @@ window.__ModuleLoader__.load({
|
|
|
566
629
|
"data-active": annotating,
|
|
567
630
|
"aria-label": annotating ? t("cancelAnnotate") : t("annotate"),
|
|
568
631
|
"aria-pressed": annotating,
|
|
569
|
-
|
|
632
|
+
disabled: imageState !== "ready",
|
|
633
|
+
onClick: () => {
|
|
634
|
+
resetGesture();
|
|
635
|
+
setAnnotating((value) => !value);
|
|
636
|
+
},
|
|
570
637
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconEditOutline16, {}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
571
638
|
className: "niv-label",
|
|
572
639
|
children: annotating ? t("cancelAnnotate") : t("annotate")
|
|
@@ -603,12 +670,13 @@ window.__ModuleLoader__.load({
|
|
|
603
670
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
604
671
|
type: "button",
|
|
605
672
|
className: "niv-button",
|
|
673
|
+
disabled: imageState !== "ready",
|
|
606
674
|
onClick: actual,
|
|
607
675
|
children: t("actual")
|
|
608
676
|
}),
|
|
609
677
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
610
678
|
className: "niv-zoom",
|
|
611
|
-
children: [Math.round(transform.zoom * 100), "%"]
|
|
679
|
+
children: [Math.round(transform.zoom * pixelScale * 100), "%"]
|
|
612
680
|
}),
|
|
613
681
|
item.download === void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("a", {
|
|
614
682
|
className: "niv-download",
|
|
@@ -622,13 +690,13 @@ window.__ModuleLoader__.load({
|
|
|
622
690
|
download: item.download,
|
|
623
691
|
item,
|
|
624
692
|
t
|
|
625
|
-
}),
|
|
693
|
+
}, item.src),
|
|
626
694
|
item.actions.map((action) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ViewerAction, {
|
|
627
695
|
action,
|
|
628
696
|
annotations,
|
|
629
697
|
item,
|
|
630
698
|
service
|
|
631
|
-
}, action.id))
|
|
699
|
+
}, `${item.src}:${action.id}`))
|
|
632
700
|
]
|
|
633
701
|
})
|
|
634
702
|
}),
|
|
@@ -649,133 +717,155 @@ window.__ModuleLoader__.load({
|
|
|
649
717
|
onClick: (event) => {
|
|
650
718
|
if (event.target === event.currentTarget && !annotating && transform.zoom === 1) service.close();
|
|
651
719
|
},
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
onPointerCancel: endPointer,
|
|
656
|
-
onDoubleClick: () => {
|
|
720
|
+
...!annotating && imageState === "ready" ? pointerHandlers : {},
|
|
721
|
+
onDoubleClick: (event) => {
|
|
722
|
+
if (event.target.closest("button,a,input,textarea") || imageState !== "ready") return;
|
|
657
723
|
if (transform.zoom === 1) actual();
|
|
658
724
|
else fit();
|
|
659
725
|
},
|
|
660
|
-
children: [
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
726
|
+
children: [
|
|
727
|
+
imageState !== "ready" ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
728
|
+
className: "niv-load-status",
|
|
729
|
+
role: imageState === "error" ? "alert" : "status",
|
|
730
|
+
children: [t(imageState === "error" ? "loadFailed" : "loading"), imageState === "error" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
731
|
+
type: "button",
|
|
732
|
+
className: "niv-button",
|
|
733
|
+
onClick: () => {
|
|
734
|
+
setImageState("loading");
|
|
735
|
+
setAttempt((value) => value + 1);
|
|
736
|
+
},
|
|
737
|
+
children: t("retry")
|
|
738
|
+
}) : null]
|
|
739
|
+
}) : null,
|
|
740
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
741
|
+
ref: surfaceRef,
|
|
742
|
+
className: "niv-surface",
|
|
743
|
+
onClick: addAnnotation,
|
|
675
744
|
style: {
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
transform: `translate(-50%,-50%) scale(${1 / transform.zoom})`
|
|
745
|
+
visibility: imageState === "ready" ? "visible" : "hidden",
|
|
746
|
+
transform: `translate3d(${transform.x}px,${transform.y}px,0) scale(${transform.zoom})`
|
|
679
747
|
},
|
|
680
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("
|
|
748
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("img", {
|
|
749
|
+
ref: imageRef,
|
|
750
|
+
className: "niv-image",
|
|
751
|
+
src: item.src,
|
|
752
|
+
alt: item.name,
|
|
753
|
+
draggable: "false",
|
|
754
|
+
onLoad: () => {
|
|
755
|
+
setImageState("ready");
|
|
756
|
+
measure();
|
|
757
|
+
},
|
|
758
|
+
onError: () => setImageState("error")
|
|
759
|
+
}, `${request.revision}:${item.id}:${attempt}`), annotations.map((annotation, position) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
760
|
+
className: "niv-annotation",
|
|
761
|
+
"data-x": annotation.x < .38 ? "right" : annotation.x > .62 ? "left" : "center",
|
|
762
|
+
"data-y": annotation.y < .28 ? "down" : "up",
|
|
763
|
+
style: {
|
|
764
|
+
left: `${annotation.x * 100}%`,
|
|
765
|
+
top: `${annotation.y * 100}%`,
|
|
766
|
+
transform: `translate(-50%,-50%) scale(${1 / transform.zoom})`
|
|
767
|
+
},
|
|
768
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
769
|
+
type: "button",
|
|
770
|
+
className: "niv-pin",
|
|
771
|
+
"data-active": selected === annotation.id,
|
|
772
|
+
"aria-label": fill(t("note"), { value: position + 1 }),
|
|
773
|
+
onClick: (event) => {
|
|
774
|
+
event.stopPropagation();
|
|
775
|
+
const opening = selected !== annotation.id;
|
|
776
|
+
setSelected(opening ? annotation.id : void 0);
|
|
777
|
+
if (opening) setFocusNote(annotation.id);
|
|
778
|
+
},
|
|
779
|
+
children: position + 1
|
|
780
|
+
}), selected === annotation.id ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
781
|
+
className: "niv-inline-note",
|
|
782
|
+
"data-note-id": annotation.id,
|
|
783
|
+
onClick: (event) => event.stopPropagation(),
|
|
784
|
+
children: [
|
|
785
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
786
|
+
className: "niv-inline-index",
|
|
787
|
+
children: position + 1
|
|
788
|
+
}),
|
|
789
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("textarea", {
|
|
790
|
+
value: annotation.note,
|
|
791
|
+
rows: 1,
|
|
792
|
+
"aria-label": fill(t("note"), { value: position + 1 }),
|
|
793
|
+
placeholder: t("notePlaceholder"),
|
|
794
|
+
onChange: (event) => {
|
|
795
|
+
const note = event.target.value;
|
|
796
|
+
setAnnotations((current) => current.map((entry) => entry.id === annotation.id ? {
|
|
797
|
+
...entry,
|
|
798
|
+
note
|
|
799
|
+
} : entry));
|
|
800
|
+
},
|
|
801
|
+
onKeyDown: (event) => {
|
|
802
|
+
if (event.key === "Enter" && !event.shiftKey || event.key === "Escape") {
|
|
803
|
+
event.preventDefault();
|
|
804
|
+
event.stopPropagation();
|
|
805
|
+
event.nativeEvent?.stopImmediatePropagation?.();
|
|
806
|
+
setSelected(void 0);
|
|
807
|
+
}
|
|
808
|
+
}
|
|
809
|
+
}),
|
|
810
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
811
|
+
type: "button",
|
|
812
|
+
className: "niv-note-remove",
|
|
813
|
+
"aria-label": t("removeNote"),
|
|
814
|
+
onClick: (event) => {
|
|
815
|
+
event.stopPropagation();
|
|
816
|
+
setAnnotations((current) => current.filter((entry) => entry.id !== annotation.id));
|
|
817
|
+
setSelected(void 0);
|
|
818
|
+
},
|
|
819
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconCloseOutline16, {})
|
|
820
|
+
})
|
|
821
|
+
]
|
|
822
|
+
}) : null]
|
|
823
|
+
}, annotation.id))]
|
|
824
|
+
}),
|
|
825
|
+
showCounter ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
|
|
826
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
827
|
+
type: "button",
|
|
828
|
+
className: "niv-button niv-icon-only niv-nav niv-prev",
|
|
829
|
+
"aria-label": t("previous"),
|
|
830
|
+
onClick: (event) => {
|
|
831
|
+
event.stopPropagation();
|
|
832
|
+
setIndex((value) => (value - 1 + request.items.length) % request.items.length);
|
|
833
|
+
},
|
|
834
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconChevronLeftOutline14, {})
|
|
835
|
+
}),
|
|
836
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
681
837
|
type: "button",
|
|
682
|
-
className: "niv-
|
|
683
|
-
"
|
|
684
|
-
"aria-label": fill(t("note"), { value: position + 1 }),
|
|
838
|
+
className: "niv-button niv-icon-only niv-nav niv-next",
|
|
839
|
+
"aria-label": t("next"),
|
|
685
840
|
onClick: (event) => {
|
|
686
841
|
event.stopPropagation();
|
|
687
|
-
|
|
688
|
-
setSelected(opening ? annotation.id : void 0);
|
|
689
|
-
if (opening) setFocusNote(annotation.id);
|
|
842
|
+
setIndex((value) => (value + 1) % request.items.length);
|
|
690
843
|
},
|
|
691
|
-
children:
|
|
692
|
-
}),
|
|
693
|
-
|
|
694
|
-
"
|
|
695
|
-
onClick: (event) => event.stopPropagation(),
|
|
844
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconChevronRightOutline14, {})
|
|
845
|
+
}),
|
|
846
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
847
|
+
className: "niv-counter",
|
|
696
848
|
children: [
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
}),
|
|
701
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("textarea", {
|
|
702
|
-
value: annotation.note,
|
|
703
|
-
rows: 1,
|
|
704
|
-
"aria-label": fill(t("note"), { value: position + 1 }),
|
|
705
|
-
placeholder: t("notePlaceholder"),
|
|
706
|
-
onChange: (event) => {
|
|
707
|
-
const note = event.target.value;
|
|
708
|
-
setAnnotations((current) => current.map((entry) => entry.id === annotation.id ? {
|
|
709
|
-
...entry,
|
|
710
|
-
note
|
|
711
|
-
} : entry));
|
|
712
|
-
},
|
|
713
|
-
onKeyDown: (event) => {
|
|
714
|
-
if (event.key === "Enter" && !event.shiftKey || event.key === "Escape") {
|
|
715
|
-
event.preventDefault();
|
|
716
|
-
event.stopPropagation();
|
|
717
|
-
event.nativeEvent?.stopImmediatePropagation?.();
|
|
718
|
-
setSelected(void 0);
|
|
719
|
-
}
|
|
720
|
-
}
|
|
721
|
-
}),
|
|
722
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
723
|
-
type: "button",
|
|
724
|
-
className: "niv-note-remove",
|
|
725
|
-
"aria-label": t("removeNote"),
|
|
726
|
-
onClick: (event) => {
|
|
727
|
-
event.stopPropagation();
|
|
728
|
-
setAnnotations((current) => current.filter((entry) => entry.id !== annotation.id));
|
|
729
|
-
setSelected(void 0);
|
|
730
|
-
},
|
|
731
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconCloseOutline16, {})
|
|
732
|
-
})
|
|
849
|
+
index + 1,
|
|
850
|
+
" / ",
|
|
851
|
+
request.items.length
|
|
733
852
|
]
|
|
734
|
-
})
|
|
735
|
-
},
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
className: "niv-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
setIndex((value) => (value - 1 + request.items.length) % request.items.length);
|
|
744
|
-
},
|
|
745
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconChevronLeftOutline14, {})
|
|
746
|
-
}),
|
|
747
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
748
|
-
type: "button",
|
|
749
|
-
className: "niv-button niv-icon-only niv-nav niv-next",
|
|
750
|
-
"aria-label": t("next"),
|
|
751
|
-
onClick: (event) => {
|
|
752
|
-
event.stopPropagation();
|
|
753
|
-
setIndex((value) => (value + 1) % request.items.length);
|
|
754
|
-
},
|
|
755
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconChevronRightOutline14, {})
|
|
756
|
-
}),
|
|
757
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
758
|
-
className: "niv-counter",
|
|
759
|
-
children: [
|
|
760
|
-
index + 1,
|
|
761
|
-
" / ",
|
|
762
|
-
request.items.length
|
|
763
|
-
]
|
|
764
|
-
})
|
|
765
|
-
] }) : annotating ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
766
|
-
className: "niv-hint",
|
|
767
|
-
children: t("regionHint")
|
|
768
|
-
}) : transform.zoom === 1 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
769
|
-
className: "niv-hint",
|
|
770
|
-
children: t("zoomHint")
|
|
771
|
-
}) : null]
|
|
853
|
+
})
|
|
854
|
+
] }) : annotating ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
855
|
+
className: "niv-hint",
|
|
856
|
+
children: t("regionHint")
|
|
857
|
+
}) : transform.zoom === 1 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
858
|
+
className: "niv-hint",
|
|
859
|
+
children: t("zoomHint")
|
|
860
|
+
}) : null
|
|
861
|
+
]
|
|
772
862
|
}), annotations.some((annotation) => annotation.note.trim() !== "") ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
773
863
|
type: "button",
|
|
774
864
|
className: "niv-copy-notes",
|
|
775
865
|
onClick: () => {
|
|
776
866
|
copyNotes();
|
|
777
867
|
},
|
|
778
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconCopyOutline16, {}), copied ? t("copied") : t("copyNotes")]
|
|
868
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconCopyOutline16, {}), copyFailed ? t("copyFailed") : copied ? t("copied") : t("copyNotes")]
|
|
779
869
|
}) : null]
|
|
780
870
|
})
|
|
781
871
|
]
|
package/lib/client.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.js","names":["#listeners","#snapshot","#annotationsByImage","#revision","#emit","CSS","IconDownloadOutline16","IconEditOutline16","IconFullscreenOutline16","IconCloseOutline16","IconChevronLeftOutline14","IconChevronRightOutline14","IconCopyOutline16","VIEWER_CSS"],"sources":["../src/viewer.js","../src/styles.js","../src/client.jsx"],"sourcesContent":["const boundedNumber = (value, fallback) => Number.isFinite(value) && value > 0 ? value : fallback\nconst downloadOf = value => typeof value?.onInvoke === 'function' ? {\n pendingLabel: typeof value.pendingLabel === 'string' && value.pendingLabel !== '' ? value.pendingLabel : undefined,\n errorLabel: typeof value.errorLabel === 'string' && value.errorLabel !== '' ? value.errorLabel : undefined,\n onInvoke: value.onInvoke,\n} : undefined\nconst actionsOf = value => Array.isArray(value) ? value.flatMap((action, position) => {\n if (typeof action?.onInvoke !== 'function' || typeof action?.label !== 'string' || action.label.trim() === '') return []\n return [{\n id: typeof action.id === 'string' && action.id !== '' ? action.id : `action-${position + 1}`,\n label: action.label,\n pendingLabel: typeof action.pendingLabel === 'string' && action.pendingLabel !== '' ? action.pendingLabel : action.label,\n errorLabel: typeof action.errorLabel === 'string' && action.errorLabel !== '' ? action.errorLabel : action.label,\n closeOnSuccess: action.closeOnSuccess === true,\n onInvoke: action.onInvoke,\n }]\n}) : []\n\nexport function normalizeViewerRequest(request) {\n const rawItems = Array.isArray(request?.items) ? request.items : []\n const items = rawItems.flatMap((item, position) => {\n if (typeof item?.src !== 'string' || item.src === '') return []\n return [{\n id: typeof item.id === 'string' && item.id !== '' ? item.id : `image-${position + 1}`,\n src: item.src,\n name: typeof item.name === 'string' && item.name !== '' ? item.name : `Image ${position + 1}`,\n width: boundedNumber(item.width, undefined),\n height: boundedNumber(item.height, undefined),\n bytes: boundedNumber(item.bytes, undefined),\n download: downloadOf(item.download),\n actions: actionsOf(item.actions),\n }]\n })\n if (items.length === 0) return undefined\n const requestedIndex = Number.isInteger(request?.index) ? request.index : 0\n return {\n items,\n index: Math.max(0, Math.min(items.length - 1, requestedIndex)),\n opener: typeof HTMLElement !== 'undefined' && request?.opener instanceof HTMLElement ? request.opener : undefined,\n source: typeof request?.source === 'string' ? request.source : 'dsh',\n annotations: request?.annotations !== false,\n }\n}\n\nexport class NativeImageViewerService {\n #listeners = new Set()\n #revision = 0\n #snapshot\n #annotationsByImage = new Map()\n\n constructor() {\n this.subscribe = listener => {\n this.#listeners.add(listener)\n return () => { this.#listeners.delete(listener) }\n }\n this.getSnapshot = () => this.#snapshot\n this.getAnnotationsSnapshot = () => Object.fromEntries(\n [...this.#annotationsByImage].map(([id, annotations]) => [id, annotations.map(annotation => ({ ...annotation }))]),\n )\n }\n\n setAnnotations(imageId, annotations) {\n if (typeof imageId !== 'string' || imageId === '' || !Array.isArray(annotations)) return\n if (annotations.length === 0) this.#annotationsByImage.delete(imageId)\n else this.#annotationsByImage.set(imageId, annotations.map(annotation => ({ ...annotation })))\n }\n\n open(request) {\n const normalized = normalizeViewerRequest(request)\n if (normalized === undefined) return false\n this.#revision += 1\n this.#snapshot = { ...normalized, revision: this.#revision }\n this.#emit()\n return true\n }\n\n close() {\n if (this.#snapshot === undefined) return\n const opener = this.#snapshot.opener\n this.#snapshot = undefined\n this.#emit()\n if (typeof window === 'undefined') opener?.focus()\n else window.requestAnimationFrame(() => { opener?.focus() })\n }\n\n #emit() {\n for (const listener of this.#listeners) listener()\n }\n}\n\nexport function nativeImageButton(target) {\n if (!(target instanceof Element)) return undefined\n const button = target.closest('button')\n if (!(button instanceof HTMLButtonElement)) return undefined\n const image = button.querySelector(':scope > img')\n if (!(image instanceof HTMLImageElement) || image.currentSrc === '') return undefined\n if (button.matches('[data-variant=\"single\"],[data-variant=\"tile\"]')) return { button, image, group: button.parentElement }\n const rail = button.closest('[role=\"group\"]')\n if (rail !== null && button.hasAttribute('title')) return { button, image, group: rail }\n return undefined\n}\n\nexport function imageItemsForButton(match) {\n const buttons = match.group?.querySelectorAll('button[data-variant=\"single\"],button[data-variant=\"tile\"],button[title]')\n ?? []\n const candidates = [...buttons].flatMap((button, index) => {\n const image = button.querySelector(':scope > img')\n if (!(image instanceof HTMLImageElement) || image.currentSrc === '') return []\n return [{\n id: image.currentSrc,\n src: image.currentSrc,\n name: image.alt || `Image ${index + 1}`,\n width: image.naturalWidth || undefined,\n height: image.naturalHeight || undefined,\n button,\n }]\n })\n const items = candidates.length > 0 ? candidates : [{\n id: match.image.currentSrc,\n src: match.image.currentSrc,\n name: match.image.alt || 'Image',\n width: match.image.naturalWidth || undefined,\n height: match.image.naturalHeight || undefined,\n button: match.button,\n }]\n const index = Math.max(0, items.findIndex(item => item.button === match.button))\n return { items: items.map(({ button: _button, ...item }) => item), index }\n}\n","export const CSS = String.raw`\n.niv-root{position:fixed;inset:0;z-index:1000;pointer-events:auto;overflow:hidden;background:rgba(7,8,10,.68);color:var(--dsw-alias-label-primary-inverted,#fff);outline:0;backdrop-filter:blur(13px) saturate(.72);-webkit-backdrop-filter:blur(13px) saturate(.72)}\n.niv-sr-only{position:absolute!important;width:1px!important;height:1px!important;padding:0!important;margin:-1px!important;overflow:hidden!important;clip:rect(0,0,0,0)!important;white-space:nowrap!important;border:0!important}\n.niv-topbar{position:absolute;right:50%;bottom:22px;z-index:6;max-width:calc(100vw - 36px);padding:5px;border:1px solid rgba(255,255,255,.12);border-radius:999px;background:rgba(38,39,43,.86);box-shadow:0 10px 34px rgba(0,0,0,.3);transform:translateX(50%);backdrop-filter:blur(18px);-webkit-backdrop-filter:blur(18px)}\n.niv-actions{display:flex;align-items:center;gap:2px;overflow-x:auto;scrollbar-width:none}.niv-actions::-webkit-scrollbar{display:none}.niv-button,.niv-download{box-sizing:border-box;display:inline-flex;align-items:center;justify-content:center;gap:6px;height:32px;padding:0 10px;border:0;border-radius:999px;background:transparent;color:rgba(255,255,255,.9);font:inherit;font-size:12px;text-decoration:none;white-space:nowrap;cursor:pointer}.niv-button:hover,.niv-download:hover,.niv-button[data-active=true]{background:rgba(255,255,255,.12)}.niv-button:focus-visible,.niv-download:focus-visible,.niv-close-floating:focus-visible{outline:2px solid rgba(255,255,255,.9);outline-offset:2px}.niv-button:disabled,.niv-download:disabled{opacity:.38;cursor:default}.niv-icon-only{width:32px;padding:0}.niv-zoom{min-width:44px;color:rgba(255,255,255,.68);font-size:12px;font-variant-numeric:tabular-nums;text-align:center}\n.niv-close-floating{position:absolute;top:20px;right:20px;z-index:8;display:grid;place-items:center;width:42px;height:42px;padding:0;border:1px solid rgba(255,255,255,.1);border-radius:50%;background:rgba(48,49,53,.82);box-shadow:0 8px 24px rgba(0,0,0,.28);color:#fff;cursor:pointer;backdrop-filter:blur(16px);-webkit-backdrop-filter:blur(16px)}.niv-close-floating:hover{background:rgba(66,67,72,.92)}\n.niv-workspace{position:absolute;inset:0;display:grid;min-width:0;min-height:0;padding:68px 24px 72px;box-sizing:border-box}\n.niv-stage{position:relative;display:grid;place-items:center;min-width:0;min-height:0;overflow:hidden;padding:0;touch-action:none;user-select:none}.niv-stage[data-dragging=true]{cursor:grabbing}.niv-stage[data-annotating=true]{cursor:crosshair}\n.niv-surface{position:relative;display:inline-flex;max-width:100%;max-height:100%;transform-origin:center;will-change:transform}.niv-image{display:block;max-width:calc(100vw - 72px);max-height:calc(100vh - 154px);border-radius:12px;object-fit:contain;box-shadow:0 22px 60px rgba(0,0,0,.46);user-select:none;-webkit-user-drag:none}\n.niv-annotation{position:absolute;z-index:5;width:24px;height:24px;transform-origin:center;pointer-events:none}.niv-pin{position:absolute;inset:0;display:grid;place-items:center;width:24px;height:24px;padding:0;border:2px solid #fff;border-radius:50%;background:rgba(23,24,27,.94);box-shadow:0 4px 16px rgba(0,0,0,.35);color:#fff;font:inherit;font-size:11px;font-weight:700;cursor:pointer;pointer-events:auto}.niv-pin[data-active=true]{background:var(--dsw-alias-state-business-primary,#3964fe)}\n.niv-inline-note{position:absolute;bottom:34px;box-sizing:border-box;display:grid;width:min(300px,calc(100vw - 40px));grid-template-columns:24px minmax(0,1fr) 24px;align-items:center;gap:7px;padding:7px 8px;border:1px solid rgba(255,255,255,.12);border-radius:18px;background:rgba(32,33,37,.94);box-shadow:0 14px 38px rgba(0,0,0,.38);color:#fff;pointer-events:auto;backdrop-filter:blur(20px);-webkit-backdrop-filter:blur(20px)}.niv-annotation[data-x=right] .niv-inline-note{left:-8px}.niv-annotation[data-x=left] .niv-inline-note{right:-8px}.niv-annotation[data-x=center] .niv-inline-note{left:50%;transform:translateX(-50%)}.niv-annotation[data-y=down] .niv-inline-note{top:34px;bottom:auto}.niv-inline-note::after{position:absolute;width:9px;height:9px;background:rgba(32,33,37,.94);content:'';transform:rotate(45deg)}.niv-annotation[data-y=up] .niv-inline-note::after{bottom:-5px}.niv-annotation[data-y=down] .niv-inline-note::after{top:-5px}.niv-annotation[data-x=right] .niv-inline-note::after{left:13px}.niv-annotation[data-x=left] .niv-inline-note::after{right:13px}.niv-annotation[data-x=center] .niv-inline-note::after{left:calc(50% - 4px)}.niv-inline-index{display:grid;place-items:center;width:22px;height:22px;border-radius:50%;background:var(--dsw-alias-state-business-primary,#3964fe);color:#fff;font-size:10px;font-weight:700}.niv-inline-note textarea{box-sizing:border-box;width:100%;min-height:24px;max-height:92px;resize:none;overflow:auto;border:0;outline:0;background:transparent;color:#fff;font:inherit;font-size:12px;line-height:18px}.niv-inline-note textarea::placeholder{color:rgba(255,255,255,.44)}.niv-note-remove{display:grid;place-items:center;width:24px;height:24px;padding:0;border:0;border-radius:50%;background:transparent;color:rgba(255,255,255,.68);cursor:pointer}.niv-note-remove:hover{background:rgba(255,255,255,.1);color:#fff}\n.niv-nav{position:absolute;top:50%;z-index:4;width:42px;height:42px;padding:0;transform:translateY(-50%);background:rgba(48,49,53,.82);box-shadow:0 8px 24px rgba(0,0,0,.28);backdrop-filter:blur(16px)}.niv-prev{left:6px}.niv-next{right:6px}.niv-counter{position:absolute;bottom:8px;left:50%;padding:5px 10px;border-radius:999px;background:rgba(38,39,43,.86);color:rgba(255,255,255,.72);font-size:11px;transform:translateX(-50%);backdrop-filter:blur(16px)}\n.niv-hint{display:none}\n.niv-copy-notes{position:absolute;right:20px;bottom:22px;z-index:6;display:inline-flex;align-items:center;gap:6px;height:32px;padding:0 11px;border:1px solid rgba(255,255,255,.1);border-radius:999px;background:rgba(38,39,43,.86);color:rgba(255,255,255,.82);font:inherit;font-size:12px;cursor:pointer;backdrop-filter:blur(16px)}\n@media(max-width:760px){.niv-close-floating{top:12px;right:12px;width:40px;height:40px}.niv-workspace{padding:60px 12px 68px}.niv-image{max-width:calc(100vw - 24px);max-height:calc(100vh - 136px)}.niv-topbar{bottom:12px;max-width:calc(100vw - 24px)}.niv-button{padding:0 8px}.niv-button span.niv-label{display:none}.niv-inline-note{width:min(260px,calc(100vw - 40px))}.niv-copy-notes{display:none}}\n@media(prefers-reduced-motion:reduce){.niv-surface{transition:none}}\n`\n","import {\n useCallback, useEffect, useMemo, useRef, useState, useSyncExternalStore,\n} from 'react'\nimport {\n IconChevronLeftOutline14, IconChevronRightOutline14, IconCloseOutline16,\n IconCopyOutline16, IconDownloadOutline16, IconEditOutline16, IconFullscreenOutline16,\n} from '@deepseek-ai/dsh-client-ui-primitives'\nimport {\n imageItemsForButton, NativeImageViewerService, nativeImageButton,\n} from './viewer.js'\nimport { CSS as VIEWER_CSS } from './styles.js'\n\nexport const name = 'dsh-image-viewer'\nexport const inject = ['locale', 'slots']\n\nconst LOCALES = {\n en: {\n dialog: 'Image viewer', close: 'Close', fit: 'Fit', actual: '100%', download: 'Download',\n annotate: 'Mark region', cancelAnnotate: 'Cancel marking', regions: 'Region notes', regionHint: 'Click a point on the image, then add a note.',\n note: 'Region {value}', notePlaceholder: 'Describe what should change here…', removeNote: 'Remove region note',\n hideNotes: 'Hide notes', copyNotes: 'Copy notes', copied: 'Copied', previous: 'Previous image', next: 'Next image',\n zoomHint: 'Wheel to zoom · drag to pan · double-click for 100%', preparing: 'Preparing…', failed: 'Could not prepare this image.',\n },\n zh: {\n dialog: '图片查看器', close: '关闭', fit: '适应窗口', actual: '原始大小', download: '下载',\n annotate: '标记区域', cancelAnnotate: '取消标记', regions: '区域备注', regionHint: '点击图片中的位置,然后填写备注。',\n note: '区域 {value}', notePlaceholder: '描述这里需要怎样调整…', removeNote: '删除区域备注',\n hideNotes: '收起备注', copyNotes: '复制备注', copied: '已复制', previous: '上一张图片', next: '下一张图片',\n zoomHint: '滚轮缩放 · 拖动查看 · 双击切换原始大小', preparing: '正在准备…', failed: '暂时无法准备这张图片。',\n },\n}\n\nconst fill = (value, variables) => Object.entries(variables).reduce(\n (text, [key, replacement]) => text.replaceAll(`{${key}}`, String(replacement)),\n value,\n)\nconst clamp = (value, min, max) => Math.min(max, Math.max(min, value))\nconst bytesLabel = bytes => bytes === undefined ? undefined : bytes < 1024 * 1024\n ? `${Math.max(0.1, bytes / 1024).toLocaleString(undefined, { maximumFractionDigits: 1 })} KB`\n : `${(bytes / 1024 / 1024).toLocaleString(undefined, { maximumFractionDigits: 1 })} MB`\nconst downloadName = name => {\n const cleaned = String(name || 'image.png').replace(/[<>:\"/\\\\|?*\\u0000-\\u001f]/gu, '-').replace(/[. ]+$/u, '').trim()\n return cleaned === '' ? 'image.png' : cleaned\n}\nconst noteText = (annotations, t) => annotations.map((annotation, index) => {\n const label = fill(t('note'), { value: index + 1 })\n return `${label} (${Math.round(annotation.x * 100)}%, ${Math.round(annotation.y * 100)}%): ${annotation.note.trim()}`\n}).filter(line => !line.endsWith(': ')).join('\\n')\n\nfunction ViewerAction({ action, annotations, item, service }) {\n const [state, setState] = useState('idle')\n const invoke = async () => {\n if (state === 'pending') return\n setState('pending')\n try {\n await action.onInvoke({ annotations, item, src: item.src })\n setState('idle')\n if (action.closeOnSuccess) service.close()\n } catch { setState('failed') }\n }\n const label = state === 'pending' ? action.pendingLabel : state === 'failed' ? action.errorLabel : action.label\n return <button type=\"button\" className=\"niv-button\" disabled={state === 'pending'} onClick={() => { void invoke() }}><span className=\"niv-label\">{label}</span></button>\n}\n\nfunction ViewerDownload({ download, item, t }) {\n const [state, setState] = useState('idle')\n const invoke = async () => {\n if (state === 'pending') return\n setState('pending')\n try { await download.onInvoke({ item, src: item.src }); setState('idle') } catch { setState('failed') }\n }\n const label = state === 'pending' ? download.pendingLabel ?? t('preparing') : state === 'failed' ? download.errorLabel ?? t('failed') : t('download')\n return <button type=\"button\" className=\"niv-download\" disabled={state === 'pending'} onClick={() => { void invoke() }}><IconDownloadOutline16 /><span className=\"niv-label\">{label}</span></button>\n}\n\nfunction ViewerOverlay({ service, t }) {\n const request = useSyncExternalStore(service.subscribe, service.getSnapshot)\n const [index, setIndex] = useState(0)\n const [transform, setTransform] = useState({ zoom: 1, x: 0, y: 0 })\n const [dragging, setDragging] = useState(false)\n const [annotating, setAnnotating] = useState(false)\n const [annotationsByImage, setAnnotationsByImage] = useState(service.getAnnotationsSnapshot)\n const annotationsByImageRef = useRef(annotationsByImage)\n const [selected, setSelected] = useState()\n const [focusNote, setFocusNote] = useState()\n const [copied, setCopied] = useState(false)\n const rootRef = useRef(null)\n const stageRef = useRef(null)\n const surfaceRef = useRef(null)\n const imageRef = useRef(null)\n const pointersRef = useRef(new Map())\n const gestureRef = useRef()\n const transformRef = useRef(transform)\n transformRef.current = transform\n annotationsByImageRef.current = annotationsByImage\n\n useEffect(() => {\n if (request === undefined) return\n setIndex(request.index)\n setTransform({ zoom: 1, x: 0, y: 0 })\n setDragging(false)\n setAnnotating(false)\n setSelected(undefined)\n setCopied(false)\n }, [request?.revision])\n\n const item = request?.items[index]\n const annotations = item === undefined ? [] : annotationsByImage[item.id] ?? []\n const setAnnotations = useCallback((update) => {\n if (item === undefined) return\n const previous = annotationsByImageRef.current[item.id] ?? []\n const next = typeof update === 'function' ? update(previous) : update\n const snapshot = { ...annotationsByImageRef.current, [item.id]: next }\n annotationsByImageRef.current = snapshot\n service.setAnnotations(item.id, next)\n setAnnotationsByImage(snapshot)\n }, [item?.id, service])\n\n const boundedPan = useCallback((zoom, x, y) => {\n const stage = stageRef.current\n const surface = surfaceRef.current\n if (stage === null || surface === null || zoom <= 1) return { x: 0, y: 0 }\n const limitX = Math.max(0, (surface.offsetWidth * zoom - stage.clientWidth) / 2) + 28\n const limitY = Math.max(0, (surface.offsetHeight * zoom - stage.clientHeight) / 2) + 28\n return { x: clamp(x, -limitX, limitX), y: clamp(y, -limitY, limitY) }\n }, [])\n\n const setZoomAt = useCallback((nextZoom, clientX, clientY) => {\n const stage = stageRef.current\n if (stage === null) return\n setTransform(current => {\n const next = clamp(nextZoom, 0.5, 8)\n const box = stage.getBoundingClientRect()\n const px = clientX - box.left - box.width / 2\n const py = clientY - box.top - box.height / 2\n const ratio = next / current.zoom\n const pan = boundedPan(next, px - (px - current.x) * ratio, py - (py - current.y) * ratio)\n return { zoom: next, ...pan }\n })\n }, [boundedPan])\n\n const fit = useCallback(() => { setTransform({ zoom: 1, x: 0, y: 0 }) }, [])\n const actual = useCallback(() => {\n const image = imageRef.current\n const surface = surfaceRef.current\n if (image === null || surface === null || image.naturalWidth === 0) return\n const zoom = clamp(image.naturalWidth / Math.max(1, surface.offsetWidth), 1, 8)\n setTransform({ zoom, x: 0, y: 0 })\n }, [])\n\n useEffect(() => {\n if (request === undefined) return undefined\n const previousOverflow = document.body.style.overflow\n document.body.style.overflow = 'hidden'\n rootRef.current?.focus()\n const onKeyDown = event => {\n if (event.key === 'Escape') {\n event.preventDefault()\n if (event.target instanceof Element && event.target.closest('.niv-inline-note') !== null) {\n setSelected(undefined)\n return\n }\n service.close()\n return\n }\n const editing = event.target instanceof HTMLInputElement || event.target instanceof HTMLTextAreaElement\n if (!editing && event.key === 'ArrowLeft' && request.items.length > 1) {\n event.preventDefault(); setIndex(value => (value - 1 + request.items.length) % request.items.length)\n } else if (!editing && event.key === 'ArrowRight' && request.items.length > 1) {\n event.preventDefault(); setIndex(value => (value + 1) % request.items.length)\n } else if (!editing && (event.key === '+' || event.key === '=')) {\n event.preventDefault(); const box = stageRef.current?.getBoundingClientRect(); if (box) setZoomAt(transformRef.current.zoom * 1.2, box.left + box.width / 2, box.top + box.height / 2)\n } else if (!editing && event.key === '-') {\n event.preventDefault(); const box = stageRef.current?.getBoundingClientRect(); if (box) setZoomAt(transformRef.current.zoom / 1.2, box.left + box.width / 2, box.top + box.height / 2)\n } else if (!editing && event.key.toLowerCase() === 'f') {\n event.preventDefault(); fit()\n } else if (event.key === 'Tab') {\n const controls = [...rootRef.current.querySelectorAll('button:not(:disabled),a[href],input:not(:disabled),textarea:not(:disabled),[tabindex]:not([tabindex=\"-1\"])')]\n const first = controls[0]\n const last = controls.at(-1)\n if (event.shiftKey && document.activeElement === first) { event.preventDefault(); last?.focus() }\n else if (!event.shiftKey && document.activeElement === last) { event.preventDefault(); first?.focus() }\n }\n }\n document.addEventListener('keydown', onKeyDown)\n return () => {\n document.body.style.overflow = previousOverflow\n document.removeEventListener('keydown', onKeyDown)\n }\n }, [request, service, fit, setZoomAt])\n\n useEffect(() => {\n if (focusNote === undefined) return\n const field = rootRef.current?.querySelector(`[data-note-id=\"${CSS.escape(focusNote)}\"] textarea`)\n field?.focus()\n setFocusNote(undefined)\n }, [focusNote, selected, annotations.length])\n\n useEffect(() => {\n setTransform({ zoom: 1, x: 0, y: 0 })\n setDragging(false)\n setAnnotating(false)\n setSelected(undefined)\n }, [item?.id])\n\n const onWheel = useCallback(event => {\n event.preventDefault()\n setZoomAt(transformRef.current.zoom * Math.exp(-event.deltaY * 0.0015), event.clientX, event.clientY)\n }, [setZoomAt])\n useEffect(() => {\n const stage = stageRef.current\n if (stage === null || request === undefined) return undefined\n stage.addEventListener('wheel', onWheel, { passive: false })\n return () => stage.removeEventListener('wheel', onWheel)\n }, [onWheel, request])\n const onPointerDown = event => {\n if (event.button !== 0 || annotating) return\n if (event.target instanceof Element && event.target.closest('button,a,input,textarea,select')) return\n if (event.pointerType === 'mouse' && transform.zoom <= 1) return\n event.currentTarget.setPointerCapture(event.pointerId)\n pointersRef.current.set(event.pointerId, { x: event.clientX, y: event.clientY })\n if (pointersRef.current.size === 2) {\n const [a, b] = [...pointersRef.current.values()]\n gestureRef.current = { kind: 'pinch', distance: Math.hypot(a.x - b.x, a.y - b.y), transform }\n } else if (!annotating && transform.zoom > 1) {\n gestureRef.current = { kind: 'pan', x: event.clientX, y: event.clientY, transform }\n setDragging(true)\n }\n }\n const onPointerMove = event => {\n if (!pointersRef.current.has(event.pointerId)) return\n pointersRef.current.set(event.pointerId, { x: event.clientX, y: event.clientY })\n const gesture = gestureRef.current\n if (gesture?.kind === 'pinch' && pointersRef.current.size >= 2) {\n const [a, b] = [...pointersRef.current.values()]\n const distance = Math.max(1, Math.hypot(a.x - b.x, a.y - b.y))\n setZoomAt(gesture.transform.zoom * distance / Math.max(1, gesture.distance), (a.x + b.x) / 2, (a.y + b.y) / 2)\n } else if (gesture?.kind === 'pan') {\n const pan = boundedPan(gesture.transform.zoom, gesture.transform.x + event.clientX - gesture.x, gesture.transform.y + event.clientY - gesture.y)\n setTransform({ zoom: gesture.transform.zoom, ...pan })\n }\n }\n const endPointer = event => {\n pointersRef.current.delete(event.pointerId)\n if (pointersRef.current.size === 0) { gestureRef.current = undefined; setDragging(false) }\n }\n const addAnnotation = event => {\n if (!annotating || event.target.closest('.niv-annotation')) return\n const bounds = surfaceRef.current?.getBoundingClientRect()\n if (bounds === undefined) return\n const annotation = {\n id: crypto.randomUUID(),\n x: clamp((event.clientX - bounds.left) / bounds.width, 0, 1),\n y: clamp((event.clientY - bounds.top) / bounds.height, 0, 1),\n note: '',\n }\n setAnnotations(current => [...current, annotation])\n setAnnotating(false)\n setSelected(annotation.id)\n setFocusNote(annotation.id)\n }\n const copyNotes = async () => {\n const text = noteText(annotations, t)\n if (text === '') return\n await navigator.clipboard.writeText(text)\n setCopied(true)\n window.setTimeout(() => { setCopied(false) }, 1200)\n }\n\n if (request === undefined || item === undefined) return null\n const meta = [item.width && item.height ? `${item.width} × ${item.height}` : undefined, bytesLabel(item.bytes)].filter(Boolean).join(' · ')\n const showCounter = request.items.length > 1\n return <div ref={rootRef} className=\"niv-root\" role=\"dialog\" aria-modal=\"true\" aria-label={t('dialog')} tabIndex={-1}>\n <div className=\"niv-title niv-sr-only\"><strong>{item.name}</strong>{meta !== '' ? <small>{meta}</small> : null}</div>\n <header className=\"niv-topbar\" role=\"toolbar\" aria-label={t('dialog')}>\n <div className=\"niv-actions\">\n {request.annotations ? <button type=\"button\" className=\"niv-button\" data-active={annotating} aria-label={annotating ? t('cancelAnnotate') : t('annotate')} aria-pressed={annotating} onClick={() => setAnnotating(value => !value)}><IconEditOutline16 /><span className=\"niv-label\">{annotating ? t('cancelAnnotate') : t('annotate')}</span></button> : null}\n {annotations.length > 0 ? <button type=\"button\" className=\"niv-button\" data-active={selected !== undefined} onClick={() => { const first = annotations[0]; setSelected(current => current === undefined ? first.id : undefined); if (selected === undefined) setFocusNote(first.id) }}>{annotations.length} <span className=\"niv-label\">{t('regions')}</span></button> : null}\n <button type=\"button\" className=\"niv-button\" aria-label={t('fit')} onClick={fit}><IconFullscreenOutline16 /><span className=\"niv-label\">{t('fit')}</span></button>\n <button type=\"button\" className=\"niv-button\" onClick={actual}>{t('actual')}</button>\n <span className=\"niv-zoom\">{Math.round(transform.zoom * 100)}%</span>\n {item.download === undefined\n ? <a className=\"niv-download\" href={item.src} download={downloadName(item.name)}><IconDownloadOutline16 /><span className=\"niv-label\">{t('download')}</span></a>\n : <ViewerDownload download={item.download} item={item} t={t} />}\n {item.actions.map(action => <ViewerAction action={action} annotations={annotations} item={item} service={service} key={action.id} />)}\n </div>\n </header>\n <button type=\"button\" className=\"niv-close-floating\" aria-label={t('close')} onClick={() => service.close()}><IconCloseOutline16 /></button>\n <div className=\"niv-workspace\">\n <main ref={stageRef} className=\"niv-stage\" data-dragging={dragging} data-annotating={annotating} onClick={event => { if (event.target === event.currentTarget && !annotating && transform.zoom === 1) service.close() }} onPointerDown={onPointerDown} onPointerMove={onPointerMove} onPointerUp={endPointer} onPointerCancel={endPointer} onDoubleClick={() => { if (transform.zoom === 1) actual(); else fit() }}>\n <div ref={surfaceRef} className=\"niv-surface\" onClick={addAnnotation} style={{ transform: `translate3d(${transform.x}px,${transform.y}px,0) scale(${transform.zoom})` }}>\n <img ref={imageRef} className=\"niv-image\" src={item.src} alt={item.name} draggable=\"false\" />\n {annotations.map((annotation, position) => <div className=\"niv-annotation\" data-x={annotation.x < 0.38 ? 'right' : annotation.x > 0.62 ? 'left' : 'center'} data-y={annotation.y < 0.28 ? 'down' : 'up'} style={{ left: `${annotation.x * 100}%`, top: `${annotation.y * 100}%`, transform: `translate(-50%,-50%) scale(${1 / transform.zoom})` }} key={annotation.id}>\n <button type=\"button\" className=\"niv-pin\" data-active={selected === annotation.id} aria-label={fill(t('note'), { value: position + 1 })} onClick={event => { event.stopPropagation(); const opening = selected !== annotation.id; setSelected(opening ? annotation.id : undefined); if (opening) setFocusNote(annotation.id) }}>{position + 1}</button>\n {selected === annotation.id ? <div className=\"niv-inline-note\" data-note-id={annotation.id} onClick={event => event.stopPropagation()}>\n <span className=\"niv-inline-index\">{position + 1}</span>\n <textarea value={annotation.note} rows={1} aria-label={fill(t('note'), { value: position + 1 })} placeholder={t('notePlaceholder')} onChange={event => { const note = event.target.value; setAnnotations(current => current.map(entry => entry.id === annotation.id ? { ...entry, note } : entry)) }} onKeyDown={event => {\n if ((event.key === 'Enter' && !event.shiftKey) || event.key === 'Escape') {\n event.preventDefault()\n event.stopPropagation()\n event.nativeEvent?.stopImmediatePropagation?.()\n setSelected(undefined)\n }\n }} />\n <button type=\"button\" className=\"niv-note-remove\" aria-label={t('removeNote')} onClick={event => { event.stopPropagation(); setAnnotations(current => current.filter(entry => entry.id !== annotation.id)); setSelected(undefined) }}><IconCloseOutline16 /></button>\n </div> : null}\n </div>)}\n </div>\n {showCounter ? <>\n <button type=\"button\" className=\"niv-button niv-icon-only niv-nav niv-prev\" aria-label={t('previous')} onClick={event => { event.stopPropagation(); setIndex(value => (value - 1 + request.items.length) % request.items.length) }}><IconChevronLeftOutline14 /></button>\n <button type=\"button\" className=\"niv-button niv-icon-only niv-nav niv-next\" aria-label={t('next')} onClick={event => { event.stopPropagation(); setIndex(value => (value + 1) % request.items.length) }}><IconChevronRightOutline14 /></button>\n <span className=\"niv-counter\">{index + 1} / {request.items.length}</span>\n </> : annotating ? <span className=\"niv-hint\">{t('regionHint')}</span> : transform.zoom === 1 ? <span className=\"niv-hint\">{t('zoomHint')}</span> : null}\n </main>\n {annotations.some(annotation => annotation.note.trim() !== '') ? <button type=\"button\" className=\"niv-copy-notes\" onClick={() => { void copyNotes() }}><IconCopyOutline16 />{copied ? t('copied') : t('copyNotes')}</button> : null}\n </div>\n </div>\n}\n\nfunction installOfficialImageBridge(service) {\n const onClick = event => {\n const match = nativeImageButton(event.target)\n if (match === undefined) return\n const { items, index } = imageItemsForButton(match)\n event.preventDefault()\n event.stopPropagation()\n event.stopImmediatePropagation()\n service.open({ items, index, opener: match.button, source: 'dsh-native', annotations: true })\n }\n document.addEventListener('click', onClick, true)\n return () => { document.removeEventListener('click', onClick, true) }\n}\n\nexport function apply(ctx) {\n const service = new NativeImageViewerService()\n ctx.effect(() => ctx.locale.register(name, LOCALES), `${name}: dictionaries`)\n ctx.effect(() => {\n const style = document.createElement('style')\n style.dataset.plugin = name\n style.textContent = VIEWER_CSS\n document.head.appendChild(style)\n return () => { style.remove() }\n }, `${name}: styles`)\n ctx.effect(() => {\n const disposeService = ctx.reflect.provide('nativeImageViewer', service)\n const disposeBridge = installOfficialImageBridge(service)\n return () => { disposeBridge(); void disposeService() }\n }, `${name}: optional viewer service and native image bridge`)\n const t = ctx.locale.bind(name)\n ctx.slots.inject('shell.overlay', () => ctx.slots.register({\n name: 'shell.overlay', id: name, order: 20, inject: () => ({ service, t }),\n }, ViewerOverlay))\n}\n\nexport { NativeImageViewerService, normalizeViewerRequest } from './viewer.js'\n"],"mappings":";;;;;;;;;;EAAA,MAAM,iBAAiB,OAAO,aAAa,OAAO,SAAS,KAAK,KAAK,QAAQ,IAAI,QAAQ;EACzF,MAAM,cAAa,UAAS,OAAO,OAAO,aAAa,aAAa;GAClE,cAAc,OAAO,MAAM,iBAAiB,YAAY,MAAM,iBAAiB,KAAK,MAAM,eAAe,KAAA;GACzG,YAAY,OAAO,MAAM,eAAe,YAAY,MAAM,eAAe,KAAK,MAAM,aAAa,KAAA;GACjG,UAAU,MAAM;EAClB,IAAI,KAAA;EACJ,MAAM,aAAY,UAAS,MAAM,QAAQ,KAAK,IAAI,MAAM,SAAS,QAAQ,aAAa;GACpF,IAAI,OAAO,QAAQ,aAAa,cAAc,OAAO,QAAQ,UAAU,YAAY,OAAO,MAAM,KAAK,MAAM,IAAI,OAAO,CAAC;GACvH,OAAO,CAAC;IACN,IAAI,OAAO,OAAO,OAAO,YAAY,OAAO,OAAO,KAAK,OAAO,KAAK,UAAU,WAAW;IACzF,OAAO,OAAO;IACd,cAAc,OAAO,OAAO,iBAAiB,YAAY,OAAO,iBAAiB,KAAK,OAAO,eAAe,OAAO;IACnH,YAAY,OAAO,OAAO,eAAe,YAAY,OAAO,eAAe,KAAK,OAAO,aAAa,OAAO;IAC3G,gBAAgB,OAAO,mBAAmB;IAC1C,UAAU,OAAO;GACnB,CAAC;EACH,CAAC,IAAI,CAAC;EAEN,SAAgB,uBAAuB,SAAS;GAE9C,MAAM,SADW,MAAM,QAAQ,SAAS,KAAK,IAAI,QAAQ,QAAQ,CAAC,EAAA,CAC3C,SAAS,MAAM,aAAa;IACjD,IAAI,OAAO,MAAM,QAAQ,YAAY,KAAK,QAAQ,IAAI,OAAO,CAAC;IAC9D,OAAO,CAAC;KACN,IAAI,OAAO,KAAK,OAAO,YAAY,KAAK,OAAO,KAAK,KAAK,KAAK,SAAS,WAAW;KAClF,KAAK,KAAK;KACV,MAAM,OAAO,KAAK,SAAS,YAAY,KAAK,SAAS,KAAK,KAAK,OAAO,SAAS,WAAW;KAC1F,OAAO,cAAc,KAAK,OAAO,KAAA,CAAS;KAC1C,QAAQ,cAAc,KAAK,QAAQ,KAAA,CAAS;KAC5C,OAAO,cAAc,KAAK,OAAO,KAAA,CAAS;KAC1C,UAAU,WAAW,KAAK,QAAQ;KAClC,SAAS,UAAU,KAAK,OAAO;IACjC,CAAC;GACH,CAAC;GACD,IAAI,MAAM,WAAW,GAAG,OAAO,KAAA;GAC/B,MAAM,iBAAiB,OAAO,UAAU,SAAS,KAAK,IAAI,QAAQ,QAAQ;GAC1E,OAAO;IACL;IACA,OAAO,KAAK,IAAI,GAAG,KAAK,IAAI,MAAM,SAAS,GAAG,cAAc,CAAC;IAC7D,QAAQ,OAAO,gBAAgB,eAAe,SAAS,kBAAkB,cAAc,QAAQ,SAAS,KAAA;IACxG,QAAQ,OAAO,SAAS,WAAW,WAAW,QAAQ,SAAS;IAC/D,aAAa,SAAS,gBAAgB;GACxC;EACF;EAEA,IAAa,2BAAb,MAAsC;GACpC,6BAAa,IAAI,IAAI;GACrB,YAAY;GACZ;GACA,sCAAsB,IAAI,IAAI;GAE9B,cAAc;IACZ,KAAK,aAAY,aAAY;KAC3B,KAAKA,WAAW,IAAI,QAAQ;KAC5B,aAAa;MAAE,KAAKA,WAAW,OAAO,QAAQ;KAAE;IAClD;IACA,KAAK,oBAAoB,KAAKC;IAC9B,KAAK,+BAA+B,OAAO,YACzC,CAAC,GAAG,KAAKC,mBAAmB,CAAC,CAAC,KAAK,CAAC,IAAI,iBAAiB,CAAC,IAAI,YAAY,KAAI,gBAAe,EAAE,GAAG,WAAW,EAAE,CAAC,CAAC,CACnH;GACF;GAEA,eAAe,SAAS,aAAa;IACnC,IAAI,OAAO,YAAY,YAAY,YAAY,MAAM,CAAC,MAAM,QAAQ,WAAW,GAAG;IAClF,IAAI,YAAY,WAAW,GAAG,KAAKA,oBAAoB,OAAO,OAAO;SAChE,KAAKA,oBAAoB,IAAI,SAAS,YAAY,KAAI,gBAAe,EAAE,GAAG,WAAW,EAAE,CAAC;GAC/F;GAEA,KAAK,SAAS;IACZ,MAAM,aAAa,uBAAuB,OAAO;IACjD,IAAI,eAAe,KAAA,GAAW,OAAO;IACrC,KAAKC,aAAa;IAClB,KAAKF,YAAY;KAAE,GAAG;KAAY,UAAU,KAAKE;IAAU;IAC3D,KAAKC,MAAM;IACX,OAAO;GACT;GAEA,QAAQ;IACN,IAAI,KAAKH,cAAc,KAAA,GAAW;IAClC,MAAM,SAAS,KAAKA,UAAU;IAC9B,KAAKA,YAAY,KAAA;IACjB,KAAKG,MAAM;IACX,IAAI,OAAO,WAAW,aAAa,QAAQ,MAAM;SAC5C,OAAO,4BAA4B;KAAE,QAAQ,MAAM;IAAE,CAAC;GAC7D;GAEA,QAAQ;IACN,KAAK,MAAM,YAAY,KAAKJ,YAAY,SAAS;GACnD;EACF;EAEA,SAAgB,kBAAkB,QAAQ;GACxC,IAAI,EAAE,kBAAkB,UAAU,OAAO,KAAA;GACzC,MAAM,SAAS,OAAO,QAAQ,QAAQ;GACtC,IAAI,EAAE,kBAAkB,oBAAoB,OAAO,KAAA;GACnD,MAAM,QAAQ,OAAO,cAAc,cAAc;GACjD,IAAI,EAAE,iBAAiB,qBAAqB,MAAM,eAAe,IAAI,OAAO,KAAA;GAC5E,IAAI,OAAO,QAAQ,mDAA+C,GAAG,OAAO;IAAE;IAAQ;IAAO,OAAO,OAAO;GAAc;GACzH,MAAM,OAAO,OAAO,QAAQ,kBAAgB;GAC5C,IAAI,SAAS,QAAQ,OAAO,aAAa,OAAO,GAAG,OAAO;IAAE;IAAQ;IAAO,OAAO;GAAK;EAEzF;EAEA,SAAgB,oBAAoB,OAAO;GAGzC,MAAM,aAAa,CAAC,GAFJ,MAAM,OAAO,iBAAiB,6EAAyE,KAClH,CAAC,CACwB,CAAC,CAAC,SAAS,QAAQ,UAAU;IACzD,MAAM,QAAQ,OAAO,cAAc,cAAc;IACjD,IAAI,EAAE,iBAAiB,qBAAqB,MAAM,eAAe,IAAI,OAAO,CAAC;IAC7E,OAAO,CAAC;KACN,IAAI,MAAM;KACV,KAAK,MAAM;KACX,MAAM,MAAM,OAAO,SAAS,QAAQ;KACpC,OAAO,MAAM,gBAAgB,KAAA;KAC7B,QAAQ,MAAM,iBAAiB,KAAA;KAC/B;IACF,CAAC;GACH,CAAC;GACD,MAAM,QAAQ,WAAW,SAAS,IAAI,aAAa,CAAC;IAClD,IAAI,MAAM,MAAM;IAChB,KAAK,MAAM,MAAM;IACjB,MAAM,MAAM,MAAM,OAAO;IACzB,OAAO,MAAM,MAAM,gBAAgB,KAAA;IACnC,QAAQ,MAAM,MAAM,iBAAiB,KAAA;IACrC,QAAQ,MAAM;GAChB,CAAC;GACD,MAAM,QAAQ,KAAK,IAAI,GAAG,MAAM,WAAU,SAAQ,KAAK,WAAW,MAAM,MAAM,CAAC;GAC/E,OAAO;IAAE,OAAO,MAAM,KAAK,EAAE,QAAQ,SAAS,GAAG,WAAW,IAAI;IAAG;GAAM;EAC3E;;;EC/HA,MAAaK,QAAM,OAAO,GAAG;;;;;;;;;;;;;;;;;;;ECY7B,MAAa,OAAO;EACpB,MAAa,SAAS,CAAC,UAAU,OAAO;EAExC,MAAM,UAAU;GACd,IAAI;IACF,QAAQ;IAAgB,OAAO;IAAS,KAAK;IAAO,QAAQ;IAAQ,UAAU;IAC9E,UAAU;IAAe,gBAAgB;IAAkB,SAAS;IAAgB,YAAY;IAChG,MAAM;IAAkB,iBAAiB;IAAqC,YAAY;IAC1F,WAAW;IAAc,WAAW;IAAc,QAAQ;IAAU,UAAU;IAAkB,MAAM;IACtG,UAAU;IAAuD,WAAW;IAAc,QAAQ;GACpG;GACA,IAAI;IACF,QAAQ;IAAS,OAAO;IAAM,KAAK;IAAQ,QAAQ;IAAQ,UAAU;IACrE,UAAU;IAAQ,gBAAgB;IAAQ,SAAS;IAAQ,YAAY;IACvE,MAAM;IAAc,iBAAiB;IAAe,YAAY;IAChE,WAAW;IAAQ,WAAW;IAAQ,QAAQ;IAAO,UAAU;IAAS,MAAM;IAC9E,UAAU;IAA0B,WAAW;IAAS,QAAQ;GAClE;EACF;EAEA,MAAM,QAAQ,OAAO,cAAc,OAAO,QAAQ,SAAS,CAAC,CAAC,QAC1D,MAAM,CAAC,KAAK,iBAAiB,KAAK,WAAW,IAAI,IAAI,IAAI,OAAO,WAAW,CAAC,GAC7E,KACF;EACA,MAAM,SAAS,OAAO,KAAK,QAAQ,KAAK,IAAI,KAAK,KAAK,IAAI,KAAK,KAAK,CAAC;EACrE,MAAM,cAAa,UAAS,UAAU,KAAA,IAAY,KAAA,IAAY,QAAQ,OAAO,OACzE,GAAG,KAAK,IAAI,IAAK,QAAQ,IAAI,CAAC,CAAC,eAAe,KAAA,GAAW,EAAE,uBAAuB,EAAE,CAAC,EAAE,OACvF,IAAI,QAAQ,OAAO,KAAA,CAAM,eAAe,KAAA,GAAW,EAAE,uBAAuB,EAAE,CAAC,EAAE;EACrF,MAAM,gBAAe,SAAQ;GAC3B,MAAM,UAAU,OAAO,QAAQ,WAAW,CAAC,CAAC,QAAQ,+BAA+B,GAAG,CAAC,CAAC,QAAQ,WAAW,EAAE,CAAC,CAAC,KAAK;GACpH,OAAO,YAAY,KAAK,cAAc;EACxC;EACA,MAAM,YAAY,aAAa,MAAM,YAAY,KAAK,YAAY,UAAU;GAE1E,OAAO,GADO,KAAK,EAAE,MAAM,GAAG,EAAE,OAAO,QAAQ,EAAE,CACnC,EAAE,IAAI,KAAK,MAAM,WAAW,IAAI,GAAG,EAAE,KAAK,KAAK,MAAM,WAAW,IAAI,GAAG,EAAE,MAAM,WAAW,KAAK,KAAK;EACpH,CAAC,CAAC,CAAC,QAAO,SAAQ,CAAC,KAAK,SAAS,IAAI,CAAC,CAAC,CAAC,KAAK,IAAI;EAEjD,SAAS,aAAa,EAAE,QAAQ,aAAa,MAAM,WAAW;GAC5D,MAAM,CAAC,OAAO,aAAA,GAAA,MAAA,SAAA,CAAqB,MAAM;GACzC,MAAM,SAAS,YAAY;IACzB,IAAI,UAAU,WAAW;IACzB,SAAS,SAAS;IAClB,IAAI;KACF,MAAM,OAAO,SAAS;MAAE;MAAa;MAAM,KAAK,KAAK;KAAI,CAAC;KAC1D,SAAS,MAAM;KACf,IAAI,OAAO,gBAAgB,QAAQ,MAAM;IAC3C,QAAQ;KAAE,SAAS,QAAQ;IAAE;GAC/B;GACA,MAAM,QAAQ,UAAU,YAAY,OAAO,eAAe,UAAU,WAAW,OAAO,aAAa,OAAO;GAC1G,OAAO,iBAAA,GAAA,kBAAA,IAAA,CAAC,UAAD;IAAQ,MAAK;IAAS,WAAU;IAAa,UAAU,UAAU;IAAW,eAAe;KAAE,OAAY;IAAE;cAAG,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;KAAM,WAAU;eAAa;IAAY,CAAA;GAAS,CAAA;EACzK;EAEA,SAAS,eAAe,EAAE,UAAU,MAAM,KAAK;GAC7C,MAAM,CAAC,OAAO,aAAA,GAAA,MAAA,SAAA,CAAqB,MAAM;GACzC,MAAM,SAAS,YAAY;IACzB,IAAI,UAAU,WAAW;IACzB,SAAS,SAAS;IAClB,IAAI;KAAE,MAAM,SAAS,SAAS;MAAE;MAAM,KAAK,KAAK;KAAI,CAAC;KAAG,SAAS,MAAM;IAAE,QAAQ;KAAE,SAAS,QAAQ;IAAE;GACxG;GACA,MAAM,QAAQ,UAAU,YAAY,SAAS,gBAAgB,EAAE,WAAW,IAAI,UAAU,WAAW,SAAS,cAAc,EAAE,QAAQ,IAAI,EAAE,UAAU;GACpJ,OAAO,iBAAA,GAAA,kBAAA,KAAA,CAAC,UAAD;IAAQ,MAAK;IAAS,WAAU;IAAe,UAAU,UAAU;IAAW,eAAe;KAAE,OAAY;IAAE;cAA7G,CAAgH,iBAAA,GAAA,kBAAA,IAAA,CAACC,sCAAAA,uBAAD,CAAwB,CAAA,GAAC,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;KAAM,WAAU;eAAa;IAAY,CAAA,CAAS;;EACpM;EAEA,SAAS,cAAc,EAAE,SAAS,KAAK;GACrC,MAAM,WAAA,GAAA,MAAA,qBAAA,CAA+B,QAAQ,WAAW,QAAQ,WAAW;GAC3E,MAAM,CAAC,OAAO,aAAA,GAAA,MAAA,SAAA,CAAqB,CAAC;GACpC,MAAM,CAAC,WAAW,iBAAA,GAAA,MAAA,SAAA,CAAyB;IAAE,MAAM;IAAG,GAAG;IAAG,GAAG;GAAE,CAAC;GAClE,MAAM,CAAC,UAAU,gBAAA,GAAA,MAAA,SAAA,CAAwB,KAAK;GAC9C,MAAM,CAAC,YAAY,kBAAA,GAAA,MAAA,SAAA,CAA0B,KAAK;GAClD,MAAM,CAAC,oBAAoB,0BAAA,GAAA,MAAA,SAAA,CAAkC,QAAQ,sBAAsB;GAC3F,MAAM,yBAAA,GAAA,MAAA,OAAA,CAA+B,kBAAkB;GACvD,MAAM,CAAC,UAAU,gBAAA,GAAA,MAAA,SAAA,CAAwB;GACzC,MAAM,CAAC,WAAW,iBAAA,GAAA,MAAA,SAAA,CAAyB;GAC3C,MAAM,CAAC,QAAQ,cAAA,GAAA,MAAA,SAAA,CAAsB,KAAK;GAC1C,MAAM,WAAA,GAAA,MAAA,OAAA,CAAiB,IAAI;GAC3B,MAAM,YAAA,GAAA,MAAA,OAAA,CAAkB,IAAI;GAC5B,MAAM,cAAA,GAAA,MAAA,OAAA,CAAoB,IAAI;GAC9B,MAAM,YAAA,GAAA,MAAA,OAAA,CAAkB,IAAI;GAC5B,MAAM,eAAA,GAAA,MAAA,OAAA,iBAAqB,IAAI,IAAI,CAAC;GACpC,MAAM,cAAA,GAAA,MAAA,OAAA,CAAoB;GAC1B,MAAM,gBAAA,GAAA,MAAA,OAAA,CAAsB,SAAS;GACrC,aAAa,UAAU;GACvB,sBAAsB,UAAU;GAEhC,CAAA,GAAA,MAAA,UAAA,OAAgB;IACd,IAAI,YAAY,KAAA,GAAW;IAC3B,SAAS,QAAQ,KAAK;IACtB,aAAa;KAAE,MAAM;KAAG,GAAG;KAAG,GAAG;IAAE,CAAC;IACpC,YAAY,KAAK;IACjB,cAAc,KAAK;IACnB,YAAY,KAAA,CAAS;IACrB,UAAU,KAAK;GACjB,GAAG,CAAC,SAAS,QAAQ,CAAC;GAEtB,MAAM,OAAO,SAAS,MAAM;GAC5B,MAAM,cAAc,SAAS,KAAA,IAAY,CAAC,IAAI,mBAAmB,KAAK,OAAO,CAAC;GAC9E,MAAM,kBAAA,GAAA,MAAA,YAAA,EAA8B,WAAW;IAC7C,IAAI,SAAS,KAAA,GAAW;IACxB,MAAM,WAAW,sBAAsB,QAAQ,KAAK,OAAO,CAAC;IAC5D,MAAM,OAAO,OAAO,WAAW,aAAa,OAAO,QAAQ,IAAI;IAC/D,MAAM,WAAW;KAAE,GAAG,sBAAsB;MAAU,KAAK,KAAK;IAAK;IACrE,sBAAsB,UAAU;IAChC,QAAQ,eAAe,KAAK,IAAI,IAAI;IACpC,sBAAsB,QAAQ;GAChC,GAAG,CAAC,MAAM,IAAI,OAAO,CAAC;GAEtB,MAAM,cAAA,GAAA,MAAA,YAAA,EAA0B,MAAM,GAAG,MAAM;IAC7C,MAAM,QAAQ,SAAS;IACvB,MAAM,UAAU,WAAW;IAC3B,IAAI,UAAU,QAAQ,YAAY,QAAQ,QAAQ,GAAG,OAAO;KAAE,GAAG;KAAG,GAAG;IAAE;IACzE,MAAM,SAAS,KAAK,IAAI,IAAI,QAAQ,cAAc,OAAO,MAAM,eAAe,CAAC,IAAI;IACnF,MAAM,SAAS,KAAK,IAAI,IAAI,QAAQ,eAAe,OAAO,MAAM,gBAAgB,CAAC,IAAI;IACrF,OAAO;KAAE,GAAG,MAAM,GAAG,CAAC,QAAQ,MAAM;KAAG,GAAG,MAAM,GAAG,CAAC,QAAQ,MAAM;IAAE;GACtE,GAAG,CAAC,CAAC;GAEL,MAAM,aAAA,GAAA,MAAA,YAAA,EAAyB,UAAU,SAAS,YAAY;IAC5D,MAAM,QAAQ,SAAS;IACvB,IAAI,UAAU,MAAM;IACpB,cAAa,YAAW;KACtB,MAAM,OAAO,MAAM,UAAU,IAAK,CAAC;KACnC,MAAM,MAAM,MAAM,sBAAsB;KACxC,MAAM,KAAK,UAAU,IAAI,OAAO,IAAI,QAAQ;KAC5C,MAAM,KAAK,UAAU,IAAI,MAAM,IAAI,SAAS;KAC5C,MAAM,QAAQ,OAAO,QAAQ;KAE7B,OAAO;MAAE,MAAM;MAAM,GADT,WAAW,MAAM,MAAM,KAAK,QAAQ,KAAK,OAAO,MAAM,KAAK,QAAQ,KAAK,KAC1D;KAAE;IAC9B,CAAC;GACH,GAAG,CAAC,UAAU,CAAC;GAEf,MAAM,OAAA,GAAA,MAAA,YAAA,OAAwB;IAAE,aAAa;KAAE,MAAM;KAAG,GAAG;KAAG,GAAG;IAAE,CAAC;GAAE,GAAG,CAAC,CAAC;GAC3E,MAAM,UAAA,GAAA,MAAA,YAAA,OAA2B;IAC/B,MAAM,QAAQ,SAAS;IACvB,MAAM,UAAU,WAAW;IAC3B,IAAI,UAAU,QAAQ,YAAY,QAAQ,MAAM,iBAAiB,GAAG;IACpE,MAAM,OAAO,MAAM,MAAM,eAAe,KAAK,IAAI,GAAG,QAAQ,WAAW,GAAG,GAAG,CAAC;IAC9E,aAAa;KAAE;KAAM,GAAG;KAAG,GAAG;IAAE,CAAC;GACnC,GAAG,CAAC,CAAC;GAEL,CAAA,GAAA,MAAA,UAAA,OAAgB;IACd,IAAI,YAAY,KAAA,GAAW,OAAO,KAAA;IAClC,MAAM,mBAAmB,SAAS,KAAK,MAAM;IAC7C,SAAS,KAAK,MAAM,WAAW;IAC/B,QAAQ,SAAS,MAAM;IACvB,MAAM,aAAY,UAAS;KACzB,IAAI,MAAM,QAAQ,UAAU;MAC1B,MAAM,eAAe;MACrB,IAAI,MAAM,kBAAkB,WAAW,MAAM,OAAO,QAAQ,kBAAkB,MAAM,MAAM;OACxF,YAAY,KAAA,CAAS;OACrB;MACF;MACA,QAAQ,MAAM;MACd;KACF;KACA,MAAM,UAAU,MAAM,kBAAkB,oBAAoB,MAAM,kBAAkB;KACpF,IAAI,CAAC,WAAW,MAAM,QAAQ,eAAe,QAAQ,MAAM,SAAS,GAAG;MACrE,MAAM,eAAe;MAAG,UAAS,WAAU,QAAQ,IAAI,QAAQ,MAAM,UAAU,QAAQ,MAAM,MAAM;KACrG,OAAO,IAAI,CAAC,WAAW,MAAM,QAAQ,gBAAgB,QAAQ,MAAM,SAAS,GAAG;MAC7E,MAAM,eAAe;MAAG,UAAS,WAAU,QAAQ,KAAK,QAAQ,MAAM,MAAM;KAC9E,OAAO,IAAI,CAAC,YAAY,MAAM,QAAQ,OAAO,MAAM,QAAQ,MAAM;MAC/D,MAAM,eAAe;MAAG,MAAM,MAAM,SAAS,SAAS,sBAAsB;MAAG,IAAI,KAAK,UAAU,aAAa,QAAQ,OAAO,KAAK,IAAI,OAAO,IAAI,QAAQ,GAAG,IAAI,MAAM,IAAI,SAAS,CAAC;KACvL,OAAO,IAAI,CAAC,WAAW,MAAM,QAAQ,KAAK;MACxC,MAAM,eAAe;MAAG,MAAM,MAAM,SAAS,SAAS,sBAAsB;MAAG,IAAI,KAAK,UAAU,aAAa,QAAQ,OAAO,KAAK,IAAI,OAAO,IAAI,QAAQ,GAAG,IAAI,MAAM,IAAI,SAAS,CAAC;KACvL,OAAO,IAAI,CAAC,WAAW,MAAM,IAAI,YAAY,MAAM,KAAK;MACtD,MAAM,eAAe;MAAG,IAAI;KAC9B,OAAO,IAAI,MAAM,QAAQ,OAAO;MAC9B,MAAM,WAAW,CAAC,GAAG,QAAQ,QAAQ,iBAAiB,8GAA4G,CAAC;MACnK,MAAM,QAAQ,SAAS;MACvB,MAAM,OAAO,SAAS,GAAG,EAAE;MAC3B,IAAI,MAAM,YAAY,SAAS,kBAAkB,OAAO;OAAE,MAAM,eAAe;OAAG,MAAM,MAAM;MAAE,OAC3F,IAAI,CAAC,MAAM,YAAY,SAAS,kBAAkB,MAAM;OAAE,MAAM,eAAe;OAAG,OAAO,MAAM;MAAE;KACxG;IACF;IACA,SAAS,iBAAiB,WAAW,SAAS;IAC9C,aAAa;KACX,SAAS,KAAK,MAAM,WAAW;KAC/B,SAAS,oBAAoB,WAAW,SAAS;IACnD;GACF,GAAG;IAAC;IAAS;IAAS;IAAK;GAAS,CAAC;GAErC,CAAA,GAAA,MAAA,UAAA,OAAgB;IACd,IAAI,cAAc,KAAA,GAAW;IAE7B,CADc,QAAQ,SAAS,cAAc,kBAAkB,IAAI,OAAO,SAAS,EAAE,YAAY,EAAA,EAC1F,MAAM;IACb,aAAa,KAAA,CAAS;GACxB,GAAG;IAAC;IAAW;IAAU,YAAY;GAAM,CAAC;GAE5C,CAAA,GAAA,MAAA,UAAA,OAAgB;IACd,aAAa;KAAE,MAAM;KAAG,GAAG;KAAG,GAAG;IAAE,CAAC;IACpC,YAAY,KAAK;IACjB,cAAc,KAAK;IACnB,YAAY,KAAA,CAAS;GACvB,GAAG,CAAC,MAAM,EAAE,CAAC;GAEb,MAAM,WAAA,GAAA,MAAA,YAAA,EAAsB,UAAS;IACnC,MAAM,eAAe;IACrB,UAAU,aAAa,QAAQ,OAAO,KAAK,IAAI,CAAC,MAAM,SAAS,KAAM,GAAG,MAAM,SAAS,MAAM,OAAO;GACtG,GAAG,CAAC,SAAS,CAAC;GACd,CAAA,GAAA,MAAA,UAAA,OAAgB;IACd,MAAM,QAAQ,SAAS;IACvB,IAAI,UAAU,QAAQ,YAAY,KAAA,GAAW,OAAO,KAAA;IACpD,MAAM,iBAAiB,SAAS,SAAS,EAAE,SAAS,MAAM,CAAC;IAC3D,aAAa,MAAM,oBAAoB,SAAS,OAAO;GACzD,GAAG,CAAC,SAAS,OAAO,CAAC;GACrB,MAAM,iBAAgB,UAAS;IAC7B,IAAI,MAAM,WAAW,KAAK,YAAY;IACtC,IAAI,MAAM,kBAAkB,WAAW,MAAM,OAAO,QAAQ,gCAAgC,GAAG;IAC/F,IAAI,MAAM,gBAAgB,WAAW,UAAU,QAAQ,GAAG;IAC1D,MAAM,cAAc,kBAAkB,MAAM,SAAS;IACrD,YAAY,QAAQ,IAAI,MAAM,WAAW;KAAE,GAAG,MAAM;KAAS,GAAG,MAAM;IAAQ,CAAC;IAC/E,IAAI,YAAY,QAAQ,SAAS,GAAG;KAClC,MAAM,CAAC,GAAG,KAAK,CAAC,GAAG,YAAY,QAAQ,OAAO,CAAC;KAC/C,WAAW,UAAU;MAAE,MAAM;MAAS,UAAU,KAAK,MAAM,EAAE,IAAI,EAAE,GAAG,EAAE,IAAI,EAAE,CAAC;MAAG;KAAU;IAC9F,OAAO,IAAI,CAAC,cAAc,UAAU,OAAO,GAAG;KAC5C,WAAW,UAAU;MAAE,MAAM;MAAO,GAAG,MAAM;MAAS,GAAG,MAAM;MAAS;KAAU;KAClF,YAAY,IAAI;IAClB;GACF;GACA,MAAM,iBAAgB,UAAS;IAC7B,IAAI,CAAC,YAAY,QAAQ,IAAI,MAAM,SAAS,GAAG;IAC/C,YAAY,QAAQ,IAAI,MAAM,WAAW;KAAE,GAAG,MAAM;KAAS,GAAG,MAAM;IAAQ,CAAC;IAC/E,MAAM,UAAU,WAAW;IAC3B,IAAI,SAAS,SAAS,WAAW,YAAY,QAAQ,QAAQ,GAAG;KAC9D,MAAM,CAAC,GAAG,KAAK,CAAC,GAAG,YAAY,QAAQ,OAAO,CAAC;KAC/C,MAAM,WAAW,KAAK,IAAI,GAAG,KAAK,MAAM,EAAE,IAAI,EAAE,GAAG,EAAE,IAAI,EAAE,CAAC,CAAC;KAC7D,UAAU,QAAQ,UAAU,OAAO,WAAW,KAAK,IAAI,GAAG,QAAQ,QAAQ,IAAI,EAAE,IAAI,EAAE,KAAK,IAAI,EAAE,IAAI,EAAE,KAAK,CAAC;IAC/G,OAAO,IAAI,SAAS,SAAS,OAAO;KAClC,MAAM,MAAM,WAAW,QAAQ,UAAU,MAAM,QAAQ,UAAU,IAAI,MAAM,UAAU,QAAQ,GAAG,QAAQ,UAAU,IAAI,MAAM,UAAU,QAAQ,CAAC;KAC/I,aAAa;MAAE,MAAM,QAAQ,UAAU;MAAM,GAAG;KAAI,CAAC;IACvD;GACF;GACA,MAAM,cAAa,UAAS;IAC1B,YAAY,QAAQ,OAAO,MAAM,SAAS;IAC1C,IAAI,YAAY,QAAQ,SAAS,GAAG;KAAE,WAAW,UAAU,KAAA;KAAW,YAAY,KAAK;IAAE;GAC3F;GACA,MAAM,iBAAgB,UAAS;IAC7B,IAAI,CAAC,cAAc,MAAM,OAAO,QAAQ,iBAAiB,GAAG;IAC5D,MAAM,SAAS,WAAW,SAAS,sBAAsB;IACzD,IAAI,WAAW,KAAA,GAAW;IAC1B,MAAM,aAAa;KACjB,IAAI,OAAO,WAAW;KACtB,GAAG,OAAO,MAAM,UAAU,OAAO,QAAQ,OAAO,OAAO,GAAG,CAAC;KAC3D,GAAG,OAAO,MAAM,UAAU,OAAO,OAAO,OAAO,QAAQ,GAAG,CAAC;KAC3D,MAAM;IACR;IACA,gBAAe,YAAW,CAAC,GAAG,SAAS,UAAU,CAAC;IAClD,cAAc,KAAK;IACnB,YAAY,WAAW,EAAE;IACzB,aAAa,WAAW,EAAE;GAC5B;GACA,MAAM,YAAY,YAAY;IAC5B,MAAM,OAAO,SAAS,aAAa,CAAC;IACpC,IAAI,SAAS,IAAI;IACjB,MAAM,UAAU,UAAU,UAAU,IAAI;IACxC,UAAU,IAAI;IACd,OAAO,iBAAiB;KAAE,UAAU,KAAK;IAAE,GAAG,IAAI;GACpD;GAEA,IAAI,YAAY,KAAA,KAAa,SAAS,KAAA,GAAW,OAAO;GACxD,MAAM,OAAO,CAAC,KAAK,SAAS,KAAK,SAAS,GAAG,KAAK,MAAM,KAAK,KAAK,WAAW,KAAA,GAAW,WAAW,KAAK,KAAK,CAAC,CAAC,CAAC,OAAO,OAAO,CAAC,CAAC,KAAK,KAAK;GAC1I,MAAM,cAAc,QAAQ,MAAM,SAAS;GAC3C,OAAO,iBAAA,GAAA,kBAAA,KAAA,CAAC,OAAD;IAAK,KAAK;IAAS,WAAU;IAAW,MAAK;IAAS,cAAW;IAAO,cAAY,EAAE,QAAQ;IAAG,UAAU;cAA3G;KACL,iBAAA,GAAA,kBAAA,KAAA,CAAC,OAAD;MAAK,WAAU;gBAAf,CAAuC,iBAAA,GAAA,kBAAA,IAAA,CAAC,UAAD,EAAA,UAAS,KAAK,KAAa,CAAA,GAAE,SAAS,KAAK,iBAAA,GAAA,kBAAA,IAAA,CAAC,SAAD,EAAA,UAAQ,KAAY,CAAA,IAAI,IAAU;;KACpH,iBAAA,GAAA,kBAAA,IAAA,CAAC,UAAD;MAAQ,WAAU;MAAa,MAAK;MAAU,cAAY,EAAE,QAAQ;gBAClE,iBAAA,GAAA,kBAAA,KAAA,CAAC,OAAD;OAAK,WAAU;iBAAf;QACG,QAAQ,cAAc,iBAAA,GAAA,kBAAA,KAAA,CAAC,UAAD;SAAQ,MAAK;SAAS,WAAU;SAAa,eAAa;SAAY,cAAY,aAAa,EAAE,gBAAgB,IAAI,EAAE,UAAU;SAAG,gBAAc;SAAY,eAAe,eAAc,UAAS,CAAC,KAAK;mBAA1M,CAA6M,iBAAA,GAAA,kBAAA,IAAA,CAACC,sCAAAA,mBAAD,CAAoB,CAAA,GAAC,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;UAAM,WAAU;oBAAa,aAAa,EAAE,gBAAgB,IAAI,EAAE,UAAU;SAAQ,CAAA,CAAS;aAAI;QACzV,YAAY,SAAS,IAAI,iBAAA,GAAA,kBAAA,KAAA,CAAC,UAAD;SAAQ,MAAK;SAAS,WAAU;SAAa,eAAa,aAAa,KAAA;SAAW,eAAe;UAAE,MAAM,QAAQ,YAAY;UAAI,aAAY,YAAW,YAAY,KAAA,IAAY,MAAM,KAAK,KAAA,CAAS;UAAG,IAAI,aAAa,KAAA,GAAW,aAAa,MAAM,EAAE;SAAE;mBAA1P;UAA8P,YAAY;UAAO;UAAC,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;WAAM,WAAU;qBAAa,EAAE,SAAS;UAAQ,CAAA;SAAS;aAAI;QACzW,iBAAA,GAAA,kBAAA,KAAA,CAAC,UAAD;SAAQ,MAAK;SAAS,WAAU;SAAa,cAAY,EAAE,KAAK;SAAG,SAAS;mBAA5E,CAAiF,iBAAA,GAAA,kBAAA,IAAA,CAACC,sCAAAA,yBAAD,CAA0B,CAAA,GAAC,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;UAAM,WAAU;oBAAa,EAAE,KAAK;SAAQ,CAAA,CAAS;;QACjK,iBAAA,GAAA,kBAAA,IAAA,CAAC,UAAD;SAAQ,MAAK;SAAS,WAAU;SAAa,SAAS;mBAAS,EAAE,QAAQ;QAAU,CAAA;QACnF,iBAAA,GAAA,kBAAA,KAAA,CAAC,QAAD;SAAM,WAAU;mBAAhB,CAA4B,KAAK,MAAM,UAAU,OAAO,GAAG,GAAE,GAAO;;QACnE,KAAK,aAAa,KAAA,IACf,iBAAA,GAAA,kBAAA,KAAA,CAAC,KAAD;SAAG,WAAU;SAAe,MAAM,KAAK;SAAK,UAAU,aAAa,KAAK,IAAI;mBAA5E,CAA+E,iBAAA,GAAA,kBAAA,IAAA,CAACF,sCAAAA,uBAAD,CAAwB,CAAA,GAAC,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;UAAM,WAAU;oBAAa,EAAE,UAAU;SAAQ,CAAA,CAAI;aAC7J,iBAAA,GAAA,kBAAA,IAAA,CAAC,gBAAD;SAAgB,UAAU,KAAK;SAAgB;SAAS;QAAI,CAAA;QAC/D,KAAK,QAAQ,KAAI,WAAU,iBAAA,GAAA,kBAAA,IAAA,CAAC,cAAD;SAAsB;SAAqB;SAAmB;SAAe;QAA0B,GAAZ,OAAO,EAAK,CAAC;OACjI;;KACC,CAAA;KACR,iBAAA,GAAA,kBAAA,IAAA,CAAC,UAAD;MAAQ,MAAK;MAAS,WAAU;MAAqB,cAAY,EAAE,OAAO;MAAG,eAAe,QAAQ,MAAM;gBAAG,iBAAA,GAAA,kBAAA,IAAA,CAACG,sCAAAA,oBAAD,CAAqB,CAAA;KAAS,CAAA;KAC3I,iBAAA,GAAA,kBAAA,KAAA,CAAC,OAAD;MAAK,WAAU;gBAAf,CACE,iBAAA,GAAA,kBAAA,KAAA,CAAC,QAAD;OAAM,KAAK;OAAU,WAAU;OAAY,iBAAe;OAAU,mBAAiB;OAAY,UAAS,UAAS;QAAE,IAAI,MAAM,WAAW,MAAM,iBAAiB,CAAC,cAAc,UAAU,SAAS,GAAG,QAAQ,MAAM;OAAE;OAAkB;OAA8B;OAAe,aAAa;OAAY,iBAAiB;OAAY,qBAAqB;QAAE,IAAI,UAAU,SAAS,GAAG,OAAO;aAAQ,IAAI;OAAE;iBAAjZ,CACE,iBAAA,GAAA,kBAAA,KAAA,CAAC,OAAD;QAAK,KAAK;QAAY,WAAU;QAAc,SAAS;QAAe,OAAO,EAAE,WAAW,eAAe,UAAU,EAAE,KAAK,UAAU,EAAE,cAAc,UAAU,KAAK,GAAG;kBAAtK,CACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,OAAD;SAAK,KAAK;SAAU,WAAU;SAAY,KAAK,KAAK;SAAK,KAAK,KAAK;SAAM,WAAU;QAAS,CAAA,GAC3F,YAAY,KAAK,YAAY,aAAa,iBAAA,GAAA,kBAAA,KAAA,CAAC,OAAD;SAAK,WAAU;SAAiB,UAAQ,WAAW,IAAI,MAAO,UAAU,WAAW,IAAI,MAAO,SAAS;SAAU,UAAQ,WAAW,IAAI,MAAO,SAAS;SAAM,OAAO;UAAE,MAAM,GAAG,WAAW,IAAI,IAAI;UAAI,KAAK,GAAG,WAAW,IAAI,IAAI;UAAI,WAAW,8BAA8B,IAAI,UAAU,KAAK;SAAG;mBAArS,CACzC,iBAAA,GAAA,kBAAA,IAAA,CAAC,UAAD;UAAQ,MAAK;UAAS,WAAU;UAAU,eAAa,aAAa,WAAW;UAAI,cAAY,KAAK,EAAE,MAAM,GAAG,EAAE,OAAO,WAAW,EAAE,CAAC;UAAG,UAAS,UAAS;WAAE,MAAM,gBAAgB;WAAG,MAAM,UAAU,aAAa,WAAW;WAAI,YAAY,UAAU,WAAW,KAAK,KAAA,CAAS;WAAG,IAAI,SAAS,aAAa,WAAW,EAAE;UAAE;oBAAI,WAAW;SAAU,CAAA,GACrV,aAAa,WAAW,KAAK,iBAAA,GAAA,kBAAA,KAAA,CAAC,OAAD;UAAK,WAAU;UAAkB,gBAAc,WAAW;UAAI,UAAS,UAAS,MAAM,gBAAgB;oBAAtG;WAC5B,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;YAAM,WAAU;sBAAoB,WAAW;WAAQ,CAAA;WACvD,iBAAA,GAAA,kBAAA,IAAA,CAAC,YAAD;YAAU,OAAO,WAAW;YAAM,MAAM;YAAG,cAAY,KAAK,EAAE,MAAM,GAAG,EAAE,OAAO,WAAW,EAAE,CAAC;YAAG,aAAa,EAAE,iBAAiB;YAAG,WAAU,UAAS;aAAE,MAAM,OAAO,MAAM,OAAO;aAAO,gBAAe,YAAW,QAAQ,KAAI,UAAS,MAAM,OAAO,WAAW,KAAK;cAAE,GAAG;cAAO;aAAK,IAAI,KAAK,CAAC;YAAE;YAAG,YAAW,UAAS;aACxT,IAAK,MAAM,QAAQ,WAAW,CAAC,MAAM,YAAa,MAAM,QAAQ,UAAU;cACxE,MAAM,eAAe;cACrB,MAAM,gBAAgB;cACtB,MAAM,aAAa,2BAA2B;cAC9C,YAAY,KAAA,CAAS;aACvB;YACF;WAAI,CAAA;WACJ,iBAAA,GAAA,kBAAA,IAAA,CAAC,UAAD;YAAQ,MAAK;YAAS,WAAU;YAAkB,cAAY,EAAE,YAAY;YAAG,UAAS,UAAS;aAAE,MAAM,gBAAgB;aAAG,gBAAe,YAAW,QAAQ,QAAO,UAAS,MAAM,OAAO,WAAW,EAAE,CAAC;aAAG,YAAY,KAAA,CAAS;YAAE;sBAAG,iBAAA,GAAA,kBAAA,IAAA,CAACA,sCAAAA,oBAAD,CAAqB,CAAA;WAAS,CAAA;UACjQ;cAAI,IACN;WAdmV,WAAW,EAc9V,CAAC,CACH;WACJ,cAAc,iBAAA,GAAA,kBAAA,KAAA,CAAA,kBAAA,UAAA,EAAA,UAAA;QACb,iBAAA,GAAA,kBAAA,IAAA,CAAC,UAAD;SAAQ,MAAK;SAAS,WAAU;SAA4C,cAAY,EAAE,UAAU;SAAG,UAAS,UAAS;UAAE,MAAM,gBAAgB;UAAG,UAAS,WAAU,QAAQ,IAAI,QAAQ,MAAM,UAAU,QAAQ,MAAM,MAAM;SAAE;mBAAG,iBAAA,GAAA,kBAAA,IAAA,CAACC,sCAAAA,0BAAD,CAA2B,CAAA;QAAS,CAAA;QACxQ,iBAAA,GAAA,kBAAA,IAAA,CAAC,UAAD;SAAQ,MAAK;SAAS,WAAU;SAA4C,cAAY,EAAE,MAAM;SAAG,UAAS,UAAS;UAAE,MAAM,gBAAgB;UAAG,UAAS,WAAU,QAAQ,KAAK,QAAQ,MAAM,MAAM;SAAE;mBAAG,iBAAA,GAAA,kBAAA,IAAA,CAACC,sCAAAA,2BAAD,CAA4B,CAAA;QAAS,CAAA;QAC9O,iBAAA,GAAA,kBAAA,KAAA,CAAC,QAAD;SAAM,WAAU;mBAAhB;UAA+B,QAAQ;UAAE;UAAI,QAAQ,MAAM;SAAa;;OACxE,EAAA,CAAA,IAAI,aAAa,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;QAAM,WAAU;kBAAY,EAAE,YAAY;OAAQ,CAAA,IAAI,UAAU,SAAS,IAAI,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;QAAM,WAAU;kBAAY,EAAE,UAAU;OAAQ,CAAA,IAAI,IAChJ;UACL,YAAY,MAAK,eAAc,WAAW,KAAK,KAAK,MAAM,EAAE,IAAI,iBAAA,GAAA,kBAAA,KAAA,CAAC,UAAD;OAAQ,MAAK;OAAS,WAAU;OAAiB,eAAe;QAAE,UAAe;OAAE;iBAAnF,CAAsF,iBAAA,GAAA,kBAAA,IAAA,CAACC,sCAAAA,mBAAD,CAAoB,CAAA,GAAE,SAAS,EAAE,QAAQ,IAAI,EAAE,WAAW,CAAU;WAAI,IAC5N;;IACF;;EACP;EAEA,SAAS,2BAA2B,SAAS;GAC3C,MAAM,WAAU,UAAS;IACvB,MAAM,QAAQ,kBAAkB,MAAM,MAAM;IAC5C,IAAI,UAAU,KAAA,GAAW;IACzB,MAAM,EAAE,OAAO,UAAU,oBAAoB,KAAK;IAClD,MAAM,eAAe;IACrB,MAAM,gBAAgB;IACtB,MAAM,yBAAyB;IAC/B,QAAQ,KAAK;KAAE;KAAO;KAAO,QAAQ,MAAM;KAAQ,QAAQ;KAAc,aAAa;IAAK,CAAC;GAC9F;GACA,SAAS,iBAAiB,SAAS,SAAS,IAAI;GAChD,aAAa;IAAE,SAAS,oBAAoB,SAAS,SAAS,IAAI;GAAE;EACtE;EAEA,SAAgB,MAAM,KAAK;GACzB,MAAM,UAAU,IAAI,yBAAyB;GAC7C,IAAI,aAAa,IAAI,OAAO,SAAS,MAAM,OAAO,GAAG,GAAG,KAAK,eAAe;GAC5E,IAAI,aAAa;IACf,MAAM,QAAQ,SAAS,cAAc,OAAO;IAC5C,MAAM,QAAQ,SAAS;IACvB,MAAM,cAAcC;IACpB,SAAS,KAAK,YAAY,KAAK;IAC/B,aAAa;KAAE,MAAM,OAAO;IAAE;GAChC,GAAG,GAAG,KAAK,SAAS;GACpB,IAAI,aAAa;IACf,MAAM,iBAAiB,IAAI,QAAQ,QAAQ,qBAAqB,OAAO;IACvE,MAAM,gBAAgB,2BAA2B,OAAO;IACxD,aAAa;KAAE,cAAc;KAAG,eAAoB;IAAE;GACxD,GAAG,GAAG,KAAK,kDAAkD;GAC7D,MAAM,IAAI,IAAI,OAAO,KAAK,IAAI;GAC9B,IAAI,MAAM,OAAO,uBAAuB,IAAI,MAAM,SAAS;IACzD,MAAM;IAAiB,IAAI;IAAM,OAAO;IAAI,eAAe;KAAE;KAAS;IAAE;GAC1E,GAAG,aAAa,CAAC;EACnB"}
|
|
1
|
+
{"version":3,"file":"client.js","names":["#listeners","#snapshot","#annotationsByImage","#revision","#emit","CSS","clamp","IconDownloadOutline16","IconEditOutline16","IconFullscreenOutline16","IconCloseOutline16","IconChevronLeftOutline14","IconChevronRightOutline14","IconCopyOutline16","VIEWER_CSS"],"sources":["../src/viewer.js","../src/styles.js","../src/image-transform.js","../src/client.jsx"],"sourcesContent":["const boundedNumber = (value, fallback) => Number.isFinite(value) && value > 0 ? value : fallback\nconst downloadOf = value => typeof value?.onInvoke === 'function' ? {\n pendingLabel: typeof value.pendingLabel === 'string' && value.pendingLabel !== '' ? value.pendingLabel : undefined,\n errorLabel: typeof value.errorLabel === 'string' && value.errorLabel !== '' ? value.errorLabel : undefined,\n onInvoke: value.onInvoke,\n} : undefined\nconst actionsOf = value => Array.isArray(value) ? value.flatMap((action, position) => {\n if (typeof action?.onInvoke !== 'function' || typeof action?.label !== 'string' || action.label.trim() === '') return []\n return [{\n id: typeof action.id === 'string' && action.id !== '' ? action.id : `action-${position + 1}`,\n label: action.label,\n pendingLabel: typeof action.pendingLabel === 'string' && action.pendingLabel !== '' ? action.pendingLabel : action.label,\n errorLabel: typeof action.errorLabel === 'string' && action.errorLabel !== '' ? action.errorLabel : action.label,\n closeOnSuccess: action.closeOnSuccess === true,\n onInvoke: action.onInvoke,\n }]\n}) : []\n\nexport function normalizeViewerRequest(request) {\n const rawItems = Array.isArray(request?.items) ? request.items : []\n const items = rawItems.flatMap((item, position) => {\n if (typeof item?.src !== 'string' || item.src === '') return []\n return [{\n id: typeof item.id === 'string' && item.id !== '' ? item.id : item.src,\n src: item.src,\n name: typeof item.name === 'string' && item.name !== '' ? item.name : `Image ${position + 1}`,\n width: boundedNumber(item.width, undefined),\n height: boundedNumber(item.height, undefined),\n bytes: boundedNumber(item.bytes, undefined),\n download: downloadOf(item.download),\n actions: actionsOf(item.actions),\n }]\n })\n if (items.length === 0) return undefined\n const requestedIndex = Number.isInteger(request?.index) ? request.index : 0\n return {\n items,\n index: Math.max(0, Math.min(items.length - 1, requestedIndex)),\n opener: typeof HTMLElement !== 'undefined' && request?.opener instanceof HTMLElement ? request.opener : undefined,\n source: typeof request?.source === 'string' ? request.source : 'dsh',\n annotations: request?.annotations !== false,\n }\n}\n\nexport class NativeImageViewerService {\n #listeners = new Set()\n #revision = 0\n #snapshot\n #annotationsByImage = new Map()\n\n constructor() {\n this.subscribe = listener => {\n this.#listeners.add(listener)\n return () => { this.#listeners.delete(listener) }\n }\n this.getSnapshot = () => this.#snapshot\n this.getAnnotationsSnapshot = () => Object.fromEntries(\n [...this.#annotationsByImage].map(([id, annotations]) => [id, annotations.map(annotation => ({ ...annotation }))]),\n )\n }\n\n setAnnotations(imageId, annotations) {\n if (typeof imageId !== 'string' || imageId === '' || !Array.isArray(annotations)) return\n if (annotations.length === 0) this.#annotationsByImage.delete(imageId)\n else this.#annotationsByImage.set(imageId, annotations.map(annotation => ({ ...annotation })))\n }\n\n open(request) {\n const normalized = normalizeViewerRequest(request)\n if (normalized === undefined) return false\n this.#revision += 1\n this.#snapshot = { ...normalized, revision: this.#revision }\n this.#emit()\n return true\n }\n\n close() {\n if (this.#snapshot === undefined) return\n const opener = this.#snapshot.opener\n this.#snapshot = undefined\n this.#emit()\n if (typeof window === 'undefined') opener?.focus()\n else window.requestAnimationFrame(() => { opener?.focus() })\n }\n\n #emit() {\n for (const listener of this.#listeners) listener()\n }\n}\n\nexport function nativeImageButton(target) {\n if (!(target instanceof Element)) return undefined\n const button = target.closest('button')\n if (!(button instanceof HTMLButtonElement)) return undefined\n const image = button.querySelector(':scope > img')\n if (!(image instanceof HTMLImageElement) || image.currentSrc === '') return undefined\n if (button.matches('[data-variant=\"single\"],[data-variant=\"tile\"]')) return { button, image, group: button.parentElement }\n const rail = button.closest('[role=\"group\"]')\n if (rail !== null && button.hasAttribute('title')) return { button, image, group: rail }\n return undefined\n}\n\nexport function imageItemsForButton(match) {\n const buttons = match.group?.querySelectorAll('button[data-variant=\"single\"],button[data-variant=\"tile\"],button[title]')\n ?? []\n const candidates = [...buttons].flatMap((button, index) => {\n const image = button.querySelector(':scope > img')\n if (!(image instanceof HTMLImageElement) || image.currentSrc === '') return []\n return [{\n id: image.currentSrc,\n src: image.currentSrc,\n name: image.alt || `Image ${index + 1}`,\n width: image.naturalWidth || undefined,\n height: image.naturalHeight || undefined,\n button,\n }]\n })\n const items = candidates.length > 0 ? candidates : [{\n id: match.image.currentSrc,\n src: match.image.currentSrc,\n name: match.image.alt || 'Image',\n width: match.image.naturalWidth || undefined,\n height: match.image.naturalHeight || undefined,\n button: match.button,\n }]\n const index = Math.max(0, items.findIndex(item => item.button === match.button))\n return { items: items.map(({ button: _button, ...item }) => item), index }\n}\n","export const CSS = String.raw`\n.niv-root{position:fixed;inset:0;z-index:1000;pointer-events:auto;overflow:hidden;background:rgba(7,8,10,.68);color:var(--dsw-alias-label-primary-inverted,#fff);outline:0;backdrop-filter:blur(13px) saturate(.72);-webkit-backdrop-filter:blur(13px) saturate(.72)}\n.niv-sr-only{position:absolute!important;width:1px!important;height:1px!important;padding:0!important;margin:-1px!important;overflow:hidden!important;clip:rect(0,0,0,0)!important;white-space:nowrap!important;border:0!important}\n.niv-title{position:absolute;top:20px;left:24px;right:84px;display:flex;align-items:baseline;gap:12px;color:#fff;font-size:13px}.niv-title strong{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.niv-title small{flex:none;opacity:.7}.niv-load-status{position:absolute;z-index:7;display:flex;align-items:center;gap:12px;color:#fff;font-size:14px}\n.niv-topbar{position:absolute;right:50%;bottom:22px;z-index:6;max-width:calc(100vw - 36px);padding:5px;border:1px solid rgba(255,255,255,.12);border-radius:999px;background:rgba(38,39,43,.86);box-shadow:0 10px 34px rgba(0,0,0,.3);transform:translateX(50%);backdrop-filter:blur(18px);-webkit-backdrop-filter:blur(18px)}\n.niv-actions{display:flex;align-items:center;gap:2px;overflow-x:auto;scrollbar-width:none}.niv-actions::-webkit-scrollbar{display:none}.niv-button,.niv-download{box-sizing:border-box;display:inline-flex;align-items:center;justify-content:center;gap:6px;height:32px;padding:0 10px;border:0;border-radius:999px;background:transparent;color:rgba(255,255,255,.9);font:inherit;font-size:12px;text-decoration:none;white-space:nowrap;cursor:pointer}.niv-button:hover,.niv-download:hover,.niv-button[data-active=true]{background:rgba(255,255,255,.12)}.niv-button:focus-visible,.niv-download:focus-visible,.niv-close-floating:focus-visible{outline:2px solid rgba(255,255,255,.9);outline-offset:2px}.niv-button:disabled,.niv-download:disabled{opacity:.38;cursor:default}.niv-icon-only{width:32px;padding:0}.niv-zoom{min-width:44px;color:rgba(255,255,255,.68);font-size:12px;font-variant-numeric:tabular-nums;text-align:center}\n.niv-close-floating{position:absolute;top:20px;right:20px;z-index:8;display:grid;place-items:center;width:42px;height:42px;padding:0;border:1px solid rgba(255,255,255,.1);border-radius:50%;background:rgba(48,49,53,.82);box-shadow:0 8px 24px rgba(0,0,0,.28);color:#fff;cursor:pointer;backdrop-filter:blur(16px);-webkit-backdrop-filter:blur(16px)}.niv-close-floating:hover{background:rgba(66,67,72,.92)}\n.niv-workspace{position:absolute;inset:0;display:grid;min-width:0;min-height:0;padding:68px 24px 72px;box-sizing:border-box}\n.niv-stage{position:relative;display:grid;place-items:center;min-width:0;min-height:0;overflow:hidden;padding:0;touch-action:none;user-select:none}.niv-stage[data-dragging=true]{cursor:grabbing}.niv-stage[data-annotating=true]{cursor:crosshair}\n.niv-surface{position:relative;display:inline-flex;max-width:100%;max-height:100%;transform-origin:center;will-change:transform}.niv-image{display:block;max-width:calc(100vw - 72px);max-height:calc(100vh - 154px);border-radius:12px;object-fit:contain;box-shadow:0 22px 60px rgba(0,0,0,.46);user-select:none;-webkit-user-drag:none}\n.niv-annotation{position:absolute;z-index:5;width:24px;height:24px;transform-origin:center;pointer-events:none}.niv-pin{position:absolute;inset:0;display:grid;place-items:center;width:24px;height:24px;padding:0;border:2px solid #fff;border-radius:50%;background:rgba(23,24,27,.94);box-shadow:0 4px 16px rgba(0,0,0,.35);color:#fff;font:inherit;font-size:11px;font-weight:700;cursor:pointer;pointer-events:auto}.niv-pin[data-active=true]{background:var(--dsw-alias-state-business-primary,#3964fe)}\n.niv-inline-note{position:absolute;bottom:34px;box-sizing:border-box;display:grid;width:min(300px,calc(100vw - 40px));grid-template-columns:24px minmax(0,1fr) 24px;align-items:center;gap:7px;padding:7px 8px;border:1px solid rgba(255,255,255,.12);border-radius:18px;background:rgba(32,33,37,.94);box-shadow:0 14px 38px rgba(0,0,0,.38);color:#fff;pointer-events:auto;backdrop-filter:blur(20px);-webkit-backdrop-filter:blur(20px)}.niv-annotation[data-x=right] .niv-inline-note{left:-8px}.niv-annotation[data-x=left] .niv-inline-note{right:-8px}.niv-annotation[data-x=center] .niv-inline-note{left:50%;transform:translateX(-50%)}.niv-annotation[data-y=down] .niv-inline-note{top:34px;bottom:auto}.niv-inline-note::after{position:absolute;width:9px;height:9px;background:rgba(32,33,37,.94);content:'';transform:rotate(45deg)}.niv-annotation[data-y=up] .niv-inline-note::after{bottom:-5px}.niv-annotation[data-y=down] .niv-inline-note::after{top:-5px}.niv-annotation[data-x=right] .niv-inline-note::after{left:13px}.niv-annotation[data-x=left] .niv-inline-note::after{right:13px}.niv-annotation[data-x=center] .niv-inline-note::after{left:calc(50% - 4px)}.niv-inline-index{display:grid;place-items:center;width:22px;height:22px;border-radius:50%;background:var(--dsw-alias-state-business-primary,#3964fe);color:#fff;font-size:10px;font-weight:700}.niv-inline-note textarea{box-sizing:border-box;width:100%;min-height:24px;max-height:92px;resize:none;overflow:auto;border:0;outline:0;background:transparent;color:#fff;font:inherit;font-size:12px;line-height:18px}.niv-inline-note textarea::placeholder{color:rgba(255,255,255,.44)}.niv-note-remove{display:grid;place-items:center;width:24px;height:24px;padding:0;border:0;border-radius:50%;background:transparent;color:rgba(255,255,255,.68);cursor:pointer}.niv-note-remove:hover{background:rgba(255,255,255,.1);color:#fff}\n.niv-nav{position:absolute;top:50%;z-index:4;width:42px;height:42px;padding:0;transform:translateY(-50%);background:rgba(48,49,53,.82);box-shadow:0 8px 24px rgba(0,0,0,.28);backdrop-filter:blur(16px)}.niv-prev{left:6px}.niv-next{right:6px}.niv-counter{position:absolute;bottom:8px;left:50%;padding:5px 10px;border-radius:999px;background:rgba(38,39,43,.86);color:rgba(255,255,255,.72);font-size:11px;transform:translateX(-50%);backdrop-filter:blur(16px)}\n.niv-hint{display:none}\n.niv-copy-notes{position:absolute;right:20px;bottom:22px;z-index:6;display:inline-flex;align-items:center;gap:6px;height:32px;padding:0 11px;border:1px solid rgba(255,255,255,.1);border-radius:999px;background:rgba(38,39,43,.86);color:rgba(255,255,255,.82);font:inherit;font-size:12px;cursor:pointer;backdrop-filter:blur(16px)}\n@media(max-width:760px){.niv-close-floating{top:12px;right:12px;width:40px;height:40px}.niv-workspace{padding:60px 12px 68px}.niv-image{max-width:calc(100vw - 24px);max-height:calc(100vh - 136px)}.niv-topbar{bottom:12px;max-width:calc(100vw - 24px)}.niv-button{padding:0 8px}.niv-button span.niv-label{display:none}.niv-inline-note{width:min(260px,calc(100vw - 40px))}.niv-copy-notes{display:none}}\n@media(prefers-reduced-motion:reduce){.niv-surface{transition:none}}\n`\n","import { useCallback, useEffect, useRef, useState } from 'react'\n\nconst clamp = (value, min, max) => Math.min(max, Math.max(min, value))\nconst fitted = () => ({ zoom: 1, x: 0, y: 0 })\n\n// Coordinates are relative to the fitted image; 100% uses its decoded pixel width.\nexport function useImageTransform(identity) {\n const [transform, setTransform] = useState(fitted)\n const [dragging, setDragging] = useState(false)\n const [pixelScale, setPixelScale] = useState(1)\n const stageRef = useRef(null), surfaceRef = useRef(null), imageRef = useRef(null)\n const transformRef = useRef(transform)\n const pointers = useRef(new Map()), gesture = useRef()\n transformRef.current = transform\n\n const resetGesture = useCallback(() => {\n pointers.current.clear()\n gesture.current = undefined\n setDragging(false)\n }, [])\n const fit = useCallback(() => { resetGesture(); setTransform(fitted()) }, [resetGesture])\n useEffect(() => { fit() }, [identity, fit])\n\n const actualScale = () => imageRef.current?.naturalWidth / Math.max(1, surfaceRef.current?.offsetWidth || 1) || 1\n const boundedPan = useCallback((zoom, x, y) => {\n const stage = stageRef.current, surface = surfaceRef.current\n if (!stage || !surface || zoom <= 1) return { x: 0, y: 0 }\n const limitX = Math.max(0, (surface.offsetWidth * zoom - stage.clientWidth) / 2)\n const limitY = Math.max(0, (surface.offsetHeight * zoom - stage.clientHeight) / 2)\n return { x: clamp(x, -limitX, limitX), y: clamp(y, -limitY, limitY) }\n }, [])\n const setZoomAt = useCallback((zoom, clientX, clientY) => {\n const stage = stageRef.current\n if (!stage) return\n setTransform(current => {\n const next = clamp(zoom, 0.5, Math.max(8, actualScale()))\n const box = stage.getBoundingClientRect()\n const px = clientX - box.left - box.width / 2, py = clientY - box.top - box.height / 2\n const ratio = next / current.zoom\n return { zoom: next, ...boundedPan(next, px - (px - current.x) * ratio, py - (py - current.y) * ratio) }\n })\n }, [boundedPan])\n const actual = useCallback(() => {\n if (!imageRef.current?.naturalWidth) return\n resetGesture()\n setTransform({ zoom: actualScale(), x: 0, y: 0 })\n }, [resetGesture])\n const measure = useCallback(() => {\n setPixelScale(1 / actualScale())\n setTransform(current => ({ ...current, ...boundedPan(current.zoom, current.x, current.y) }))\n }, [boundedPan])\n useEffect(() => {\n if (!stageRef.current || !surfaceRef.current) return\n const observer = new ResizeObserver(measure)\n observer.observe(stageRef.current)\n observer.observe(surfaceRef.current)\n measure()\n return () => observer.disconnect()\n }, [identity, measure])\n useEffect(() => {\n const stage = stageRef.current\n if (!stage) return\n const wheel = event => {\n event.preventDefault()\n const delta = event.deltaY * (event.deltaMode === 1 ? 16 : event.deltaMode === 2 ? stage.clientHeight : 1)\n setZoomAt(transformRef.current.zoom * Math.exp(-delta * 0.0015), event.clientX, event.clientY)\n }\n stage.addEventListener('wheel', wheel, { passive: false })\n return () => stage.removeEventListener('wheel', wheel)\n }, [identity, setZoomAt])\n\n const onPointerDown = event => {\n if (event.button !== 0 || event.target.closest('button,a,input,textarea,select')) return\n const current = transformRef.current\n if (event.pointerType === 'mouse' && current.zoom <= 1) return\n event.currentTarget.setPointerCapture(event.pointerId)\n pointers.current.set(event.pointerId, { x: event.clientX, y: event.clientY })\n if (pointers.current.size === 2) {\n const [a, b] = [...pointers.current.values()]\n gesture.current = { kind: 'pinch', distance: Math.hypot(a.x - b.x, a.y - b.y), transform: current }\n } else {\n gesture.current = { kind: 'pan', x: event.clientX, y: event.clientY, transform: current }\n }\n setDragging(true)\n }\n const onPointerMove = event => {\n if (!pointers.current.has(event.pointerId)) return\n pointers.current.set(event.pointerId, { x: event.clientX, y: event.clientY })\n const start = gesture.current\n if (start?.kind === 'pinch' && pointers.current.size >= 2) {\n const [a, b] = [...pointers.current.values()]\n setZoomAt(start.transform.zoom * Math.hypot(a.x - b.x, a.y - b.y) / Math.max(1, start.distance), (a.x + b.x) / 2, (a.y + b.y) / 2)\n } else if (start?.kind === 'pan') {\n setTransform({ zoom: start.transform.zoom, ...boundedPan(start.transform.zoom, start.transform.x + event.clientX - start.x, start.transform.y + event.clientY - start.y) })\n }\n }\n const endPointer = event => {\n pointers.current.delete(event.pointerId)\n const remaining = [...pointers.current.values()][0]\n if (remaining) gesture.current = { kind: 'pan', ...remaining, transform: transformRef.current }\n else resetGesture()\n }\n return { transform, transformRef, dragging, pixelScale, stageRef, surfaceRef, imageRef, fit, actual, measure, setZoomAt, resetGesture,\n pointerHandlers: { onPointerDown, onPointerMove, onPointerUp: endPointer, onPointerCancel: endPointer, onLostPointerCapture: endPointer } }\n}\n","import {\n useCallback, useEffect, useRef, useState, useSyncExternalStore,\n} from 'react'\nimport {\n IconChevronLeftOutline14, IconChevronRightOutline14, IconCloseOutline16,\n IconCopyOutline16, IconDownloadOutline16, IconEditOutline16, IconFullscreenOutline16,\n} from '@deepseek-ai/dsh-client-ui-primitives'\nimport {\n imageItemsForButton, NativeImageViewerService, nativeImageButton,\n} from './viewer.js'\nimport { CSS as VIEWER_CSS } from './styles.js'\nimport { useImageTransform } from './image-transform.js'\n\nexport const name = 'dsh-image-viewer'\nexport const inject = ['locale', 'slots']\n\nconst LOCALES = {\n en: {\n dialog: 'Image viewer', close: 'Close', fit: 'Fit', actual: '100%', download: 'Download',\n annotate: 'Mark region', cancelAnnotate: 'Cancel marking', regions: 'Region notes', regionHint: 'Click a point on the image, then add a note.',\n note: 'Region {value}', notePlaceholder: 'Describe what should change here…', removeNote: 'Remove region note',\n hideNotes: 'Hide notes', copyNotes: 'Copy notes', copied: 'Copied', previous: 'Previous image', next: 'Next image',\n zoomHint: 'Wheel to zoom · drag to pan · double-click for 100%', preparing: 'Preparing…', failed: 'Could not prepare this image.',\n loading: 'Loading image…', loadFailed: 'Image could not be loaded.', retry: 'Retry', copyFailed: 'Copy failed. Try again.',\n },\n zh: {\n dialog: '图片查看器', close: '关闭', fit: '适应窗口', actual: '原始大小', download: '下载',\n annotate: '标记区域', cancelAnnotate: '取消标记', regions: '区域备注', regionHint: '点击图片中的位置,然后填写备注。',\n note: '区域 {value}', notePlaceholder: '描述这里需要怎样调整…', removeNote: '删除区域备注',\n hideNotes: '收起备注', copyNotes: '复制备注', copied: '已复制', previous: '上一张图片', next: '下一张图片',\n zoomHint: '滚轮缩放 · 拖动查看 · 双击切换原始大小', preparing: '正在准备…', failed: '暂时无法准备这张图片。',\n loading: '正在加载图片…', loadFailed: '图片加载失败。', retry: '重试', copyFailed: '复制失败,请重试。',\n },\n}\n\nconst fill = (value, variables) => Object.entries(variables).reduce(\n (text, [key, replacement]) => text.replaceAll(`{${key}}`, String(replacement)),\n value,\n)\nconst clamp = (value, min, max) => Math.min(max, Math.max(min, value))\nconst bytesLabel = bytes => bytes === undefined ? undefined : bytes < 1024 * 1024\n ? `${Math.max(0.1, bytes / 1024).toLocaleString(undefined, { maximumFractionDigits: 1 })} KB`\n : `${(bytes / 1024 / 1024).toLocaleString(undefined, { maximumFractionDigits: 1 })} MB`\nconst downloadName = name => {\n const cleaned = String(name || 'image.png').replace(/[<>:\"/\\\\|?*\\u0000-\\u001f]/gu, '-').replace(/[. ]+$/u, '').trim()\n return cleaned === '' ? 'image.png' : cleaned\n}\nconst noteText = (annotations, t) => annotations.map((annotation, index) => {\n const label = fill(t('note'), { value: index + 1 })\n return `${label} (${Math.round(annotation.x * 100)}%, ${Math.round(annotation.y * 100)}%): ${annotation.note.trim()}`\n}).filter(line => !line.endsWith(': ')).join('\\n')\n\nfunction ViewerAction({ action, annotations, item, service }) {\n const [state, setState] = useState('idle')\n const invoke = async () => {\n if (state === 'pending') return\n setState('pending')\n try {\n await action.onInvoke({ annotations, item, src: item.src })\n setState('idle')\n if (action.closeOnSuccess) service.close()\n } catch { setState('failed') }\n }\n const label = state === 'pending' ? action.pendingLabel : state === 'failed' ? action.errorLabel : action.label\n return <button type=\"button\" className=\"niv-button\" disabled={state === 'pending'} onClick={() => { void invoke() }}><span className=\"niv-label\">{label}</span></button>\n}\n\nfunction ViewerDownload({ download, item, t }) {\n const [state, setState] = useState('idle')\n const invoke = async () => {\n if (state === 'pending') return\n setState('pending')\n try { await download.onInvoke({ item, src: item.src }); setState('idle') } catch { setState('failed') }\n }\n const label = state === 'pending' ? download.pendingLabel ?? t('preparing') : state === 'failed' ? download.errorLabel ?? t('failed') : t('download')\n return <button type=\"button\" className=\"niv-download\" disabled={state === 'pending'} onClick={() => { void invoke() }}><IconDownloadOutline16 /><span className=\"niv-label\">{label}</span></button>\n}\n\nfunction ViewerOverlay({ service, t }) {\n const request = useSyncExternalStore(service.subscribe, service.getSnapshot)\n const [index, setIndex] = useState(0)\n const [imageState, setImageState] = useState('loading')\n const [attempt, setAttempt] = useState(0)\n const [copyFailed, setCopyFailed] = useState(false)\n const [annotating, setAnnotating] = useState(false)\n const [annotationsByImage, setAnnotationsByImage] = useState(service.getAnnotationsSnapshot)\n const annotationsByImageRef = useRef(annotationsByImage)\n const [selected, setSelected] = useState()\n const [focusNote, setFocusNote] = useState()\n const [copied, setCopied] = useState(false)\n const rootRef = useRef(null)\n annotationsByImageRef.current = annotationsByImage\n\n useEffect(() => {\n if (request === undefined) return\n setIndex(request.index)\n setAnnotating(false)\n setSelected(undefined)\n setCopied(false)\n }, [request?.revision])\n\n const item = request?.items[index]\n const { transform, transformRef, dragging, pixelScale, stageRef, surfaceRef, imageRef, fit, actual, measure, setZoomAt, resetGesture, pointerHandlers } = useImageTransform(`${request?.revision}:${item?.id}:${item?.src}`)\n const annotations = item === undefined ? [] : annotationsByImage[item.id] ?? []\n const setAnnotations = useCallback((update) => {\n if (item === undefined) return\n const previous = annotationsByImageRef.current[item.id] ?? []\n const next = typeof update === 'function' ? update(previous) : update\n const snapshot = { ...annotationsByImageRef.current, [item.id]: next }\n annotationsByImageRef.current = snapshot\n service.setAnnotations(item.id, next)\n setAnnotationsByImage(snapshot)\n }, [item?.id, service])\n\n useEffect(() => {\n if (request === undefined) return undefined\n const previousOverflow = document.body.style.overflow\n document.body.style.overflow = 'hidden'\n rootRef.current?.focus()\n const onKeyDown = event => {\n if (event.defaultPrevented || event.isComposing) return\n if (event.key === 'Escape') {\n event.preventDefault()\n event.stopPropagation()\n if (event.target instanceof Element && event.target.closest('.niv-inline-note') !== null) {\n setSelected(undefined)\n return\n }\n service.close()\n return\n }\n if (event.ctrlKey || event.metaKey || event.altKey) return\n const editing = event.target instanceof Element && event.target.closest('input,textarea,select,[contenteditable=\"true\"]') !== null\n if (!editing && ['ArrowLeft', 'ArrowRight', '+', '=', '-', 'f', 'F'].includes(event.key)) event.stopPropagation()\n if (!editing && event.key === 'ArrowLeft' && request.items.length > 1) {\n event.preventDefault(); setIndex(value => (value - 1 + request.items.length) % request.items.length)\n } else if (!editing && event.key === 'ArrowRight' && request.items.length > 1) {\n event.preventDefault(); setIndex(value => (value + 1) % request.items.length)\n } else if (!editing && (event.key === '+' || event.key === '=')) {\n event.preventDefault(); const box = stageRef.current?.getBoundingClientRect(); if (box) setZoomAt(transformRef.current.zoom * 1.2, box.left + box.width / 2, box.top + box.height / 2)\n } else if (!editing && event.key === '-') {\n event.preventDefault(); const box = stageRef.current?.getBoundingClientRect(); if (box) setZoomAt(transformRef.current.zoom / 1.2, box.left + box.width / 2, box.top + box.height / 2)\n } else if (!editing && event.key.toLowerCase() === 'f') {\n event.preventDefault(); fit()\n } else if (event.key === 'Tab') {\n const controls = [...rootRef.current.querySelectorAll('button:not(:disabled),a[href],input:not(:disabled),textarea:not(:disabled),[tabindex]:not([tabindex=\"-1\"])')]\n const first = controls[0]\n const last = controls.at(-1)\n if (event.shiftKey && (document.activeElement === first || document.activeElement === rootRef.current)) { event.preventDefault(); last?.focus() }\n else if (!event.shiftKey && (document.activeElement === last || document.activeElement === rootRef.current)) { event.preventDefault(); first?.focus() }\n }\n }\n const root = rootRef.current\n root.addEventListener('keydown', onKeyDown)\n return () => {\n document.body.style.overflow = previousOverflow\n root.removeEventListener('keydown', onKeyDown)\n }\n }, [request, service, fit, setZoomAt])\n\n useEffect(() => {\n if (focusNote === undefined) return\n const field = rootRef.current?.querySelector(`[data-note-id=\"${CSS.escape(focusNote)}\"] textarea`)\n field?.focus()\n setFocusNote(undefined)\n }, [focusNote, selected, annotations.length])\n\n useEffect(() => {\n setAnnotating(false)\n setSelected(undefined)\n setImageState('loading')\n setCopyFailed(false)\n setCopied(false)\n }, [item?.id, item?.src, request?.revision])\n\n const addAnnotation = event => {\n if (!annotating || event.target.closest('.niv-annotation')) return\n const bounds = surfaceRef.current?.getBoundingClientRect()\n if (bounds === undefined) return\n const annotation = {\n id: crypto.randomUUID(),\n x: clamp((event.clientX - bounds.left) / bounds.width, 0, 1),\n y: clamp((event.clientY - bounds.top) / bounds.height, 0, 1),\n note: '',\n }\n setAnnotations(current => [...current, annotation])\n setAnnotating(false)\n setSelected(annotation.id)\n setFocusNote(annotation.id)\n }\n const copyNotes = async () => {\n const text = noteText(annotations, t)\n if (text === '') return\n try {\n await navigator.clipboard.writeText(text)\n setCopied(true)\n setCopyFailed(false)\n } catch { setCopyFailed(true) }\n }\n\n if (request === undefined || item === undefined) return null\n const meta = [item.width && item.height ? `${item.width} × ${item.height}` : undefined, bytesLabel(item.bytes)].filter(Boolean).join(' · ')\n const showCounter = request.items.length > 1\n return <div ref={rootRef} className=\"niv-root\" role=\"dialog\" aria-modal=\"true\" aria-label={t('dialog')} tabIndex={-1}>\n <div className=\"niv-title\"><strong>{item.name}</strong>{meta !== '' ? <small>{meta}</small> : null}</div>\n <header className=\"niv-topbar\" role=\"toolbar\" aria-label={t('dialog')}>\n <div className=\"niv-actions\">\n {request.annotations ? <button type=\"button\" className=\"niv-button\" data-active={annotating} aria-label={annotating ? t('cancelAnnotate') : t('annotate')} aria-pressed={annotating} disabled={imageState !== 'ready'} onClick={() => { resetGesture(); setAnnotating(value => !value) }}><IconEditOutline16 /><span className=\"niv-label\">{annotating ? t('cancelAnnotate') : t('annotate')}</span></button> : null}\n {annotations.length > 0 ? <button type=\"button\" className=\"niv-button\" data-active={selected !== undefined} onClick={() => { const first = annotations[0]; setSelected(current => current === undefined ? first.id : undefined); if (selected === undefined) setFocusNote(first.id) }}>{annotations.length} <span className=\"niv-label\">{t('regions')}</span></button> : null}\n <button type=\"button\" className=\"niv-button\" aria-label={t('fit')} onClick={fit}><IconFullscreenOutline16 /><span className=\"niv-label\">{t('fit')}</span></button>\n <button type=\"button\" className=\"niv-button\" disabled={imageState !== 'ready'} onClick={actual}>{t('actual')}</button>\n <span className=\"niv-zoom\">{Math.round(transform.zoom * pixelScale * 100)}%</span>\n {item.download === undefined\n ? <a className=\"niv-download\" href={item.src} download={downloadName(item.name)}><IconDownloadOutline16 /><span className=\"niv-label\">{t('download')}</span></a>\n : <ViewerDownload key={item.src} download={item.download} item={item} t={t} />}\n {item.actions.map(action => <ViewerAction action={action} annotations={annotations} item={item} service={service} key={`${item.src}:${action.id}`} />)}\n </div>\n </header>\n <button type=\"button\" className=\"niv-close-floating\" aria-label={t('close')} onClick={() => service.close()}><IconCloseOutline16 /></button>\n <div className=\"niv-workspace\">\n <main ref={stageRef} className=\"niv-stage\" data-dragging={dragging} data-annotating={annotating} onClick={event => { if (event.target === event.currentTarget && !annotating && transform.zoom === 1) service.close() }} {...(!annotating && imageState === 'ready' ? pointerHandlers : {})} onDoubleClick={event => { if (event.target.closest('button,a,input,textarea') || imageState !== 'ready') return; if (transform.zoom === 1) actual(); else fit() }}>\n {imageState !== 'ready' ? <div className=\"niv-load-status\" role={imageState === 'error' ? 'alert' : 'status'}>{t(imageState === 'error' ? 'loadFailed' : 'loading')}{imageState === 'error' ? <button type=\"button\" className=\"niv-button\" onClick={() => { setImageState('loading'); setAttempt(value => value + 1) }}>{t('retry')}</button> : null}</div> : null}\n <div ref={surfaceRef} className=\"niv-surface\" onClick={addAnnotation} style={{ visibility: imageState === 'ready' ? 'visible' : 'hidden', transform: `translate3d(${transform.x}px,${transform.y}px,0) scale(${transform.zoom})` }}>\n <img key={`${request.revision}:${item.id}:${attempt}`} ref={imageRef} className=\"niv-image\" src={item.src} alt={item.name} draggable=\"false\" onLoad={() => { setImageState('ready'); measure() }} onError={() => setImageState('error')} />\n {annotations.map((annotation, position) => <div className=\"niv-annotation\" data-x={annotation.x < 0.38 ? 'right' : annotation.x > 0.62 ? 'left' : 'center'} data-y={annotation.y < 0.28 ? 'down' : 'up'} style={{ left: `${annotation.x * 100}%`, top: `${annotation.y * 100}%`, transform: `translate(-50%,-50%) scale(${1 / transform.zoom})` }} key={annotation.id}>\n <button type=\"button\" className=\"niv-pin\" data-active={selected === annotation.id} aria-label={fill(t('note'), { value: position + 1 })} onClick={event => { event.stopPropagation(); const opening = selected !== annotation.id; setSelected(opening ? annotation.id : undefined); if (opening) setFocusNote(annotation.id) }}>{position + 1}</button>\n {selected === annotation.id ? <div className=\"niv-inline-note\" data-note-id={annotation.id} onClick={event => event.stopPropagation()}>\n <span className=\"niv-inline-index\">{position + 1}</span>\n <textarea value={annotation.note} rows={1} aria-label={fill(t('note'), { value: position + 1 })} placeholder={t('notePlaceholder')} onChange={event => { const note = event.target.value; setAnnotations(current => current.map(entry => entry.id === annotation.id ? { ...entry, note } : entry)) }} onKeyDown={event => {\n if ((event.key === 'Enter' && !event.shiftKey) || event.key === 'Escape') {\n event.preventDefault()\n event.stopPropagation()\n event.nativeEvent?.stopImmediatePropagation?.()\n setSelected(undefined)\n }\n }} />\n <button type=\"button\" className=\"niv-note-remove\" aria-label={t('removeNote')} onClick={event => { event.stopPropagation(); setAnnotations(current => current.filter(entry => entry.id !== annotation.id)); setSelected(undefined) }}><IconCloseOutline16 /></button>\n </div> : null}\n </div>)}\n </div>\n {showCounter ? <>\n <button type=\"button\" className=\"niv-button niv-icon-only niv-nav niv-prev\" aria-label={t('previous')} onClick={event => { event.stopPropagation(); setIndex(value => (value - 1 + request.items.length) % request.items.length) }}><IconChevronLeftOutline14 /></button>\n <button type=\"button\" className=\"niv-button niv-icon-only niv-nav niv-next\" aria-label={t('next')} onClick={event => { event.stopPropagation(); setIndex(value => (value + 1) % request.items.length) }}><IconChevronRightOutline14 /></button>\n <span className=\"niv-counter\">{index + 1} / {request.items.length}</span>\n </> : annotating ? <span className=\"niv-hint\">{t('regionHint')}</span> : transform.zoom === 1 ? <span className=\"niv-hint\">{t('zoomHint')}</span> : null}\n </main>\n {annotations.some(annotation => annotation.note.trim() !== '') ? <button type=\"button\" className=\"niv-copy-notes\" onClick={() => { void copyNotes() }}><IconCopyOutline16 />{copyFailed ? t('copyFailed') : copied ? t('copied') : t('copyNotes')}</button> : null}\n </div>\n </div>\n}\n\nfunction installOfficialImageBridge(service) {\n const onClick = event => {\n const match = nativeImageButton(event.target)\n if (match === undefined) return\n const { items, index } = imageItemsForButton(match)\n event.preventDefault()\n event.stopPropagation()\n event.stopImmediatePropagation()\n service.open({ items, index, opener: match.button, source: 'dsh-native', annotations: true })\n }\n document.addEventListener('click', onClick, true)\n return () => { document.removeEventListener('click', onClick, true) }\n}\n\nexport function apply(ctx) {\n const service = new NativeImageViewerService()\n ctx.effect(() => ctx.locale.register(name, LOCALES), `${name}: dictionaries`)\n ctx.effect(() => {\n const style = document.createElement('style')\n style.dataset.plugin = name\n style.textContent = VIEWER_CSS\n document.head.appendChild(style)\n return () => { style.remove() }\n }, `${name}: styles`)\n ctx.effect(() => {\n const disposeService = ctx.reflect.provide('nativeImageViewer', service)\n const disposeBridge = installOfficialImageBridge(service)\n return () => { disposeBridge(); void disposeService() }\n }, `${name}: optional viewer service and native image bridge`)\n const t = ctx.locale.bind(name)\n ctx.slots.inject('shell.overlay', () => ctx.slots.register({\n name: 'shell.overlay', id: name, order: 20, inject: () => ({ service, t }),\n }, ViewerOverlay))\n}\n\nexport { NativeImageViewerService, normalizeViewerRequest } from './viewer.js'\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-image-viewer",
|
|
3
|
-
"version": "0.1.0-beta.
|
|
3
|
+
"version": "0.1.0-beta.11",
|
|
4
4
|
"description": "Zoom, pan, download, gallery, and region-note image viewer for DeepSeek Harness",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"dsh-plugin",
|
|
@@ -63,10 +63,10 @@
|
|
|
63
63
|
},
|
|
64
64
|
"peerDependencies": {
|
|
65
65
|
"@deepseek-ai/cordis": "4.0.1 || 4.0.2",
|
|
66
|
-
"@deepseek-ai/dsh-client-locale": "0.1.1-rc.2 || 0.1.2-rc.1 || 0.1.2-alpha.2 || 0.1.2-alpha.3 || 0.1.3-alpha.2",
|
|
67
|
-
"@deepseek-ai/dsh-client-ui-layout": "0.1.1-rc.2 || 0.1.2-rc.1 || 0.1.2-alpha.2 || 0.1.2-alpha.3 || 0.1.3-alpha.2",
|
|
68
|
-
"@deepseek-ai/dsh-client-ui-primitives": "0.1.1-rc.2 || 0.1.2-rc.1 || 0.1.2-alpha.2 || 0.1.2-alpha.3 || 0.1.3-alpha.2",
|
|
69
|
-
"@deepseek-ai/dsh-client-ui-slots": "0.1.1-rc.2 || 0.1.2-rc.1 || 0.1.2-alpha.2 || 0.1.2-alpha.3 || 0.1.3-alpha.2",
|
|
66
|
+
"@deepseek-ai/dsh-client-locale": "0.1.1-rc.2 || 0.1.2-rc.1 || 0.1.2-alpha.2 || 0.1.2-alpha.3 || 0.1.3-alpha.2 || 0.1.5-alpha.1",
|
|
67
|
+
"@deepseek-ai/dsh-client-ui-layout": "0.1.1-rc.2 || 0.1.2-rc.1 || 0.1.2-alpha.2 || 0.1.2-alpha.3 || 0.1.3-alpha.2 || 0.1.5-alpha.1",
|
|
68
|
+
"@deepseek-ai/dsh-client-ui-primitives": "0.1.1-rc.2 || 0.1.2-rc.1 || 0.1.2-alpha.2 || 0.1.2-alpha.3 || 0.1.3-alpha.2 || 0.1.5-alpha.1",
|
|
69
|
+
"@deepseek-ai/dsh-client-ui-slots": "0.1.1-rc.2 || 0.1.2-rc.1 || 0.1.2-alpha.2 || 0.1.2-alpha.3 || 0.1.3-alpha.2 || 0.1.5-alpha.1",
|
|
70
70
|
"react": "^18.2.0"
|
|
71
71
|
},
|
|
72
72
|
"peerDependenciesMeta": {
|
|
@@ -97,6 +97,7 @@
|
|
|
97
97
|
"@deepseek-ai/dsh-client-ui-slots": "0.1.2-rc.1",
|
|
98
98
|
"playwright": "1.62.1",
|
|
99
99
|
"react": "18.3.1",
|
|
100
|
+
"react-dom": "18.3.1",
|
|
100
101
|
"tsdown": "0.22.2"
|
|
101
102
|
},
|
|
102
103
|
"scripts": {
|