@dsh-plus/image-studio 0.1.7 → 0.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
@@ -2616,6 +2616,14 @@ ${extra}
2616
2616
  function presetId(prefix) {
2617
2617
  return `${prefix}-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 6)}`;
2618
2618
  }
2619
+ /** 单选上传结果 → 遮罩引用(无成功条目时保持原值)。 */
2620
+ function uploadRef(entries) {
2621
+ const first = entries[0];
2622
+ return first === void 0 ? null : {
2623
+ kind: "upload",
2624
+ id: first.id
2625
+ };
2626
+ }
2619
2627
  function GeneratorForm(props) {
2620
2628
  const { t, endpoint, catalog, protocols, presets, gallery, scope, api } = props;
2621
2629
  const [providerId, setProviderId] = (0, react.useState)("");
@@ -2980,40 +2988,52 @@ ${extra}
2980
2988
  className: "ims-hint",
2981
2989
  children: t("sources.count").replace("{n}", String(sources.length))
2982
2990
  }),
2983
- uploads.error !== null ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("p", {
2984
- className: "ims-status ims-statusError",
2985
- role: "alert",
2986
- children: [t("upload.failed"), uploads.error]
2987
- }) : null,
2988
2991
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("h3", {
2989
2992
  className: "ims-blockTitle",
2990
2993
  children: t("sources.mask")
2991
2994
  }),
2992
2995
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2993
2996
  className: "ims-sources",
2994
- children: [mask !== null ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
2995
- className: "ims-thumb",
2996
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("img", {
2997
- src: refUrl(mask),
2998
- alt: ""
2999
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
2997
+ children: [
2998
+ mask !== null ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
2999
+ className: "ims-thumb",
3000
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("img", {
3001
+ src: refUrl(mask),
3002
+ alt: ""
3003
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
3004
+ type: "button",
3005
+ className: "ims-thumbRemove",
3006
+ "aria-label": t("sources.maskClear"),
3007
+ onClick: () => setMask(null),
3008
+ children: "×"
3009
+ })]
3010
+ }) : null,
3011
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
3000
3012
  type: "button",
3001
- className: "ims-thumbRemove",
3002
- "aria-label": t("sources.maskClear"),
3003
- onClick: () => setMask(null),
3004
- children: "×"
3005
- })]
3006
- }) : null, /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
3007
- type: "button",
3008
- className: "ims-thumbAdd",
3009
- onClick: () => setPicker("mask"),
3010
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(IconLayers, { size: 18 }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t("sources.maskPick") })]
3011
- })]
3013
+ className: "ims-thumbAdd",
3014
+ onClick: () => setPicker("mask"),
3015
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(IconLayers, { size: 18 }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t("sources.maskPick") })]
3016
+ }),
3017
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(UploadButton, {
3018
+ t,
3019
+ uploads,
3020
+ multiple: false,
3021
+ accept: "image/png",
3022
+ className: "ims-thumbAdd",
3023
+ onUploaded: (entries) => setMask(uploadRef(entries)),
3024
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconPlusOutline16, { size: 18 }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t("upload.pick") })]
3025
+ })
3026
+ ]
3012
3027
  }),
3013
3028
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
3014
3029
  className: "ims-hint",
3015
3030
  children: t("sources.maskHint")
3016
- })
3031
+ }),
3032
+ uploads.error !== null ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("p", {
3033
+ className: "ims-status ims-statusError",
3034
+ role: "alert",
3035
+ children: [t("upload.failed"), uploads.error]
3036
+ }) : null
3017
3037
  ]
3018
3038
  }) : null
3019
3039
  ]
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dsh-plus/image-studio",
3
- "version": "0.1.7",
3
+ "version": "0.1.8",
4
4
  "description": "dsh-plus service+ui plugin: 图像工作室——OpenAI Images 协议文生图/图生图,全参数开关化,双预设体系,并发生图任务与可二次编辑画廊",
5
5
  "type": "module",
6
6
  "main": "lib/index.js",
@@ -15,7 +15,13 @@ import {
15
15
  type Scope,
16
16
  } from '@dsh-plus/shared/client'
17
17
  import { type ReactElement, useEffect, useMemo, useRef, useState } from 'react'
18
- import type { GenerateRequest, PresetsWire, ProvidersWire, SourceRef } from '../../dto.ts'
18
+ import type {
19
+ GenerateRequest,
20
+ PresetsWire,
21
+ ProvidersWire,
22
+ SourceRef,
23
+ UploadEntry,
24
+ } from '../../dto.ts'
19
25
  import type { GalleryItem } from '../../gallery/store.ts'
20
26
  import { MAX_SOURCE_IMAGES } from '../../limits.ts'
21
27
  import type { ParamEntry } from '../../params/catalog.ts'
@@ -66,6 +72,12 @@ function presetId(prefix: string): string {
66
72
  return `${prefix}-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 6)}`
67
73
  }
68
74
 
75
+ /** 单选上传结果 → 遮罩引用(无成功条目时保持原值)。 */
76
+ function uploadRef(entries: UploadEntry[]): SourceRef | null {
77
+ const first = entries[0]
78
+ return first === undefined ? null : { kind: 'upload', id: first.id }
79
+ }
80
+
69
81
  export function GeneratorForm(props: GeneratorProps): ReactElement {
70
82
  const { t, endpoint, catalog, protocols, presets, gallery, scope, api } = props
71
83
  const [providerId, setProviderId] = useState('')
@@ -433,12 +445,6 @@ export function GeneratorForm(props: GeneratorProps): ReactElement {
433
445
  </UploadButton>
434
446
  </div>
435
447
  <p className="ims-hint">{t('sources.count').replace('{n}', String(sources.length))}</p>
436
- {uploads.error !== null ? (
437
- <p className="ims-status ims-statusError" role="alert">
438
- {t('upload.failed')}
439
- {uploads.error}
440
- </p>
441
- ) : null}
442
448
  <h3 className="ims-blockTitle">{t('sources.mask')}</h3>
443
449
  <div className="ims-sources">
444
450
  {mask !== null ? (
@@ -458,8 +464,26 @@ export function GeneratorForm(props: GeneratorProps): ReactElement {
458
464
  <IconLayers size={18} />
459
465
  <span>{t('sources.maskPick')}</span>
460
466
  </button>
467
+ <UploadButton
468
+ t={t}
469
+ uploads={uploads}
470
+ multiple={false}
471
+ // 遮罩必须 PNG(官方要求带透明通道),文件选择器先行收窄。
472
+ accept="image/png"
473
+ className="ims-thumbAdd"
474
+ onUploaded={(entries) => setMask(uploadRef(entries))}
475
+ >
476
+ <IconPlusOutline16 size={18} />
477
+ <span>{t('upload.pick')}</span>
478
+ </UploadButton>
461
479
  </div>
462
480
  <p className="ims-hint">{t('sources.maskHint')}</p>
481
+ {uploads.error !== null ? (
482
+ <p className="ims-status ims-statusError" role="alert">
483
+ {t('upload.failed')}
484
+ {uploads.error}
485
+ </p>
486
+ ) : null}
463
487
  </section>
464
488
  ) : null}
465
489
  </div>