{"_id":"@buckeyestudio/toh-client-ui-attachment","name":"@buckeyestudio/toh-client-ui-attachment","dist-tags":{"next":"0.1.1-rc.2","latest":"0.1.1-rc.2"},"versions":{"0.1.1-rc.2":{"name":"@buckeyestudio/toh-client-ui-attachment","description":"Dynamic attachment presentation plugin for conversation input and message-image slots","version":"0.1.1-rc.2","publishConfig":{"access":"public"},"repository":{"type":"git","url":"git+https://github.com/dustinwloring1988/theopen-harness.git","directory":"packages/client/ui-attachment"},"type":"module","main":"lib/index.js","types":"lib/types/index.d.ts","exports":{".":{"types":"./lib/types/index.d.ts","default":"./lib/index.js"},"./invariant":{"types":"./lib/types/invariant.d.ts","default":"./lib/invariant.js"},"./client":{"types":"./lib/types/client/index.d.ts","default":"./lib/client.js"},"./src/*":"./src/*","./package.json":"./package.json"},"toh":{"client":{"inject":["@buckeyestudio/toh-client-ui-conversation"],"platform":"web"}},"license":"MIT","author":{"name":"buckeyestudio"},"dependencies":{"clsx":"^2.0.0"},"devDependencies":{"@types/react":"~19.2.3","@types/react-dom":"~19.2.3","react":"^19.2.8","react-dom":"^19.2.8","@buckeyestudio/toh-invariants":"^0.1.1-rc.2","@buckeyestudio/toh-client-runtime":"^0.1.1-rc.2","@buckeyestudio/cordis":"^4.0.1","@buckeyestudio/toh-client-ui-primitives":"^0.1.1-rc.2","@buckeyestudio/toh-client-ui-conversation":"^0.1.1-rc.2","@buckeyestudio/toh-client-ui-slots":"^0.1.1-rc.2","@buckeyestudio/toh-attachment":"^0.1.1-rc.2"},"peerDependencies":{"@buckeyestudio/toh-client-ui-conversation":"^0.1.1-rc.2","@buckeyestudio/toh-client-runtime":"^0.1.1-rc.2","@buckeyestudio/toh-attachment":"^0.1.1-rc.2","@buckeyestudio/toh-invariants":"^0.1.1-rc.2","@buckeyestudio/cordis":"^4.0.1"},"scripts":{"bundle":"tsdown","watch":"tsdown --watch"},"_id":"@buckeyestudio/toh-client-ui-attachment@0.1.1-rc.2","bugs":{"url":"https://github.com/dustinwloring1988/theopen-harness/issues"},"homepage":"https://github.com/dustinwloring1988/theopen-harness#readme","_integrity":"sha512-YlvLar/R+q/wMf+0Vx4KEHCCVXr4jJLw34EjYr8chMsPSXDJOs5RXmsNqTlWuo/eqx1lgUQZXtw7HBMGZgq1GQ==","_resolved":"/home/runner/work/theopen-harness/theopen-harness/dist/npm/buckeyestudio-toh-client-ui-attachment-0.1.1-rc.2.tgz","_from":"file:/home/runner/work/theopen-harness/theopen-harness/dist/npm/buckeyestudio-toh-client-ui-attachment-0.1.1-rc.2.tgz","_nodeVersion":"24.19.0","_npmVersion":"11.17.0","dist":{"integrity":"sha512-YlvLar/R+q/wMf+0Vx4KEHCCVXr4jJLw34EjYr8chMsPSXDJOs5RXmsNqTlWuo/eqx1lgUQZXtw7HBMGZgq1GQ==","shasum":"a1725e3f48ed97ad2afd0fb0b1726953dbb85aab","tarball":"https://registry.npmjs.org/@buckeyestudio/toh-client-ui-attachment/-/toh-client-ui-attachment-0.1.1-rc.2.tgz","fileCount":18,"unpackedSize":58912,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIDEkqAn4zMloc80t0vk3SzVS8Lg9CuWqZVDIPFA1wjeaAiEA/yAauxLeB6uPMOjWgXSgsV09l9v+wpUgbZQJS02RJmU="}]},"_npmUser":{"name":"buckeyestudio","email":"dustinwloring1988@gmail.com"},"directories":{},"maintainers":[{"name":"buckeyestudio","email":"dustinwloring1988@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/toh-client-ui-attachment_0.1.1-rc.2_1787489582489_0.8038977925297599"},"_hasShrinkwrap":false}},"time":{"created":"2026-08-23T12:53:02.316Z","0.1.1-rc.2":"2026-08-23T12:53:02.631Z","modified":"2026-08-23T12:53:02.790Z"},"maintainers":[{"name":"buckeyestudio","email":"dustinwloring1988@gmail.com"}],"description":"Dynamic attachment presentation plugin for conversation input and message-image slots","homepage":"https://github.com/dustinwloring1988/theopen-harness#readme","repository":{"type":"git","url":"git+https://github.com/dustinwloring1988/theopen-harness.git","directory":"packages/client/ui-attachment"},"author":{"name":"buckeyestudio"},"bugs":{"url":"https://github.com/dustinwloring1988/theopen-harness/issues"},"license":"MIT","readme":"# @buckeyestudio/toh-client-ui-attachment\n\n[English](README.md) | 中文\n\n对话 UI 的动态附件呈现插件。它通过 `ctx.slots.inject` 等待 conversation 包声明 `conversation.input.attachments` 与 `conversation.message.images`，随后注册输入框草稿图片栏、文档拖放目标、聊天历史图片画廊和原图灯箱。conversation slot 持有方提供附件数据、图片加载、回调及其命名空间翻译器；呈现组件保持纯 props，且不从包入口导出。\n\n## 附件栏\n\n`AttachmentRail` 将待发送草稿图片渲染为固定 64px（16px 圆角）的缩略图横排，滚动条始终隐藏，溢出改由两端的圆形箭头提示：每次翻页滚动一个视口宽度（减去一张卡片作为上下文，下限 200px）并平滑滚动（`prefers-reduced-motion: reduce` 下瞬时完成），箭头的显隐在滚动、条目数量变化和栏自身尺寸变化时依据滚动几何重算（rail 元素上的 ResizeObserver，因此侧栏、面板的宽度变化也计入，不只是窗口尺寸变化）。附件栏只允许横向滚动：非 passive 监听器消费所有带纵向分量的滚轮事件——不会滚动输入框背后的会话记录——纯纵向滚轮转为横向步进（LINE/PAGE 单位先归一化为像素，单次行程钳制在 60px 内），对角平移保留其横向分量，纯横向平移保持原生滚动。新增条目会滚动到栏尾展示，删除则保持原位，带着已有草稿重新挂载的栏保持起始位置。每张缩略图单击经 `onOpen` 打开原图，删除按钮位于卡片内部右上角，悬停卡片或键盘聚焦时才显示；粗指针（触屏）设备没有悬停，因此常显。是否挂载由持有方决定，仅在有条目时渲染。\n\n## 消息图片与灯箱\n\n`MessageImage` 渲染一张持久化历史图片，经持有方的 `ImageLoader` 加载会话授权 URL；加载失败渲染显式重试按钮，加载完成后单击打开 `ImageLightbox`（加载中的点击被忽略）。尺寸规则对齐 DeepSeek Chat：一条消息仅有的一张图（`variant=\"single\"`）长边 240px、展示宽高比钳制在 [0.25, 4] 之间——超出部分由 `object-fit: cover` 裁切，特别高的图锚定顶部、特别宽的图锚定左侧——且从不放大超过原始尺寸；多图中的一张（`variant=\"tile\"`）为固定 64px 方块。`ImageGallery` 将一条消息的图片包为一个对齐的可换行弹性分组（用户消息 `end`，助手消息 `start`），按图片数量选择 variant，空列表不渲染。`ImageLightbox` 是文档级模态预览，铺在共享的对话框遮罩上（`--dsw-alias-bg-mask-1` 加 `--dsw-mask-blur`，画在独立图层上，模糊不会波及预览图本身），按 Escape、按下遮罩或点关闭按钮均可关闭，卸载时将焦点还给打开者。\n\n## 拖放遮罩\n\n`DropOverlay` 是文件拖拽悬停页面时的全视口邀请层：插画、标题，接受拖放时再加一行上限说明（`disabled` 换为禁用插画并隐藏上限行）。该层不接收指针事件——持有方的 document 级拖拽监听器负责 enter/leave 计数和接受与否的判定；遮罩只呈现状态。与灯箱一样经 body portal 渲染。\n\n## 模型体验\n\n无，因为该插件只渲染由对话 UI 提供的附件状态，不贡献模型可见输入。\n\n#### KV Cache 影响\n\n无；该包既不组装也不发送提供方请求。\n\n## 已知限制与暂缓事项\n\n- **仅支持图片** — 非图片文件尚无附件栏卡片与历史渲染；DeepSeek Chat 风格的文件卡片和上传进度状态等输入框接受非图片附件后再做。\n- **灯箱无缩放与下载** — 预览仅以适配视口的尺寸渲染原图。\n- **灯箱不锁定焦点** — 它设置 `aria-modal` 并在关闭时归还焦点，但 Tab 仍可移动到背后的页面。\n","readmeFilename":"README.zh.md","_rev":"1-a891e3c81327265e962b73e8b4e2a5da"}