@qilin-agent/client-ui-attachment 3.1.6 → 3.1.8

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/lib/client.js CHANGED
@@ -24,7 +24,7 @@ window.__ModuleLoader__.load({
24
24
  }
25
25
  //#endregion
26
26
  //#region \0qilin-css:/home/runner/work/QiLin/QiLin/packages/client/ui-attachment/src/AttachmentRail.module.css.mjs
27
- const css$4 = ".tsmrHq_root{min-width:0;position:relative}.tsmrHq_rail{scrollbar-width:none;--qilin-scrollbar-thumb:var(--qilin-alias-scrollbar-bg-l2);--qilin-scrollbar-thumb-hover:var(--qilin-alias-scrollbar-hover-l2);align-items:stretch;gap:10px;display:flex;overflow:auto hidden}.tsmrHq_rail::-webkit-scrollbar{display:none}.tsmrHq_item{flex:none;height:64px}.tsmrHq_thumbnail{border:.5px solid var(--qilin-alias-border-l2-darkmode-thin);background:var(--qilin-alias-interactive-bg-hover);cursor:zoom-in;border-radius:16px;width:64px;height:64px;padding:0;overflow:hidden}.tsmrHq_thumbnail img{object-fit:cover;width:100%;height:100%;display:block}.tsmrHq_remove{z-index:1;corner-shape:round;background:var(--qilin-alias-button-contrast-fill);width:18px;height:18px;color:var(--qilin-alias-label-primary-inverted);cursor:pointer;opacity:0;border:none;border-radius:50%;place-items:center;padding:0;transition:opacity .2s ease-in-out;display:grid;position:absolute;top:4px;right:4px}.tsmrHq_item:hover .tsmrHq_remove,.tsmrHq_remove:focus-visible{opacity:1}@media (pointer:coarse){.tsmrHq_remove{opacity:1}}@media (prefers-reduced-motion:reduce){.tsmrHq_remove{transition:none}}.tsmrHq_arrow{z-index:2;--qilin-elevation-stroke-color:var(--qilin-alias-border-l2-darkmode-thin);corner-shape:round;background:var(--qilin-specific-input-major);width:24px;height:24px;color:var(--qilin-alias-label-secondary);box-shadow:var(--qilin-elevation-panel);cursor:pointer;border:0;border-radius:999px;place-items:center;padding:0;display:grid;position:absolute;top:50%;transform:translateY(-50%)}.tsmrHq_arrow:hover{background:var(--qilin-alias-interactive-bg-hover-solid)}.tsmrHq_arrowLeft{left:4px}.tsmrHq_arrowRight{right:4px}";
27
+ const css$4 = ".tsmrHq_root{min-width:0;position:relative}.tsmrHq_rail{scrollbar-width:none;--qilin-scrollbar-thumb:var(--qilin-alias-scrollbar-bg-l2);--qilin-scrollbar-thumb-hover:var(--qilin-alias-scrollbar-hover-l2);align-items:stretch;gap:10px;display:flex;overflow:auto hidden}.tsmrHq_rail::-webkit-scrollbar{display:none}.tsmrHq_item{flex:none;height:64px}.tsmrHq_thumbnail{border:1px solid var(--qilin-alias-border-l2-darkmode-thin);border-radius:var(--qilin-radius-xl);background:var(--qilin-alias-interactive-bg-hover);cursor:zoom-in;width:64px;height:64px;padding:0;overflow:hidden}.tsmrHq_thumbnail img{object-fit:cover;width:100%;height:100%;display:block}.tsmrHq_remove{z-index:1;corner-shape:round;background:var(--qilin-alias-button-contrast-fill);width:18px;height:18px;color:var(--qilin-alias-label-primary-inverted);cursor:pointer;opacity:0;border:none;border-radius:50%;place-items:center;padding:0;transition:opacity .2s ease-in-out;display:grid;position:absolute;top:4px;right:4px}.tsmrHq_item:hover .tsmrHq_remove,.tsmrHq_remove:focus-visible{opacity:1}@media (pointer:coarse){.tsmrHq_remove{opacity:1}}@media (prefers-reduced-motion:reduce){.tsmrHq_remove{transition:none}}.tsmrHq_arrow{z-index:2;--qilin-elevation-stroke-color:var(--qilin-alias-border-l2-darkmode-thin);corner-shape:round;background:var(--qilin-specific-input-major);width:24px;height:24px;color:var(--qilin-alias-label-secondary);box-shadow:var(--qilin-elevation-panel);cursor:pointer;border:0;border-radius:999px;place-items:center;padding:0;display:grid;position:absolute;top:50%;transform:translateY(-50%)}.tsmrHq_arrow:hover{background:var(--qilin-alias-interactive-bg-hover-solid)}.tsmrHq_arrowLeft{left:4px}.tsmrHq_arrowRight{right:4px}";
28
28
  const tagId$4 = "@qilin-agent/client-ui-attachment/AttachmentRail.module.css";
29
29
  if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$4) + "]") === null) {
30
30
  const tag = document.createElement("style");
@@ -144,7 +144,7 @@ window.__ModuleLoader__.load({
144
144
  onClick: () => {
145
145
  page(-1);
146
146
  },
147
- children: (0, react_jsx_runtime.jsx)(_qilin_agent_client_ui_primitives.IconChevronLeftOutline14, {})
147
+ children: (0, react_jsx_runtime.jsx)(_qilin_agent_client_ui_primitives.IconChevronLeftOutlineRegular, {})
148
148
  }),
149
149
  (0, react_jsx_runtime.jsx)("div", {
150
150
  ref: railRef,
@@ -164,7 +164,7 @@ window.__ModuleLoader__.load({
164
164
  onClick: () => {
165
165
  page(1);
166
166
  },
167
- children: (0, react_jsx_runtime.jsx)(_qilin_agent_client_ui_primitives.IconChevronRightOutline14, {})
167
+ children: (0, react_jsx_runtime.jsx)(_qilin_agent_client_ui_primitives.IconChevronRightOutlineRegular, {})
168
168
  })
169
169
  ]
170
170
  });
@@ -357,7 +357,7 @@ window.__ModuleLoader__.load({
357
357
  });
358
358
  //#endregion
359
359
  //#region \0qilin-css:/home/runner/work/QiLin/QiLin/packages/client/ui-attachment/src/FileCard.module.css.mjs
360
- const css$2 = ".LBRGAa_card{border:.5px solid var(--qilin-alias-border-l2,#0000001f);background:var(--qilin-specific-input-major,transparent);box-sizing:border-box;text-align:left;border-radius:16px;align-items:center;gap:10px;width:240px;height:64px;padding:0 12px;display:inline-flex;position:relative}.LBRGAa_failed{border-color:var(--qilin-alias-state-error-primary,#d54941)}.LBRGAa_icon{flex:none;justify-content:center;align-items:center;width:28px;height:28px;display:inline-flex}.LBRGAa_spinner{corner-shape:round;border:2px solid;border-top-color:#0000;border-radius:50%;width:20px;height:20px;animation:.8s linear infinite LBRGAa_file-card-spin}@keyframes LBRGAa_file-card-spin{to{transform:rotate(360deg)}}.LBRGAa_body{flex-direction:column;flex:1;min-width:0;padding:8px 0;display:flex}.LBRGAa_retry{color:inherit;font:inherit;text-align:left;cursor:pointer;background:0 0;border:0;padding:0}.LBRGAa_name{white-space:nowrap;text-overflow:ellipsis;color:var(--qilin-alias-label-primary);font-size:14px;font-weight:500;line-height:22px;overflow:hidden}.LBRGAa_meta{white-space:nowrap;text-overflow:ellipsis;color:var(--qilin-alias-label-tertiary,#00000073);font-size:12px;line-height:15px;overflow:hidden}.LBRGAa_metaFailed{color:var(--qilin-alias-state-error-primary,#d54941)}.LBRGAa_remove{corner-shape:round;background:var(--qilin-alias-button-contrast-fill,#000000b8);width:18px;height:18px;color:var(--qilin-alias-label-primary-inverted,#fff);opacity:0;cursor:pointer;border:none;border-radius:50%;justify-content:center;align-items:center;padding:0;transition:opacity .2s ease-in-out;display:inline-flex;position:absolute;top:6px;right:6px}.LBRGAa_card:hover .LBRGAa_remove,.LBRGAa_remove:focus-visible{opacity:1}@media (pointer:coarse){.LBRGAa_remove{opacity:1}}@media (prefers-reduced-motion:reduce){.LBRGAa_remove{transition:none}}.LBRGAa_card:hover .LBRGAa_name,.LBRGAa_card:focus-within .LBRGAa_name{padding-right:18px}.LBRGAa_removeFailed{background:var(--qilin-alias-state-error-primary,#d54941);color:#fff;opacity:1}.LBRGAa_progressTrack{background:var(--qilin-alias-fill-tertiary,#00000014);border-radius:1px;height:2px;position:absolute;bottom:5px;left:12px;right:12px;overflow:hidden}.LBRGAa_progressBar{border-radius:inherit;background:var(--qilin-alias-brand-primary,#4d6bfe);width:35%;height:100%;animation:1.2s ease-in-out infinite alternate LBRGAa_file-card-progress;display:block}.LBRGAa_progressBar[style]{animation:none}@keyframes LBRGAa_file-card-progress{0%{transform:translate(-70%)}to{transform:translate(220%)}}@media (pointer:coarse){.LBRGAa_remove{opacity:1}}";
360
+ const css$2 = ".LBRGAa_card{border:1px solid var(--qilin-alias-border-l2,#0000001f);border-radius:var(--qilin-radius-lg);background:var(--qilin-specific-input-major,transparent);box-sizing:border-box;text-align:left;align-items:center;gap:10px;width:240px;height:64px;padding:0 12px;display:inline-flex;position:relative}.LBRGAa_failed{border-color:var(--qilin-alias-state-error-primary,#d54941)}.LBRGAa_icon{flex:none;justify-content:center;align-items:center;width:28px;height:28px;display:inline-flex}.LBRGAa_spinner{corner-shape:round;border:2px solid;border-top-color:#0000;border-radius:50%;width:20px;height:20px;animation:.8s linear infinite LBRGAa_file-card-spin}@keyframes LBRGAa_file-card-spin{to{transform:rotate(360deg)}}.LBRGAa_body{flex-direction:column;flex:1;min-width:0;padding:8px 0;display:flex}.LBRGAa_retry{color:inherit;font:inherit;text-align:left;cursor:pointer;background:0 0;border:0;padding:0}.LBRGAa_name{white-space:nowrap;text-overflow:ellipsis;color:var(--qilin-alias-label-primary);font-size:14px;font-weight:500;line-height:22px;overflow:hidden}.LBRGAa_meta{white-space:nowrap;text-overflow:ellipsis;color:var(--qilin-alias-label-tertiary,#00000073);font-size:12px;line-height:15px;overflow:hidden}.LBRGAa_metaFailed{color:var(--qilin-alias-state-error-primary,#d54941)}.LBRGAa_remove{corner-shape:round;background:var(--qilin-alias-button-contrast-fill,#000000b8);width:18px;height:18px;color:var(--qilin-alias-label-primary-inverted,#fff);opacity:0;cursor:pointer;border:none;border-radius:50%;justify-content:center;align-items:center;padding:0;transition:opacity .2s ease-in-out;display:inline-flex;position:absolute;top:6px;right:6px}.LBRGAa_card:hover .LBRGAa_remove,.LBRGAa_remove:focus-visible{opacity:1}@media (pointer:coarse){.LBRGAa_remove{opacity:1}}@media (prefers-reduced-motion:reduce){.LBRGAa_remove{transition:none}}.LBRGAa_card:hover .LBRGAa_name,.LBRGAa_card:focus-within .LBRGAa_name{padding-right:18px}.LBRGAa_removeFailed{background:var(--qilin-alias-state-error-primary,#d54941);color:#fff;opacity:1}.LBRGAa_progressTrack{background:var(--qilin-alias-fill-tertiary,#00000014);border-radius:1px;height:2px;position:absolute;bottom:5px;left:12px;right:12px;overflow:hidden}.LBRGAa_progressBar{border-radius:inherit;background:var(--qilin-alias-brand-primary,#4d6bfe);width:35%;height:100%;animation:1.2s ease-in-out infinite alternate LBRGAa_file-card-progress;display:block}.LBRGAa_progressBar[style]{animation:none}@keyframes LBRGAa_file-card-progress{0%{transform:translate(-70%)}to{transform:translate(220%)}}@media (pointer:coarse){.LBRGAa_remove{opacity:1}}";
361
361
  const tagId$2 = "@qilin-agent/client-ui-attachment/FileCard.module.css";
362
362
  if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$2) + "]") === null) {
363
363
  const tag = document.createElement("style");
@@ -427,7 +427,7 @@ window.__ModuleLoader__.load({
427
427
  className: retryable ? `${FileCard_module_css_default.remove} ${FileCard_module_css_default.removeFailed}` : FileCard_module_css_default.remove,
428
428
  "aria-label": labels.remove,
429
429
  onClick: onRemove,
430
- children: (0, react_jsx_runtime.jsx)(_qilin_agent_client_ui_primitives.IconCloseFill14, { size: 12 })
430
+ children: (0, react_jsx_runtime.jsx)(_qilin_agent_client_ui_primitives.IconCloseFillRegular, { size: 12 })
431
431
  }),
432
432
  state === "uploading" && (0, react_jsx_runtime.jsx)("span", {
433
433
  className: FileCard_module_css_default.progressTrack,
@@ -512,6 +512,23 @@ window.__ModuleLoader__.load({
512
512
  //#endregion
513
513
  //#region lib/types/client/drop-events.js
514
514
  /**
515
+ * Members of a drop that are directories. The `File` a directory drop yields
516
+ * is indistinguishable from an empty file, so the entry API is the only
517
+ * source of that fact; browsers without it report no directories.
518
+ */
519
+ function droppedDirectories(dataTransfer, files) {
520
+ const directories = /* @__PURE__ */ new Set();
521
+ let fileIndex = 0;
522
+ for (const item of dataTransfer.items) {
523
+ if (item.kind !== "file") continue;
524
+ const file = files[fileIndex++];
525
+ if (typeof item.webkitGetAsEntry !== "function") continue;
526
+ if (item.webkitGetAsEntry()?.isDirectory !== true) continue;
527
+ if (file !== void 0) directories.add(file);
528
+ }
529
+ return directories;
530
+ }
531
+ /**
515
532
  * Install one attachment view's file-drop listeners.
516
533
  * @param canAcceptDrop - whether this view accepts the dropped files.
517
534
  * @param onAddFiles - attachment intake callback.
@@ -553,7 +570,10 @@ window.__ModuleLoader__.load({
553
570
  if (dataTransfer === null) return;
554
571
  event.preventDefault();
555
572
  reset();
556
- if (canAcceptDrop) onAddFiles([...dataTransfer.files]);
573
+ if (canAcceptDrop) {
574
+ const files = [...dataTransfer.files];
575
+ onAddFiles(files, droppedDirectories(dataTransfer, files));
576
+ }
557
577
  };
558
578
  document.addEventListener("dragenter", onDragEnter);
559
579
  document.addEventListener("dragover", onDragOver);
@@ -570,7 +590,7 @@ window.__ModuleLoader__.load({
570
590
  }
571
591
  //#endregion
572
592
  //#region \0qilin-css:/home/runner/work/QiLin/QiLin/packages/client/ui-attachment/src/client/ComposerAttachments.module.css.mjs
573
- const css$1 = ".z3i06q_rail{min-width:0;margin-bottom:-6px;padding:2px 10px 0}.z3i06q_imageItem{width:64px;height:64px;position:relative}.z3i06q_thumbnail{border:.5px solid var(--qilin-alias-border-l2-darkmode-thin);background:var(--qilin-alias-interactive-bg-hover);cursor:zoom-in;border-radius:16px;width:64px;height:64px;padding:0;overflow:hidden}.z3i06q_thumbnail img{object-fit:cover;width:100%;height:100%;display:block}.z3i06q_remove{z-index:1;corner-shape:round;background:var(--qilin-alias-button-contrast-fill);width:18px;height:18px;color:var(--qilin-alias-label-primary-inverted);cursor:pointer;opacity:0;border:none;border-radius:50%;place-items:center;padding:0;transition:opacity .2s ease-in-out;display:grid;position:absolute;top:4px;right:4px}.z3i06q_imageItem:hover .z3i06q_remove,.z3i06q_remove:focus-visible{opacity:1}@media (pointer:coarse){.z3i06q_remove{opacity:1}}@media (prefers-reduced-motion:reduce){.z3i06q_remove{transition:none}}";
593
+ const css$1 = ".z3i06q_rail{min-width:0;margin-bottom:-6px;padding:2px 10px 0}.z3i06q_imageItem{width:64px;height:64px;position:relative}.z3i06q_thumbnail{border:1px solid var(--qilin-alias-border-l2-darkmode-thin);border-radius:var(--qilin-radius-xl);background:var(--qilin-alias-interactive-bg-hover);cursor:zoom-in;width:64px;height:64px;padding:0;overflow:hidden}.z3i06q_thumbnail img{object-fit:cover;width:100%;height:100%;display:block}.z3i06q_remove{z-index:1;corner-shape:round;background:var(--qilin-alias-button-contrast-fill);width:18px;height:18px;color:var(--qilin-alias-label-primary-inverted);cursor:pointer;opacity:0;border:none;border-radius:50%;place-items:center;padding:0;transition:opacity .2s ease-in-out;display:grid;position:absolute;top:4px;right:4px}.z3i06q_imageItem:hover .z3i06q_remove,.z3i06q_remove:focus-visible{opacity:1}@media (pointer:coarse){.z3i06q_remove{opacity:1}}@media (prefers-reduced-motion:reduce){.z3i06q_remove{transition:none}}";
574
594
  const tagId$1 = "@qilin-agent/client-ui-attachment/ComposerAttachments.module.css";
575
595
  if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$1) + "]") === null) {
576
596
  const tag = document.createElement("style");
@@ -653,7 +673,7 @@ window.__ModuleLoader__.load({
653
673
  onClick: () => {
654
674
  onRemoveAttachment(attachment.id);
655
675
  },
656
- children: (0, react_jsx_runtime.jsx)(_qilin_agent_client_ui_primitives.IconCloseFill14, { size: 12 })
676
+ children: (0, react_jsx_runtime.jsx)(_qilin_agent_client_ui_primitives.IconCloseFillRegular, { size: 12 })
657
677
  })]
658
678
  });
659
679
  }
@@ -669,7 +689,7 @@ window.__ModuleLoader__.load({
669
689
  }
670
690
  //#endregion
671
691
  //#region \0qilin-css:/home/runner/work/QiLin/QiLin/packages/client/ui-attachment/src/MessageImage.module.css.mjs
672
- const css = ".AdZSYG_gallery{flex-wrap:wrap;gap:10px;max-width:100%;display:flex}.AdZSYG_gallery[data-align=end]{justify-content:flex-end;align-self:flex-end}.AdZSYG_gallery[data-align=start]{justify-content:flex-start;align-self:flex-start}.AdZSYG_frame{border:.5px solid var(--qilin-alias-border-l2-darkmode-thin);background:var(--qilin-alias-interactive-bg-hover);cursor:zoom-in;border-radius:16px;flex:none;place-items:center;min-width:44px;min-height:44px;padding:0;display:grid;overflow:hidden}.AdZSYG_frame[data-variant=tile]{width:64px;min-width:64px;height:64px;min-height:64px}.AdZSYG_frame img{object-fit:cover;width:100%;height:100%;display:block}.AdZSYG_loading,.AdZSYG_error{color:var(--qilin-alias-label-tertiary);font-size:12px;line-height:18px}.AdZSYG_error{border:.5px solid var(--qilin-alias-border-l2-darkmode-thin);background:var(--qilin-alias-interactive-bg-hover-danger);cursor:pointer;border-radius:10px;max-width:240px;padding:10px 12px}.AdZSYG_error[data-variant=tile]{border-radius:16px;width:64px;height:64px;padding:4px;overflow:hidden}.AdZSYG_frame[data-variant=thumbnail],.AdZSYG_error[data-variant=thumbnail]{box-sizing:border-box;border-radius:8px;place-items:center;width:48px;min-width:48px;height:48px;min-height:48px;padding:2px;display:grid;overflow:hidden}.AdZSYG_frame[data-variant=thumbnail] img{object-fit:contain}.AdZSYG_spinner{animation:.9s linear infinite AdZSYG_spinner-rotate}@keyframes AdZSYG_spinner-rotate{to{transform:rotate(360deg)}}@media (prefers-reduced-motion:reduce){.AdZSYG_spinner{animation:none}}.AdZSYG_frame:focus-visible,.AdZSYG_error:focus-visible{outline:var(--qilin-focus-ring-width) solid var(--qilin-focus-ring-color,var(--qilin-alias-state-business-primary));outline-offset:2px}";
692
+ const css = ".AdZSYG_gallery{flex-wrap:wrap;gap:10px;max-width:100%;display:flex}.AdZSYG_gallery[data-align=end]{justify-content:flex-end;align-self:flex-end}.AdZSYG_gallery[data-align=start]{justify-content:flex-start;align-self:flex-start}.AdZSYG_frame{border:1px solid var(--qilin-alias-border-l2-darkmode-thin);border-radius:var(--qilin-radius-xl);background:var(--qilin-alias-interactive-bg-hover);cursor:zoom-in;flex:none;place-items:center;min-width:44px;min-height:44px;padding:0;display:grid;overflow:hidden}.AdZSYG_frame[data-variant=tile]{width:64px;min-width:64px;height:64px;min-height:64px}.AdZSYG_frame img{object-fit:cover;width:100%;height:100%;display:block}.AdZSYG_loading,.AdZSYG_error{color:var(--qilin-alias-label-tertiary);font-size:12px;line-height:18px}.AdZSYG_error{border:1px solid var(--qilin-alias-border-l2-darkmode-thin);border-radius:var(--qilin-radius-md);background:var(--qilin-alias-interactive-bg-hover-danger);cursor:pointer;max-width:240px;padding:10px 12px}.AdZSYG_error[data-variant=tile]{border-radius:var(--qilin-radius-xl);width:64px;height:64px;padding:4px;overflow:hidden}.AdZSYG_frame[data-variant=thumbnail],.AdZSYG_error[data-variant=thumbnail]{box-sizing:border-box;border-radius:var(--qilin-radius-lg);place-items:center;width:48px;min-width:48px;height:48px;min-height:48px;padding:2px;display:grid;overflow:hidden}.AdZSYG_frame[data-variant=thumbnail] img{object-fit:contain}.AdZSYG_spinner{animation:.9s linear infinite AdZSYG_spinner-rotate}@keyframes AdZSYG_spinner-rotate{to{transform:rotate(360deg)}}@media (prefers-reduced-motion:reduce){.AdZSYG_spinner{animation:none}}.AdZSYG_frame:focus-visible,.AdZSYG_error:focus-visible{outline:var(--qilin-focus-ring-width) solid var(--qilin-focus-ring-color,var(--qilin-alias-state-business-primary));outline-offset:2px}";
673
693
  const tagId = "@qilin-agent/client-ui-attachment/MessageImage.module.css";
674
694
  if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId) + "]") === null) {
675
695
  const tag = document.createElement("style");
@@ -729,15 +749,18 @@ window.__ModuleLoader__.load({
729
749
  * @param props.load - session-authorized URL loader for the durable arm.
730
750
  * @param props.variant - lone image, cropped gallery tile, or uncropped list thumbnail.
731
751
  * @param props.labels - resolved strings (tooltip, loading, retry, lightbox).
752
+ * @param props.getTriggerProps - ordinary gesture binding for the original image.
732
753
  * @returns the bounded thumbnail button, or the retry control on failure.
733
754
  */
734
- function MessageImage({ image, load, variant, labels }) {
755
+ function MessageImage({ image, load, variant, labels, getTriggerProps }) {
735
756
  const preview = "preview" in image ? image.preview : void 0;
736
757
  const attachment = "attachment" in image ? image.attachment : void 0;
737
758
  const [loaded, setLoaded] = (0, react.useState)(() => attachment === void 0 ? null : load.peek?.(attachment) ?? null);
738
759
  const [error, setError] = (0, react.useState)(false);
739
760
  const [open, setOpen] = (0, react.useState)(false);
740
761
  const [attempt, setAttempt] = (0, react.useState)(0);
762
+ const autoReloads = (0, react.useRef)(0);
763
+ const autoReloadsFor = (0, react.useRef)(void 0);
741
764
  const request = (0, react.useCallback)(() => {
742
765
  setAttempt((a) => a + 1);
743
766
  }, []);
@@ -757,6 +780,10 @@ window.__ModuleLoader__.load({
757
780
  if (attachment === void 0) return;
758
781
  let live = true;
759
782
  setError(false);
783
+ if (autoReloadsFor.current !== attachment.attachmentId) {
784
+ autoReloads.current = 0;
785
+ autoReloadsFor.current = attachment.attachmentId;
786
+ }
760
787
  setLoaded(load.peek?.(attachment) ?? null);
761
788
  load(attachment).then((url) => {
762
789
  if (live) setLoaded(url);
@@ -773,6 +800,14 @@ window.__ModuleLoader__.load({
773
800
  ]);
774
801
  const src = preview?.url ?? loaded;
775
802
  const label = ("attachment" in image ? image.label : void 0) ?? preview?.name ?? attachment?.name ?? labels.image;
803
+ const contextMenuProps = getTriggerProps(src === null ? void 0 : {
804
+ kind: "image",
805
+ value: {
806
+ url: src,
807
+ name: label,
808
+ ...attachment === void 0 ? {} : { mediaType: attachment.mediaType }
809
+ }
810
+ });
776
811
  const loadingThumbnail = variant === "thumbnail" && src === null;
777
812
  if (error) return (0, react_jsx_runtime.jsx)("button", {
778
813
  type: "button",
@@ -783,7 +818,7 @@ window.__ModuleLoader__.load({
783
818
  onClick: request,
784
819
  children: variant === "thumbnail" ? (0, react_jsx_runtime.jsx)("span", {
785
820
  "aria-hidden": "true",
786
- children: (0, react_jsx_runtime.jsx)(_qilin_agent_client_ui_primitives.IconRefreshOutline16, {})
821
+ children: (0, react_jsx_runtime.jsx)(_qilin_agent_client_ui_primitives.IconRefreshOutlineRegular, {})
787
822
  }) : labels.loadFailed
788
823
  });
789
824
  return (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [(0, react_jsx_runtime.jsx)("button", {
@@ -797,28 +832,36 @@ window.__ModuleLoader__.load({
797
832
  title: loadingThumbnail ? labels.loading : labels.open,
798
833
  "aria-label": loadingThumbnail ? labels.loading : labels.openNamed(label),
799
834
  "aria-busy": loadingThumbnail || void 0,
835
+ ...contextMenuProps,
800
836
  onClick: () => {
801
837
  if (src !== null) setOpen(true);
802
838
  },
803
839
  children: src === null ? (0, react_jsx_runtime.jsx)("span", {
804
840
  className: MessageImage_module_css_default.loading,
805
841
  "aria-hidden": loadingThumbnail || void 0,
806
- children: loadingThumbnail ? (0, react_jsx_runtime.jsx)(_qilin_agent_client_ui_primitives.IconLoadingOutline16, { className: MessageImage_module_css_default.spinner }) : labels.loading
842
+ children: loadingThumbnail ? (0, react_jsx_runtime.jsx)(_qilin_agent_client_ui_primitives.IconLoadingOutlineRegular, { className: MessageImage_module_css_default.spinner }) : labels.loading
807
843
  }) : (0, react_jsx_runtime.jsx)("img", {
808
844
  src,
809
845
  alt: label,
810
- style: fit === void 0 ? void 0 : { objectPosition: fit.objectPosition }
846
+ style: fit === void 0 ? void 0 : { objectPosition: fit.objectPosition },
847
+ onError: attachment === void 0 ? void 0 : () => {
848
+ if (autoReloads.current < 1) {
849
+ autoReloads.current += 1;
850
+ request();
851
+ } else setError(true);
852
+ }
811
853
  })
812
854
  }), open && src !== null && (0, react_jsx_runtime.jsx)(_qilin_agent_client_ui_primitives.ImageLightbox, {
813
855
  src,
814
856
  alt: label,
815
857
  labels: labels.lightbox,
816
- onClose: close
858
+ onClose: close,
859
+ contextMenuProps
817
860
  })] });
818
861
  }
819
862
  /** Wrapping image group shared by user and assistant history: a lone image
820
863
  * renders large unless its owner requests compact tiles or contained list thumbnails. */
821
- function ImageGallery({ images, load, align, compact = false, thumbnail = false, labels }) {
864
+ function ImageGallery({ images, load, align, compact = false, thumbnail = false, labels, getTriggerProps }) {
822
865
  if (images.length === 0) return null;
823
866
  const variant = thumbnail ? "thumbnail" : compact || images.length > 1 ? "tile" : "single";
824
867
  return (0, react_jsx_runtime.jsx)("div", {
@@ -828,21 +871,24 @@ window.__ModuleLoader__.load({
828
871
  image,
829
872
  load,
830
873
  variant,
831
- labels
874
+ labels,
875
+ getTriggerProps
832
876
  }, `${"attachment" in image ? image.attachment.attachmentId : image.preview.url}:${index}`))
833
877
  });
834
878
  }
835
879
  //#endregion
836
880
  //#region lib/types/client/MessageImages.js
837
881
  /** Historical message-image slot entry. */
838
- function MessageImages({ images, loadImage, align, compact = false, thumbnail = false, t }) {
882
+ function MessageImages({ images, loadImage, align, compact = false, thumbnail = false, t, useContextMenu }) {
883
+ const { getTriggerProps } = useContextMenu();
839
884
  return (0, react_jsx_runtime.jsx)(ImageGallery, {
840
885
  images,
841
886
  load: loadImage,
842
887
  align,
843
888
  compact,
844
889
  thumbnail,
845
- labels: messageImageLabels(t)
890
+ labels: messageImageLabels(t),
891
+ getTriggerProps
846
892
  });
847
893
  }
848
894
  //#endregion
@@ -1,5 +1,6 @@
1
1
  import type { ImageAttachmentRef } from '@qilin-agent/attachment';
2
2
  import type { ImageLightboxLabels } from '@qilin-agent/client-ui-primitives';
3
+ import type { ContextMenuBindings } from '@qilin-agent/client-ui-context-menu/client';
3
4
  /** Loads a session-authorized durable image URL and may expose a cached URL synchronously. */
4
5
  export type ImageLoader = ((attachment: ImageAttachmentRef) => Promise<string>) & {
5
6
  peek?: (attachment: ImageAttachmentRef) => string | undefined;
@@ -43,22 +44,25 @@ export interface MessageImageLabels {
43
44
  * @param props.load - session-authorized URL loader for the durable arm.
44
45
  * @param props.variant - lone image, cropped gallery tile, or uncropped list thumbnail.
45
46
  * @param props.labels - resolved strings (tooltip, loading, retry, lightbox).
47
+ * @param props.getTriggerProps - ordinary gesture binding for the original image.
46
48
  * @returns the bounded thumbnail button, or the retry control on failure.
47
49
  */
48
- export declare function MessageImage({ image, load, variant, labels }: {
50
+ export declare function MessageImage({ image, load, variant, labels, getTriggerProps }: {
49
51
  image: MessageImageSpec;
50
52
  load: ImageLoader;
51
53
  variant: 'single' | 'tile' | 'thumbnail';
52
54
  labels: MessageImageLabels;
55
+ getTriggerProps: ContextMenuBindings['getTriggerProps'];
53
56
  }): import("react").JSX.Element;
54
57
  /** Wrapping image group shared by user and assistant history: a lone image
55
58
  * renders large unless its owner requests compact tiles or contained list thumbnails. */
56
- export declare function ImageGallery({ images, load, align, compact, thumbnail, labels }: {
59
+ export declare function ImageGallery({ images, load, align, compact, thumbnail, labels, getTriggerProps }: {
57
60
  images: readonly MessageImageSpec[];
58
61
  load: ImageLoader;
59
62
  align: 'start' | 'end';
60
63
  compact?: boolean;
61
64
  thumbnail?: boolean;
62
65
  labels: MessageImageLabels;
66
+ getTriggerProps: ContextMenuBindings['getTriggerProps'];
63
67
  }): import("react").JSX.Element | null;
64
68
  //# sourceMappingURL=MessageImage.d.ts.map
@@ -1,4 +1,4 @@
1
1
  import type { MessageImagesProps } from '@qilin-agent/client-ui-chat/client';
2
2
  /** Historical message-image slot entry. */
3
- export declare function MessageImages({ images, loadImage, align, compact, thumbnail, t }: MessageImagesProps): import("react").JSX.Element;
3
+ export declare function MessageImages({ images, loadImage, align, compact, thumbnail, t, useContextMenu }: MessageImagesProps): import("react").JSX.Element;
4
4
  //# sourceMappingURL=MessageImages.d.ts.map
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@qilin-agent/client-ui-attachment",
3
3
  "description": "Dynamic attachment presentation plugin for conversation input, message-image, and trajectory image slots",
4
- "version": "3.1.6",
4
+ "version": "3.1.8",
5
5
  "publishConfig": {
6
6
  "access": "public"
7
7
  },
@@ -42,20 +42,21 @@
42
42
  },
43
43
  "license": "MIT",
44
44
  "devDependencies": {
45
+ "@qilin-agent/kylin": "~4.0.6-alpha.2",
45
46
  "@types/react": "~18.3.1",
46
47
  "@types/react-dom": "~18.3.0",
48
+ "@qilin-agent/client-ui-chat": "3.1.8",
49
+ "@qilin-agent/client-ui-conversation": "3.1.8",
50
+ "@qilin-agent/client-ui-trajectory": "3.1.8",
51
+ "@qilin-agent/client-ui-renderer": "3.1.8",
52
+ "@qilin-agent/client-ui-primitives": "3.1.8",
53
+ "@qilin-agent/client-ui-context-menu": "3.1.8",
54
+ "@qilin-agent/client-ui-slots": "3.1.8",
47
55
  "react": "^18.2.0",
48
56
  "react-dom": "^18.2.0",
49
- "clsx": "^2.0.0",
50
- "@qilin-agent/kylin": "~4.0.5",
51
- "@qilin-agent/client-ui-chat": "3.1.6",
52
- "@qilin-agent/client-ui-conversation": "3.1.6",
53
- "@qilin-agent/client-ui-trajectory": "3.1.6",
54
- "@qilin-agent/client-ui-primitives": "3.1.6",
55
- "@qilin-agent/attachment": "3.1.6",
56
- "@qilin-agent/client-ui-slots": "3.1.6",
57
- "@qilin-agent/client-ui-tool": "3.1.6",
58
- "@qilin-agent/client-ui-renderer": "3.1.6"
57
+ "@qilin-agent/attachment": "3.1.8",
58
+ "@qilin-agent/client-ui-tool": "3.1.8",
59
+ "clsx": "^2.0.0"
59
60
  },
60
61
  "files": [
61
62
  "lib/index.js",
@@ -63,7 +64,7 @@
63
64
  "lib/types/**/*.d.ts"
64
65
  ],
65
66
  "peerDependencies": {
66
- "@qilin-agent/kylin": "~4.0.5"
67
+ "@qilin-agent/kylin": "~4.0.6-alpha.2"
67
68
  },
68
69
  "scripts": {
69
70
  "bundle": "tsdown",