dsh-image-viewer 0.1.0 → 0.1.2-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.en.md CHANGED
@@ -5,6 +5,8 @@
5
5
 
6
6
  # DSH Image Viewer
7
7
 
8
+ Package: `dsh-image-viewer`. [Awesome DSH listing](https://github.com/awesome-dsh-plugin/awesome-dsh-plugin/blob/main/data/plugins/WSL043__dsh-image-viewer.yml) · [Chat Manager](https://github.com/WSL043/dsh-chat-manager)
9
+
8
10
  A compact, provider-neutral image viewer for DeepSeek Harness. It upgrades images already shown by DSH without replacing the conversation, attachment, or model workflows.
9
11
 
10
12
  [![CI](https://github.com/WSL043/dsh-image-viewer/actions/workflows/ci.yml/badge.svg)](https://github.com/WSL043/dsh-image-viewer/actions/workflows/ci.yml)
@@ -30,8 +32,10 @@ Release checks exercise real attachments on stable and current Alpha DSH: galler
30
32
 
31
33
  - Wheel zoom centered on the pointer, drag-to-pan, touch pinch, and double-click 100% view.
32
34
  - Fit and original-size controls, original-file download, keyboard navigation, and multi-image galleries.
35
+ - 0.1.1: download progress when the file size is available, cancellation and retry; switching images or closing the viewer cancels the active download.
33
36
  - Visible filename, dimensions and pixel-scale percentage; very wide images can reach 100%, and window resizing keeps the image within reach.
34
37
  - Loading and retryable error states, gesture reset on image changes, and independent notes for unnamed images.
38
+ - 0.1.1: closing an annotated native DSH image adds a numbered PNG and notes to the originating conversation draft, preserving existing text without sending. Unchanged notes are not added twice. Failed intake preserves notes with retry and close-only choices.
35
39
  - One-shot region marking with each note edited beside its numbered image marker. Enter saves and collapses the note;
36
40
  Shift+Enter adds a new line.
37
41
  - Light and dark themes through DSH design tokens, responsive layout, focus containment, and reduced-motion support.
@@ -61,9 +65,15 @@ dsh plugin --profile web remove dsh-image-viewer
61
65
 
62
66
  Uninstalling restores DSH's built-in image lightbox. It does not remove conversations, attachments, generated images, provider plugins, or credentials.
63
67
 
68
+ ## Custom download integration
69
+
70
+ When calling `nativeImageViewer.open()`, an item's `download.onInvoke` receives `{ item, src, signal, onProgress }`. Pass `signal` to the download request and report bytes through `onProgress({ loaded, total })`. Omit `total` when the size is unknown; the viewer shows a preparing state and a cancel button.
71
+
72
+ Existing callbacks remain compatible. Custom transfers must honor `signal` to stop their underlying work. The viewer ignores late progress and results from cancelled operations. Download authorization and original-file integrity checks remain the image provider's responsibility.
73
+
64
74
  ## Privacy
65
75
 
66
- Image bytes stay in the current browser profile. The plugin reads only URLs already rendered by DSH, does not upload images, does not call a model, and does not read provider credentials. Region notes remain available when the same image is reopened during the current DSH page session, but are not written to conversation storage unless another plugin explicitly uses them for a user-requested action.
76
+ The plugin reads only URLs already rendered by DSH, does not call a model, and does not read provider credentials. The annotation workflow adds images and notes through DSH's attachment and draft APIs; the user decides whether to send. Notes remain available when reopening an image within the current page, which does not imply a sent message or permanent conversation storage.
67
77
 
68
78
  ## Support
69
79
 
package/README.md CHANGED
@@ -3,10 +3,12 @@
3
3
 
4
4
  <div align="center">
5
5
 
6
- # DSH 图片查看器
6
+ # DSH Image Viewer · 图片查看器
7
7
 
8
8
  面向 DeepSeek Harness 的简洁、与模型和供应商无关的图片查看器。它只增强 DSH 已经显示的图片,不替换会话、附件或模型流程。
9
9
 
10
+ 插件包名:`dsh-image-viewer`。支持图片缩放、原图下载、图库浏览与区域标注。[Awesome DSH 收录](https://github.com/awesome-dsh-plugin/awesome-dsh-plugin/blob/main/data/plugins/WSL043__dsh-image-viewer.yml) · [会话管理插件](https://github.com/WSL043/dsh-chat-manager)
11
+
10
12
  [![CI](https://github.com/WSL043/dsh-image-viewer/actions/workflows/ci.yml/badge.svg)](https://github.com/WSL043/dsh-image-viewer/actions/workflows/ci.yml)
11
13
  [![npm](https://img.shields.io/npm/v/dsh-image-viewer?logo=npm&label=npm)](https://www.npmjs.com/package/dsh-image-viewer)
12
14
  [![npm 总下载量](https://img.shields.io/npm/dt/dsh-image-viewer?logo=npm&label=%E6%80%BB%E4%B8%8B%E8%BD%BD%E9%87%8F)](https://www.npmjs.com/package/dsh-image-viewer)
@@ -30,9 +32,11 @@
30
32
 
31
33
  - 以鼠标位置为中心的滚轮缩放、拖动查看、触控双指缩放和双击原始大小。
32
34
  - 适应窗口、原始大小、原图下载、键盘切换和多图浏览。
35
+ - 0.1.1:下载时显示可用的进度,支持取消和重试;切换图片或关闭查看器会取消正在进行的下载。
33
36
  - 显示图片名称、尺寸与真实像素缩放比例;超宽大图也能切换到 100%,调整窗口后保持图片可见。
34
37
  - 图片加载中和加载失败都有明确提示,失败可重试;切换图片会重置拖拽状态,区域备注不会串到另一张未命名图片。
35
38
  - 一次点击标记一个区域,备注直接显示在图片编号附近并自动获得输入焦点;Enter 保存并收起,Shift+Enter 换行。
39
+ - 0.1.1:在 DSH 原生图片入口添加备注后,关闭查看器会把带编号的 PNG 和备注加入打开图片时的会话草稿,保留已有文字,不自动发送。没有修改备注时不会重复添加;失败时保留标注并可重试或仅关闭。
36
40
  - 使用 DSH 设计令牌适配亮色、暗色、响应式布局、焦点约束和减少动态效果设置。
37
41
  - 提供可选的 `nativeImageViewer` 客户端服务,图片生成插件可以按需增加自己的后续操作。
38
42
 
@@ -60,9 +64,15 @@ dsh plugin --profile web remove dsh-image-viewer
60
64
 
61
65
  卸载后恢复 DSH 内置图片灯箱,不会删除会话、附件、生成图片、供应商插件或凭据。
62
66
 
67
+ ## 自定义下载接入
68
+
69
+ 调用 `nativeImageViewer.open()` 时,图片条目的 `download.onInvoke` 会收到 `{ item, src, signal, onProgress }`。将 `signal` 传给下载请求,并通过 `onProgress({ loaded, total })` 上报字节数。文件总大小未知时省略 `total`,查看器显示准备状态和取消按钮。
70
+
71
+ 旧的下载回调仍可使用;要实际停止自定义传输,回调需要响应 `signal`。查看器会忽略已取消操作的迟到进度和结果。下载权限及原图完整性校验仍由提供图片的插件负责。
72
+
63
73
  ## 隐私
64
74
 
65
- 图片数据保留在当前浏览器配置中。插件只读取 DSH 已经渲染的图片 URL,不上传图片、不调用模型,也不读取供应商凭据。当前 DSH 页面会话内重新打开同一张图片时,区域备注仍会保留;除非其他插件响应用户的明确操作,否则不会写入会话存储。
75
+ 插件只读取 DSH 已经渲染的图片 URL,不调用模型或读取供应商凭据。下一版的标注操作会通过 DSH 的附件与输入框接口加入当前草稿,由用户决定是否发送。当前页面内重新打开同一张图片时,区域备注仍会保留;这不等于已发送或永久保存会话。
66
76
 
67
77
  ## 反馈
68
78
 
@@ -8,6 +8,8 @@
8
8
  "0.1.2-alpha.2",
9
9
  "0.1.2-alpha.3",
10
10
  "0.1.3-alpha.2",
11
- "0.1.5-alpha.1"
11
+ "0.1.5-alpha.1",
12
+ "0.1.6-alpha.1",
13
+ "0.1.6-alpha.2"
12
14
  ]
13
15
  }
package/lib/client.js CHANGED
@@ -46,7 +46,8 @@ window.__ModuleLoader__.load({
46
46
  index: Math.max(0, Math.min(items.length - 1, requestedIndex)),
47
47
  opener: typeof HTMLElement !== "undefined" && request?.opener instanceof HTMLElement ? request.opener : void 0,
48
48
  source: typeof request?.source === "string" ? request.source : "dsh",
49
- annotations: request?.annotations !== false
49
+ annotations: request?.annotations !== false,
50
+ commitAnnotations: typeof request?.commitAnnotations === "function" ? request.commitAnnotations : void 0
50
51
  };
51
52
  }
52
53
  var NativeImageViewerService = class {
@@ -54,6 +55,8 @@ window.__ModuleLoader__.load({
54
55
  #revision = 0;
55
56
  #snapshot;
56
57
  #annotationsByImage = /* @__PURE__ */ new Map();
58
+ #openingAnnotations = /* @__PURE__ */ new Map();
59
+ #closing = false;
57
60
  constructor() {
58
61
  this.subscribe = (listener) => {
59
62
  this.#listeners.add(listener);
@@ -70,6 +73,7 @@ window.__ModuleLoader__.load({
70
73
  else this.#annotationsByImage.set(imageId, annotations.map((annotation) => ({ ...annotation })));
71
74
  }
72
75
  open(request) {
76
+ if (this.#closing) return false;
73
77
  const normalized = normalizeViewerRequest(request);
74
78
  if (normalized === void 0) return false;
75
79
  this.#revision += 1;
@@ -77,11 +81,39 @@ window.__ModuleLoader__.load({
77
81
  ...normalized,
78
82
  revision: this.#revision
79
83
  };
84
+ this.#openingAnnotations = new Map(normalized.items.map((item) => [item.id, JSON.stringify(this.#annotationsByImage.get(item.id) || [])]));
80
85
  this.#emit();
81
86
  return true;
82
87
  }
83
- close() {
88
+ async close({ discard = false } = {}) {
84
89
  if (this.#snapshot === void 0) return;
90
+ if (this.#closing) return;
91
+ const pending = this.#snapshot.items.map((item) => ({
92
+ item,
93
+ annotations: this.#annotationsByImage.get(item.id) || []
94
+ })).filter(({ item, annotations }) => annotations.some((note) => note.note.trim()) && JSON.stringify(annotations) !== this.#openingAnnotations.get(item.id));
95
+ if (!discard && pending.length && this.#snapshot.commitAnnotations) {
96
+ this.#closing = true;
97
+ this.#snapshot = {
98
+ ...this.#snapshot,
99
+ committing: true,
100
+ commitError: false
101
+ };
102
+ this.#emit();
103
+ try {
104
+ await this.#snapshot.commitAnnotations(pending);
105
+ } catch {
106
+ this.#snapshot = {
107
+ ...this.#snapshot,
108
+ committing: false,
109
+ commitError: true
110
+ };
111
+ this.#closing = false;
112
+ this.#emit();
113
+ return false;
114
+ }
115
+ this.#closing = false;
116
+ }
85
117
  const opener = this.#snapshot.opener;
86
118
  this.#snapshot = void 0;
87
119
  this.#emit();
@@ -146,6 +178,7 @@ window.__ModuleLoader__.load({
146
178
  //#endregion
147
179
  //#region src/styles.js
148
180
  const CSS$1 = String.raw`
181
+ .niv-draft-status{position:absolute;top:76px;left:50%;transform:translateX(-50%);z-index:10;max-width:calc(100% - 48px);padding:10px 16px;border-radius:12px;background:#26272a;color:#fff;font-size:13px;line-height:20px}
149
182
  .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)}
150
183
  .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}
151
184
  .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}
@@ -339,11 +372,122 @@ window.__ModuleLoader__.load({
339
372
  };
340
373
  }
341
374
  //#endregion
375
+ //#region src/image-download.js
376
+ function downloadPercent(value) {
377
+ const { loaded, total } = value ?? {};
378
+ if (!Number.isFinite(loaded) || loaded < 0 || !Number.isFinite(total) || total <= 0) return void 0;
379
+ return Math.min(100, Math.floor(loaded / total * 100));
380
+ }
381
+ async function readImageBlob(src, { signal, onProgress }) {
382
+ const response = await fetch(src, { signal });
383
+ if (!response.ok) throw new Error(`Image download failed: ${response.status}`);
384
+ if (!response.body) return response.blob();
385
+ const length = response.headers.get("content-encoding") ? void 0 : Number(response.headers.get("content-length"));
386
+ const total = Number.isFinite(length) && length > 0 ? length : void 0;
387
+ const reader = response.body.getReader();
388
+ const chunks = [];
389
+ let loaded = 0;
390
+ try {
391
+ while (true) {
392
+ signal.throwIfAborted();
393
+ const { done, value } = await reader.read();
394
+ if (done) break;
395
+ chunks.push(value);
396
+ loaded += value.byteLength;
397
+ onProgress({
398
+ loaded,
399
+ total
400
+ });
401
+ }
402
+ signal.throwIfAborted();
403
+ return new Blob(chunks, { type: response.headers.get("content-type") || "" });
404
+ } finally {
405
+ reader.releaseLock();
406
+ }
407
+ }
408
+ //#endregion
409
+ //#region src/annotation-draft.js
410
+ async function renderAnnotationImage(blob, annotations) {
411
+ const image = await createImageBitmap(blob);
412
+ try {
413
+ const canvas = document.createElement("canvas");
414
+ canvas.width = image.width;
415
+ canvas.height = image.height;
416
+ const context = canvas.getContext("2d");
417
+ if (!context) throw new Error("Canvas unavailable");
418
+ context.drawImage(image, 0, 0);
419
+ const radius = Math.max(12, Math.min(image.width, image.height) / 60);
420
+ annotations.forEach((annotation, index) => {
421
+ const x = Math.max(radius, Math.min(image.width - radius, annotation.x * image.width));
422
+ const y = Math.max(radius, Math.min(image.height - radius, annotation.y * image.height));
423
+ context.beginPath();
424
+ context.arc(x, y, radius, 0, Math.PI * 2);
425
+ context.fillStyle = "#26272a";
426
+ context.fill();
427
+ context.strokeStyle = "#ffffff";
428
+ context.lineWidth = Math.max(2, radius / 7);
429
+ context.stroke();
430
+ context.fillStyle = "#ffffff";
431
+ context.font = `600 ${radius}px sans-serif`;
432
+ context.textAlign = "center";
433
+ context.textBaseline = "middle";
434
+ context.fillText(String(index + 1), x, y);
435
+ });
436
+ return await new Promise((resolve, reject) => canvas.toBlob((value) => value ? resolve(value) : reject(/* @__PURE__ */ new Error("Image encoding failed")), "image/png"));
437
+ } finally {
438
+ image.close();
439
+ }
440
+ }
441
+ const hasOwn = Object.prototype.hasOwnProperty;
442
+ function currentSessionId(snapshot) {
443
+ if (snapshot !== null && typeof snapshot === "object" && hasOwn.call(snapshot, "current")) return snapshot.current;
444
+ const retained = Object.entries(snapshot?.byId ?? {}).filter(([, entry]) => (entry?.retainedBy?.mainView ?? 0) > 0);
445
+ return retained.length === 1 ? retained[0][0] : void 0;
446
+ }
447
+ function createAnnotationCommit(ctx, { readBlob, render = renderAnnotationImage, formatNotes }) {
448
+ let sessions, conversation, sessionId;
449
+ try {
450
+ sessions = ctx.get("sessions");
451
+ conversation = ctx.get("conversation");
452
+ sessionId = currentSessionId(sessions.list.getSnapshot());
453
+ } catch {}
454
+ return async (entries) => {
455
+ if (!sessionId || !conversation?.input?.for || currentSessionId(sessions.list.getSnapshot()) !== sessionId) throw new Error("Composer unavailable or session changed");
456
+ const prepared = await Promise.all(entries.map(async ({ item, annotations }) => {
457
+ const image = await render(await readBlob(item.src), annotations);
458
+ const name = `${String(item.name || "image").replace(/\.[^.]+$/, "")}-annotated.png`;
459
+ return {
460
+ file: new File([image], name, { type: "image/png" }),
461
+ text: `${name}\n${formatNotes(annotations)}`
462
+ };
463
+ }));
464
+ if (currentSessionId(sessions.list.getSnapshot()) !== sessionId) throw new Error("Session changed");
465
+ const input = conversation.input.for(sessions.scope(sessionId));
466
+ const state = input.state.getSnapshot();
467
+ if (state.phase !== "plain" || state.occurrences?.length) throw new Error("Composer busy or contains references");
468
+ const modern = typeof conversation.createDrafts === "function";
469
+ const add = modern ? input.addAttachments : input.addImages;
470
+ const release = modern ? conversation.releaseDraftAttachments : conversation.releaseDraftImages;
471
+ if (typeof add !== "function" || typeof release !== "function") throw new Error("Composer unavailable");
472
+ const created = modern ? conversation.createDrafts(sessionId, prepared.map((item) => item.file)) : conversation.createDraftImages(prepared.map((item) => item.file));
473
+ try {
474
+ if (!add.call(input, created.map((item) => item.id))) throw new Error("Composer busy");
475
+ } catch (error) {
476
+ release.call(conversation, created);
477
+ throw error;
478
+ }
479
+ input.setDraft([state.draft, ...prepared.map((item) => item.text)].filter(Boolean).join("\n\n"));
480
+ };
481
+ }
482
+ //#endregion
342
483
  //#region src/client.jsx
343
484
  const name = "dsh-image-viewer";
344
485
  const inject = ["locale", "slots"];
345
486
  const LOCALES = {
346
487
  en: {
488
+ addingDraft: "Adding image and notes to draft…",
489
+ draftFailed: "Could not add to draft. Return to the original session and keep the composer editable, then close to retry.",
490
+ closeWithoutDraft: "Close without adding",
347
491
  dialog: "Image viewer",
348
492
  close: "Close",
349
493
  fit: "Fit",
@@ -364,12 +508,17 @@ window.__ModuleLoader__.load({
364
508
  zoomHint: "Wheel to zoom · drag to pan · double-click for 100%",
365
509
  preparing: "Preparing…",
366
510
  failed: "Could not prepare this image.",
511
+ cancelDownload: "Cancel download",
512
+ cancel: "Cancel",
367
513
  loading: "Loading image…",
368
514
  loadFailed: "Image could not be loaded.",
369
515
  retry: "Retry",
370
516
  copyFailed: "Copy failed. Try again."
371
517
  },
372
518
  zh: {
519
+ addingDraft: "正在把图片和备注加入草稿…",
520
+ draftFailed: "未能加入草稿。请回到原会话并确保输入框可编辑,再关闭以重试。",
521
+ closeWithoutDraft: "仅关闭,不加入草稿",
373
522
  dialog: "图片查看器",
374
523
  close: "关闭",
375
524
  fit: "适应窗口",
@@ -390,6 +539,8 @@ window.__ModuleLoader__.load({
390
539
  zoomHint: "滚轮缩放 · 拖动查看 · 双击切换原始大小",
391
540
  preparing: "正在准备…",
392
541
  failed: "暂时无法准备这张图片。",
542
+ cancelDownload: "取消下载",
543
+ cancel: "取消",
393
544
  loading: "正在加载图片…",
394
545
  loadFailed: "图片加载失败。",
395
546
  retry: "重试",
@@ -398,7 +549,7 @@ window.__ModuleLoader__.load({
398
549
  };
399
550
  const fill = (value, variables) => Object.entries(variables).reduce((text, [key, replacement]) => text.replaceAll(`{${key}}`, String(replacement)), value);
400
551
  const clamp = (value, min, max) => Math.min(max, Math.max(min, value));
401
- const bytesLabel = (bytes) => bytes === void 0 ? void 0 : bytes < 1024 * 1024 ? `${Math.max(.1, bytes / 1024).toLocaleString(void 0, { maximumFractionDigits: 1 })} KB` : `${(bytes / 1024 / 1024).toLocaleString(void 0, { maximumFractionDigits: 1 })} MB`;
552
+ const bytesLabel = (bytes) => bytes === void 0 ? void 0 : bytes < 1048576 ? `${Math.max(.1, bytes / 1024).toLocaleString(void 0, { maximumFractionDigits: 1 })} KB` : `${(bytes / 1024 / 1024).toLocaleString(void 0, { maximumFractionDigits: 1 })} MB`;
402
553
  const downloadName = (name) => {
403
554
  const cleaned = String(name || "image.png").replace(/[<>:"/\\|?*\u0000-\u001f]/gu, "-").replace(/[. ]+$/u, "").trim();
404
555
  return cleaned === "" ? "image.png" : cleaned;
@@ -447,32 +598,43 @@ window.__ModuleLoader__.load({
447
598
  }
448
599
  function ViewerDownload({ download, item, t }) {
449
600
  const [state, setState] = (0, react.useState)("idle");
601
+ const [progress, setProgress] = (0, react.useState)(void 0);
450
602
  const controller = (0, react.useRef)(null);
451
- const buttonRef = (0, react.useRef)(null);
452
- const restoreFocus = (0, react.useRef)(false);
453
603
  (0, react.useEffect)(() => () => {
454
604
  controller.current?.abort();
455
- }, []);
456
- (0, react.useEffect)(() => {
457
- if (state === "pending" || !restoreFocus.current) return;
458
- restoreFocus.current = false;
459
- if (document.activeElement === document.body) buttonRef.current?.focus();
460
- }, [state]);
605
+ controller.current = null;
606
+ }, [
607
+ item.id,
608
+ item.src,
609
+ download
610
+ ]);
461
611
  const invoke = async () => {
462
- if (controller.current !== null) return;
612
+ if (controller.current !== null) {
613
+ controller.current.abort();
614
+ controller.current = null;
615
+ setState("idle");
616
+ setProgress(void 0);
617
+ return;
618
+ }
463
619
  const operation = new AbortController();
464
620
  controller.current = operation;
465
- restoreFocus.current = document.activeElement === buttonRef.current;
466
621
  setState("pending");
622
+ setProgress(void 0);
623
+ const onProgress = (value) => {
624
+ if (controller.current === operation) setProgress(downloadPercent(value));
625
+ };
467
626
  try {
468
627
  if (download !== void 0) await download.onInvoke({
469
628
  item,
470
- src: item.src
629
+ src: item.src,
630
+ signal: operation.signal,
631
+ onProgress
471
632
  });
472
633
  else {
473
- const response = await fetch(item.src, { signal: operation.signal });
474
- if (!response.ok) throw new Error(`Image download failed: ${response.status}`);
475
- const blob = await response.blob();
634
+ const blob = await readImageBlob(item.src, {
635
+ signal: operation.signal,
636
+ onProgress
637
+ });
476
638
  if (operation.signal.aborted) return;
477
639
  const url = URL.createObjectURL(blob);
478
640
  const link = document.createElement("a");
@@ -483,20 +645,19 @@ window.__ModuleLoader__.load({
483
645
  link.remove();
484
646
  setTimeout(() => URL.revokeObjectURL(url), 6e4);
485
647
  }
486
- if (!operation.signal.aborted) setState("idle");
648
+ if (controller.current === operation) setState("idle");
487
649
  } catch {
488
- if (!operation.signal.aborted) setState("failed");
650
+ if (controller.current === operation) setState("failed");
489
651
  } finally {
490
652
  if (controller.current === operation) controller.current = null;
491
653
  }
492
654
  };
493
- const label = state === "pending" ? download?.pendingLabel ?? t("preparing") : state === "failed" ? download?.errorLabel ?? t("failed") : t("download");
655
+ const label = state === "pending" ? `${download?.pendingLabel ?? t("preparing")}${progress === void 0 ? "" : ` ${progress}%`} · ${t("cancel")}` : state === "failed" ? download?.errorLabel ?? t("failed") : t("download");
494
656
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
495
- ref: buttonRef,
496
657
  type: "button",
497
658
  className: "niv-download",
498
- "aria-label": label,
499
- disabled: state === "pending",
659
+ "aria-label": state === "pending" ? t("cancelDownload") : label,
660
+ title: label,
500
661
  onClick: () => {
501
662
  invoke();
502
663
  },
@@ -538,6 +699,7 @@ window.__ModuleLoader__.load({
538
699
  const { transform, transformRef, dragging, pixelScale, geometry, stageRef, surfaceRef, imageRef, fit, actual, measure, setZoomAt, resetGesture, pointerHandlers } = useImageTransform(`${request?.revision}:${item?.id}:${item?.src}`);
539
700
  const annotations = item === void 0 ? [] : annotationsByImage[item.id] ?? [];
540
701
  const setAnnotations = (0, react.useCallback)((update) => {
702
+ if (service.getSnapshot()?.committing) return;
541
703
  if (item === void 0) return;
542
704
  const previous = annotationsByImageRef.current[item.id] ?? [];
543
705
  const next = typeof update === "function" ? update(previous) : update;
@@ -557,6 +719,11 @@ window.__ModuleLoader__.load({
557
719
  document.body.style.overflow = "hidden";
558
720
  rootRef.current?.focus();
559
721
  const onKeyDown = (event) => {
722
+ if (service.getSnapshot()?.committing) {
723
+ event.preventDefault();
724
+ event.stopPropagation();
725
+ return;
726
+ }
560
727
  if (event.defaultPrevented || event.isComposing) return;
561
728
  if (event.key === "Escape") {
562
729
  event.preventDefault();
@@ -688,6 +855,18 @@ window.__ModuleLoader__.load({
688
855
  "aria-label": t("dialog"),
689
856
  tabIndex: -1,
690
857
  children: [
858
+ request.committing || request.commitError ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
859
+ className: "niv-draft-status",
860
+ role: "status",
861
+ children: [t(request.committing ? "addingDraft" : "draftFailed"), request.commitError ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
862
+ className: "niv-button",
863
+ type: "button",
864
+ onClick: () => {
865
+ service.close({ discard: true });
866
+ },
867
+ children: t("closeWithoutDraft")
868
+ }) : null]
869
+ }) : null,
691
870
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
692
871
  className: "niv-title",
693
872
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("strong", { children: item.name }), meta !== "" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("small", { children: meta }) : null]
@@ -758,7 +937,7 @@ window.__ModuleLoader__.load({
758
937
  download: item.download,
759
938
  item,
760
939
  t
761
- }, `${request.revision}:${item.src}`),
940
+ }, `${request.revision}:${index}:${item.src}`),
762
941
  annotations.some((annotation) => annotation.note.trim() !== "") ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
763
942
  type: "button",
764
943
  className: "niv-button niv-copy-notes",
@@ -945,7 +1124,7 @@ window.__ModuleLoader__.load({
945
1124
  ]
946
1125
  });
947
1126
  }
948
- function installOfficialImageBridge(service) {
1127
+ function installOfficialImageBridge(service, ctx, t) {
949
1128
  const onClick = (event) => {
950
1129
  const match = nativeImageButton(event.target);
951
1130
  if (match === void 0) return;
@@ -953,12 +1132,20 @@ window.__ModuleLoader__.load({
953
1132
  event.preventDefault();
954
1133
  event.stopPropagation();
955
1134
  event.stopImmediatePropagation();
1135
+ const commitAnnotations = createAnnotationCommit(ctx, {
1136
+ readBlob: (src) => readImageBlob(src, {
1137
+ signal: new AbortController().signal,
1138
+ onProgress: () => {}
1139
+ }),
1140
+ formatNotes: (annotations) => noteText(annotations, t)
1141
+ });
956
1142
  service.open({
957
1143
  items,
958
1144
  index,
959
1145
  opener: match.button,
960
1146
  source: "dsh-native",
961
- annotations: true
1147
+ annotations: true,
1148
+ commitAnnotations
962
1149
  });
963
1150
  };
964
1151
  document.addEventListener("click", onClick, true);
@@ -969,6 +1156,7 @@ window.__ModuleLoader__.load({
969
1156
  function apply(ctx) {
970
1157
  const service = new NativeImageViewerService();
971
1158
  ctx.effect(() => ctx.locale.register(name, LOCALES), `${name}: dictionaries`);
1159
+ const t = ctx.locale.bind(name);
972
1160
  ctx.effect(() => {
973
1161
  const style = document.createElement("style");
974
1162
  style.dataset.plugin = name;
@@ -980,13 +1168,12 @@ window.__ModuleLoader__.load({
980
1168
  }, `${name}: styles`);
981
1169
  ctx.effect(() => {
982
1170
  const disposeService = ctx.reflect.provide("nativeImageViewer", service);
983
- const disposeBridge = installOfficialImageBridge(service);
1171
+ const disposeBridge = installOfficialImageBridge(service, ctx, t);
984
1172
  return () => {
985
1173
  disposeBridge();
986
1174
  disposeService();
987
1175
  };
988
1176
  }, `${name}: optional viewer service and native image bridge`);
989
- const t = ctx.locale.bind(name);
990
1177
  ctx.slots.inject("shell.overlay", () => ctx.slots.register({
991
1178
  name: "shell.overlay",
992
1179
  id: name,
package/lib/client.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"client.js","names":["#listeners","#snapshot","#annotationsByImage","#revision","#emit","CSS","clamp","IconDownloadOutline16","IconEditOutline16","IconFullscreenOutline16","IconCopyOutline16","IconCloseOutline16","IconChevronLeftOutline14","IconChevronRightOutline14","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, kind: 'message' }\n const rail = button.closest('[role=\"group\"]')\n if (rail !== null && button.hasAttribute('title')) return { button, image, group: rail, kind: 'composer' }\n return undefined\n}\n\nexport function imageItemsForButton(match) {\n const selector = match.kind === 'message'\n ? ':scope > button[data-variant=\"single\"],:scope > button[data-variant=\"tile\"]'\n : 'button[title]'\n const buttons = match.group?.querySelectorAll(selector)\n ?? []\n const candidates = [...buttons].flatMap((button, index) => {\n if (match.kind === 'composer' && button.closest('[role=\"group\"]') !== match.group) return []\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@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))}}\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 [geometry, setGeometry] = useState({ width: 0, height: 0, stageWidth: 0, stageHeight: 0 })\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 const next = { width: surfaceRef.current?.offsetWidth ?? 0, height: surfaceRef.current?.offsetHeight ?? 0,\n stageWidth: stageRef.current?.clientWidth ?? 0, stageHeight: stageRef.current?.clientHeight ?? 0 }\n setGeometry(current => Object.keys(next).every(key => current[key] === next[key]) ? current : next)\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, geometry, 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, revision }) {\n const [state, setState] = useState('idle')\n const active = useRef(true)\n useEffect(() => { active.current = true; return () => { active.current = false } }, [])\n const invoke = async () => {\n if (state === 'pending') return\n setState('pending')\n try {\n await action.onInvoke({ annotations, item, src: item.src })\n if (!active.current || service.getSnapshot()?.revision !== revision) return\n setState('idle')\n if (action.closeOnSuccess) service.close()\n } catch { if (active.current) 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 controller = useRef(null)\n const buttonRef = useRef(null)\n const restoreFocus = useRef(false)\n useEffect(() => () => { controller.current?.abort() }, [])\n useEffect(() => {\n if (state === 'pending' || !restoreFocus.current) return\n restoreFocus.current = false\n if (document.activeElement === document.body) buttonRef.current?.focus()\n }, [state])\n const invoke = async () => {\n if (controller.current !== null) return\n const operation = new AbortController()\n controller.current = operation\n restoreFocus.current = document.activeElement === buttonRef.current\n setState('pending')\n try {\n if (download !== undefined) await download.onInvoke({ item, src: item.src })\n else {\n const response = await fetch(item.src, { signal: operation.signal })\n if (!response.ok) throw new Error(`Image download failed: ${response.status}`)\n const blob = await response.blob()\n if (operation.signal.aborted) return\n const url = URL.createObjectURL(blob)\n const link = document.createElement('a')\n link.href = url\n link.download = downloadName(item.name)\n document.body.append(link)\n link.click()\n link.remove()\n // Keep the URL alive while the browser takes ownership of the download.\n setTimeout(() => URL.revokeObjectURL(url), 60_000)\n }\n if (!operation.signal.aborted) setState('idle')\n } catch { if (!operation.signal.aborted) setState('failed') }\n finally { if (controller.current === operation) controller.current = null }\n }\n const label = state === 'pending' ? download?.pendingLabel ?? t('preparing') : state === 'failed' ? download?.errorLabel ?? t('failed') : t('download')\n return <button ref={buttonRef} type=\"button\" className=\"niv-download\" aria-label={label} 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 [cursor, setCursor] = useState({ revision: 0, index: 0 })\n const index = cursor.revision === request?.revision ? cursor.index : request?.index ?? 0\n const setIndex = update => setCursor(current => ({\n revision: request.revision,\n index: typeof update === 'function' ? update(current.revision === request.revision ? current.index : request.index) : update,\n }))\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 setAnnotating(false)\n setSelected(undefined)\n setCopied(false)\n }, [request?.revision])\n\n const item = request?.items[index]\n const { transform, transformRef, dragging, pixelScale, geometry, 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 setCopied(false)\n setCopyFailed(false)\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 rootRef.current?.focus()\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 const annotationPosition = annotation => {\n // Only the image is scaled. Notes stay in screen coordinates so their text\n // is not rasterized inside a scaled compositor layer and then enlarged.\n const ratio = globalThis.devicePixelRatio || 1\n const align = value => Math.round(value * ratio) / ratio\n return {\n left: align(geometry.stageWidth / 2 + transform.x + (annotation.x - 0.5) * geometry.width * transform.zoom - 12),\n top: align(geometry.stageHeight / 2 + transform.y + (annotation.y - 0.5) * geometry.height * transform.zoom - 12),\n visibility: imageState === 'ready' ? 'visible' : 'hidden',\n }\n }\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 <ViewerDownload key={`${request.revision}:${item.src}`} download={item.download} item={item} t={t} />\n {annotations.some(annotation => annotation.note.trim() !== '') ? <button type=\"button\" className=\"niv-button niv-copy-notes\" aria-label={copyFailed ? t('copyFailed') : copied ? t('copied') : t('copyNotes')} onClick={() => { void copyNotes() }}><IconCopyOutline16 /><span className=\"niv-label\">{copyFailed ? t('copyFailed') : copied ? t('copied') : t('copyNotes')}</span></button> : null}\n {item.actions.map(action => <ViewerAction action={action} annotations={annotations} item={item} service={service} revision={request.revision} key={`${request.revision}:${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 </div>\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={annotationPosition(annotation)} 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.nativeEvent?.isComposing || event.isComposing) return\n if ((event.key === 'Enter' && !event.shiftKey) || event.key === 'Escape') {\n event.preventDefault()\n event.stopPropagation()\n event.nativeEvent?.stopImmediatePropagation?.()\n setSelected(undefined)\n rootRef.current?.focus()\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); rootRef.current?.focus() }}><IconCloseOutline16 /></button>\n </div> : null}\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\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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"}
1
+ {"version":3,"file":"client.js","names":["CSS","clamp","useState","useRef","useCallback","useState","useRef","IconDownloadOutline16","useSyncExternalStore","useCallback","IconEditOutline16","IconFullscreenOutline16","IconCopyOutline16","IconCloseOutline16","IconChevronLeftOutline14","IconChevronRightOutline14","VIEWER_CSS"],"sources":["../src/viewer.js","../src/styles.js","../src/image-transform.js","../src/image-download.js","../src/annotation-draft.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 commitAnnotations: typeof request?.commitAnnotations === 'function' ? request.commitAnnotations : undefined,\n }\n}\n\nexport class NativeImageViewerService {\n #listeners = new Set()\n #revision = 0\n #snapshot\n #annotationsByImage = new Map()\n #openingAnnotations = new Map()\n #closing = false\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 if (this.#closing) return false\n const normalized = normalizeViewerRequest(request)\n if (normalized === undefined) return false\n this.#revision += 1\n this.#snapshot = { ...normalized, revision: this.#revision }\n this.#openingAnnotations = new Map(normalized.items.map(item => [item.id, JSON.stringify(this.#annotationsByImage.get(item.id) || [])]))\n this.#emit()\n return true\n }\n\n async close({ discard = false } = {}) {\n if (this.#snapshot === undefined) return\n if (this.#closing) return\n const pending = this.#snapshot.items.map(item => ({ item, annotations: this.#annotationsByImage.get(item.id) || [] }))\n .filter(({ item, annotations }) => annotations.some(note => note.note.trim()) && JSON.stringify(annotations) !== this.#openingAnnotations.get(item.id))\n if (!discard && pending.length && this.#snapshot.commitAnnotations) {\n this.#closing = true\n this.#snapshot = { ...this.#snapshot, committing: true, commitError: false }\n this.#emit()\n try { await this.#snapshot.commitAnnotations(pending) }\n catch {\n this.#snapshot = { ...this.#snapshot, committing: false, commitError: true }\n this.#closing = false\n this.#emit()\n return false\n }\n this.#closing = false\n }\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, kind: 'message' }\n const rail = button.closest('[role=\"group\"]')\n if (rail !== null && button.hasAttribute('title')) return { button, image, group: rail, kind: 'composer' }\n return undefined\n}\n\nexport function imageItemsForButton(match) {\n const selector = match.kind === 'message'\n ? ':scope > button[data-variant=\"single\"],:scope > button[data-variant=\"tile\"]'\n : 'button[title]'\n const buttons = match.group?.querySelectorAll(selector)\n ?? []\n const candidates = [...buttons].flatMap((button, index) => {\n if (match.kind === 'composer' && button.closest('[role=\"group\"]') !== match.group) return []\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-draft-status{position:absolute;top:76px;left:50%;transform:translateX(-50%);z-index:10;max-width:calc(100% - 48px);padding:10px 16px;border-radius:12px;background:#26272a;color:#fff;font-size:13px;line-height:20px}\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@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))}}\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 [geometry, setGeometry] = useState({ width: 0, height: 0, stageWidth: 0, stageHeight: 0 })\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 const next = { width: surfaceRef.current?.offsetWidth ?? 0, height: surfaceRef.current?.offsetHeight ?? 0,\n stageWidth: stageRef.current?.clientWidth ?? 0, stageHeight: stageRef.current?.clientHeight ?? 0 }\n setGeometry(current => Object.keys(next).every(key => current[key] === next[key]) ? current : next)\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, geometry, stageRef, surfaceRef, imageRef, fit, actual, measure, setZoomAt, resetGesture,\n pointerHandlers: { onPointerDown, onPointerMove, onPointerUp: endPointer, onPointerCancel: endPointer, onLostPointerCapture: endPointer } }\n}\n","export function downloadPercent(value) {\n const { loaded, total } = value ?? {}\n if (!Number.isFinite(loaded) || loaded < 0 || !Number.isFinite(total) || total <= 0) return undefined\n return Math.min(100, Math.floor(loaded / total * 100))\n}\n\nexport async function readImageBlob(src, { signal, onProgress }) {\n const response = await fetch(src, { signal })\n if (!response.ok) throw new Error(`Image download failed: ${response.status}`)\n if (!response.body) return response.blob()\n // Compressed transfer lengths do not describe the decoded stream's size.\n const length = response.headers.get('content-encoding') ? undefined : Number(response.headers.get('content-length'))\n const total = Number.isFinite(length) && length > 0 ? length : undefined\n const reader = response.body.getReader()\n const chunks = []\n let loaded = 0\n try {\n while (true) {\n signal.throwIfAborted()\n const { done, value } = await reader.read()\n if (done) break\n chunks.push(value)\n loaded += value.byteLength\n onProgress({ loaded, total })\n }\n signal.throwIfAborted()\n return new Blob(chunks, { type: response.headers.get('content-type') || '' })\n } finally {\n reader.releaseLock()\n }\n}\n","export async function renderAnnotationImage(blob, annotations) {\n const image = await createImageBitmap(blob)\n try {\n const canvas = document.createElement('canvas')\n canvas.width = image.width\n canvas.height = image.height\n const context = canvas.getContext('2d')\n if (!context) throw new Error('Canvas unavailable')\n context.drawImage(image, 0, 0)\n const radius = Math.max(12, Math.min(image.width, image.height) / 60)\n annotations.forEach((annotation, index) => {\n const x = Math.max(radius, Math.min(image.width - radius, annotation.x * image.width))\n const y = Math.max(radius, Math.min(image.height - radius, annotation.y * image.height))\n context.beginPath()\n context.arc(x, y, radius, 0, Math.PI * 2)\n context.fillStyle = '#26272a'\n context.fill()\n context.strokeStyle = '#ffffff'\n context.lineWidth = Math.max(2, radius / 7)\n context.stroke()\n context.fillStyle = '#ffffff'\n context.font = `600 ${radius}px sans-serif`\n context.textAlign = 'center'\n context.textBaseline = 'middle'\n context.fillText(String(index + 1), x, y)\n })\n return await new Promise((resolve, reject) => canvas.toBlob(value => value ? resolve(value) : reject(new Error('Image encoding failed')), 'image/png'))\n } finally { image.close() }\n}\n\nconst hasOwn = Object.prototype.hasOwnProperty\n\n// Legacy hosts expose the selected session as `list.current`. Alpha2 keeps\n// that selection in the UI session retention projection instead, where the\n// main view is the only owner allowed to retain the current session.\nexport function currentSessionId(snapshot) {\n if (snapshot !== null && typeof snapshot === 'object' && hasOwn.call(snapshot, 'current')) return snapshot.current\n const retained = Object.entries(snapshot?.byId ?? {}).filter(([, entry]) => (entry?.retainedBy?.mainView ?? 0) > 0)\n return retained.length === 1 ? retained[0][0] : undefined\n}\n\n// Capture the destination when the viewer opens, then validate it again after\n// asynchronous image preparation. Never send or redirect another session.\nexport function createAnnotationCommit(ctx, { readBlob, render = renderAnnotationImage, formatNotes }) {\n let sessions, conversation, sessionId\n try {\n sessions = ctx.get('sessions')\n conversation = ctx.get('conversation')\n sessionId = currentSessionId(sessions.list.getSnapshot())\n } catch { /* The viewer also works without a conversation host. */ }\n return async entries => {\n if (!sessionId || !conversation?.input?.for || currentSessionId(sessions.list.getSnapshot()) !== sessionId) throw new Error('Composer unavailable or session changed')\n const prepared = await Promise.all(entries.map(async ({ item, annotations }) => {\n const image = await render(await readBlob(item.src), annotations)\n const name = `${String(item.name || 'image').replace(/\\.[^.]+$/, '')}-annotated.png`\n return { file: new File([image], name, { type: 'image/png' }), text: `${name}\\n${formatNotes(annotations)}` }\n }))\n if (currentSessionId(sessions.list.getSnapshot()) !== sessionId) throw new Error('Session changed')\n const input = conversation.input.for(sessions.scope(sessionId))\n const state = input.state.getSnapshot()\n if (state.phase !== 'plain' || state.occurrences?.length) throw new Error('Composer busy or contains references')\n const modern = typeof conversation.createDrafts === 'function'\n const add = modern ? input.addAttachments : input.addImages\n const release = modern ? conversation.releaseDraftAttachments : conversation.releaseDraftImages\n if (typeof add !== 'function' || typeof release !== 'function') throw new Error('Composer unavailable')\n const created = modern ? conversation.createDrafts(sessionId, prepared.map(item => item.file)) : conversation.createDraftImages(prepared.map(item => item.file))\n try {\n if (!add.call(input, created.map(item => item.id))) throw new Error('Composer busy')\n } catch (error) { release.call(conversation, created); throw error }\n input.setDraft([state.draft, ...prepared.map(item => item.text)].filter(Boolean).join('\\n\\n'))\n }\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'\nimport { downloadPercent, readImageBlob } from './image-download.js'\nimport { createAnnotationCommit } from './annotation-draft.js'\n\nexport const name = 'dsh-image-viewer'\nexport const inject = ['locale', 'slots']\n\nconst LOCALES = {\n en: {\n addingDraft: 'Adding image and notes to draft…', draftFailed: 'Could not add to draft. Return to the original session and keep the composer editable, then close to retry.', closeWithoutDraft: 'Close without adding',\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 cancelDownload: 'Cancel download', cancel: 'Cancel', loading: 'Loading image…', loadFailed: 'Image could not be loaded.', retry: 'Retry', copyFailed: 'Copy failed. Try again.',\n },\n zh: {\n addingDraft: '正在把图片和备注加入草稿…', draftFailed: '未能加入草稿。请回到原会话并确保输入框可编辑,再关闭以重试。', closeWithoutDraft: '仅关闭,不加入草稿',\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 cancelDownload: '取消下载', cancel: '取消', 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, revision }) {\n const [state, setState] = useState('idle')\n const active = useRef(true)\n useEffect(() => { active.current = true; return () => { active.current = false } }, [])\n const invoke = async () => {\n if (state === 'pending') return\n setState('pending')\n try {\n await action.onInvoke({ annotations, item, src: item.src })\n if (!active.current || service.getSnapshot()?.revision !== revision) return\n setState('idle')\n if (action.closeOnSuccess) service.close()\n } catch { if (active.current) 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 [progress, setProgress] = useState(undefined)\n const controller = useRef(null)\n useEffect(() => () => {\n controller.current?.abort()\n controller.current = null\n }, [item.id, item.src, download])\n const invoke = async () => {\n if (controller.current !== null) {\n controller.current.abort()\n controller.current = null\n setState('idle')\n setProgress(undefined)\n return\n }\n const operation = new AbortController()\n controller.current = operation\n setState('pending')\n setProgress(undefined)\n const onProgress = value => {\n if (controller.current === operation) setProgress(downloadPercent(value))\n }\n try {\n if (download !== undefined) await download.onInvoke({ item, src: item.src, signal: operation.signal, onProgress })\n else {\n const blob = await readImageBlob(item.src, { signal: operation.signal, onProgress })\n if (operation.signal.aborted) return\n const url = URL.createObjectURL(blob)\n const link = document.createElement('a')\n link.href = url\n link.download = downloadName(item.name)\n document.body.append(link)\n link.click()\n link.remove()\n // Keep the URL alive while the browser takes ownership of the download.\n setTimeout(() => URL.revokeObjectURL(url), 60_000)\n }\n if (controller.current === operation) setState('idle')\n } catch { if (controller.current === operation) setState('failed') }\n finally { if (controller.current === operation) controller.current = null }\n }\n const label = state === 'pending' ? `${download?.pendingLabel ?? t('preparing')}${progress === undefined ? '' : ` ${progress}%`} · ${t('cancel')}` : state === 'failed' ? download?.errorLabel ?? t('failed') : t('download')\n return <button type=\"button\" className=\"niv-download\" aria-label={state === 'pending' ? t('cancelDownload') : label} title={label} 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 [cursor, setCursor] = useState({ revision: 0, index: 0 })\n const index = cursor.revision === request?.revision ? cursor.index : request?.index ?? 0\n const setIndex = update => setCursor(current => ({\n revision: request.revision,\n index: typeof update === 'function' ? update(current.revision === request.revision ? current.index : request.index) : update,\n }))\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 setAnnotating(false)\n setSelected(undefined)\n setCopied(false)\n }, [request?.revision])\n\n const item = request?.items[index]\n const { transform, transformRef, dragging, pixelScale, geometry, 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 (service.getSnapshot()?.committing) return\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 setCopied(false)\n setCopyFailed(false)\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 (service.getSnapshot()?.committing) { event.preventDefault(); event.stopPropagation(); return }\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 rootRef.current?.focus()\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 const annotationPosition = annotation => {\n // Only the image is scaled. Notes stay in screen coordinates so their text\n // is not rasterized inside a scaled compositor layer and then enlarged.\n const ratio = globalThis.devicePixelRatio || 1\n const align = value => Math.round(value * ratio) / ratio\n return {\n left: align(geometry.stageWidth / 2 + transform.x + (annotation.x - 0.5) * geometry.width * transform.zoom - 12),\n top: align(geometry.stageHeight / 2 + transform.y + (annotation.y - 0.5) * geometry.height * transform.zoom - 12),\n visibility: imageState === 'ready' ? 'visible' : 'hidden',\n }\n }\n return <div ref={rootRef} className=\"niv-root\" role=\"dialog\" aria-modal=\"true\" aria-label={t('dialog')} tabIndex={-1}>\n {request.committing || request.commitError ? <div className=\"niv-draft-status\" role=\"status\">{t(request.committing ? 'addingDraft' : 'draftFailed')}{request.commitError ? <button className=\"niv-button\" type=\"button\" onClick={() => { void service.close({ discard: true }) }}>{t('closeWithoutDraft')}</button> : null}</div> : null}\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 <ViewerDownload key={`${request.revision}:${index}:${item.src}`} download={item.download} item={item} t={t} />\n {annotations.some(annotation => annotation.note.trim() !== '') ? <button type=\"button\" className=\"niv-button niv-copy-notes\" aria-label={copyFailed ? t('copyFailed') : copied ? t('copied') : t('copyNotes')} onClick={() => { void copyNotes() }}><IconCopyOutline16 /><span className=\"niv-label\">{copyFailed ? t('copyFailed') : copied ? t('copied') : t('copyNotes')}</span></button> : null}\n {item.actions.map(action => <ViewerAction action={action} annotations={annotations} item={item} service={service} revision={request.revision} key={`${request.revision}:${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 </div>\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={annotationPosition(annotation)} 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.nativeEvent?.isComposing || event.isComposing) return\n if ((event.key === 'Enter' && !event.shiftKey) || event.key === 'Escape') {\n event.preventDefault()\n event.stopPropagation()\n event.nativeEvent?.stopImmediatePropagation?.()\n setSelected(undefined)\n rootRef.current?.focus()\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); rootRef.current?.focus() }}><IconCloseOutline16 /></button>\n </div> : null}\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\n </div>\n </div>\n}\n\nfunction installOfficialImageBridge(service, ctx, t) {\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 const commitAnnotations = createAnnotationCommit(ctx, {\n readBlob: src => readImageBlob(src, { signal: new AbortController().signal, onProgress: () => {} }),\n formatNotes: annotations => noteText(annotations, t),\n })\n service.open({ items, index, opener: match.button, source: 'dsh-native', annotations: true, commitAnnotations })\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 const t = ctx.locale.bind(name)\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, ctx, t)\n return () => { disposeBridge(); void disposeService() }\n }, `${name}: optional viewer service and native image bridge`)\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",
3
+ "version": "0.1.2-beta.1",
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 || 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",
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 || 0.1.6-alpha.1 || 0.1.6-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 || 0.1.5-alpha.1 || 0.1.6-alpha.1 || 0.1.6-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 || 0.1.5-alpha.1 || 0.1.6-alpha.1 || 0.1.6-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 || 0.1.5-alpha.1 || 0.1.6-alpha.1 || 0.1.6-alpha.2",
70
70
  "react": "^18.2.0"
71
71
  },
72
72
  "peerDependenciesMeta": {
@@ -95,14 +95,14 @@
95
95
  "@deepseek-ai/dsh-client-ui-layout": "0.1.2-rc.1",
96
96
  "@deepseek-ai/dsh-client-ui-primitives": "0.1.2-rc.1",
97
97
  "@deepseek-ai/dsh-client-ui-slots": "0.1.2-rc.1",
98
- "playwright": "1.62.1",
98
+ "playwright": "1.63.0",
99
99
  "react": "18.3.1",
100
100
  "react-dom": "18.3.1",
101
- "tsdown": "0.22.2"
101
+ "tsdown": "0.23.0"
102
102
  },
103
103
  "scripts": {
104
104
  "build": "tsdown --config tsdown.config.mjs",
105
- "test:behavior": "node --test tests/viewer.test.mjs",
105
+ "test:behavior": "node --test tests/viewer.test.mjs tests/image-download.test.mjs",
106
106
  "test:delivery": "node --test tests/package-contract.test.mjs",
107
107
  "test": "node --test tests/*.test.mjs",
108
108
  "check": "pnpm run test && pnpm run build && pnpm pack --pack-destination .artifacts"