@dsh-plus/image-studio 0.1.23 → 0.1.25

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
@@ -4,9 +4,175 @@ window.__ModuleLoader__.load({
4
4
  var module = { exports: {} };
5
5
  var exports = module.exports;
6
6
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
7
- let react = require("react");
8
7
  let react_jsx_runtime = require("react/jsx-runtime");
8
+ let react = require("react");
9
9
  let _deepseek_ai_dsh_client_ui_primitives = require("@deepseek-ai/dsh-client-ui-primitives");
10
+ //#region ../shared/src/client/card.tsx
11
+ const IDLE_STATUS = {
12
+ kind: "idle",
13
+ text: ""
14
+ };
15
+ function CardChrome(props) {
16
+ const p = props.prefix;
17
+ const badge = props.statusBadge;
18
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
19
+ className: `${p}-section`,
20
+ "aria-label": props.title,
21
+ children: [
22
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
23
+ className: `${p}-sectionHead`,
24
+ children: [
25
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("h3", {
26
+ className: `${p}-sectionTitle`,
27
+ children: props.title
28
+ }),
29
+ badge !== void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
30
+ className: `${p}-sectionBadge ${badge.on ? `${p}-statusOn` : `${p}-statusOff`}`,
31
+ children: badge.text
32
+ }) : null,
33
+ props.dirty ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
34
+ className: `${p}-pending`,
35
+ children: props.dirtyLabel
36
+ }) : null
37
+ ]
38
+ }),
39
+ props.description === "" ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
40
+ className: `${p}-sectionDesc`,
41
+ children: props.description
42
+ }),
43
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
44
+ className: `${p}-sectionBody`,
45
+ children: [
46
+ props.readOnlyNotice !== void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
47
+ className: `${p}-readOnly`,
48
+ role: "status",
49
+ children: props.readOnlyNotice
50
+ }) : null,
51
+ props.children,
52
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
53
+ className: `${p}-sectionFooter`,
54
+ children: [props.status !== void 0 && props.status.kind !== "idle" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
55
+ className: `${p}-status${props.status.kind === "error" ? ` ${p}-statusError` : ""}`,
56
+ role: "status",
57
+ children: props.status.text
58
+ }) : null, props.actions.map((action) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
59
+ type: "button",
60
+ className: `${p}-btn ${action.variant === "primary" ? `${p}-btnPrimary` : `${p}-btnGhost`}`,
61
+ disabled: action.disabled === true,
62
+ onClick: action.onClick,
63
+ children: action.label
64
+ }, action.key))]
65
+ })
66
+ ]
67
+ })
68
+ ]
69
+ });
70
+ }
71
+ /** 取值未到达时的占位:与 CardChrome 同形态,避免宿主页里闪一次卡片外壳。 */
72
+ function CardLoading(props) {
73
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("section", {
74
+ className: `${props.prefix}-section`,
75
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
76
+ className: `${props.prefix}-readOnly`,
77
+ role: "status",
78
+ children: props.text
79
+ })
80
+ });
81
+ }
82
+ //#endregion
83
+ //#region ../shared/src/client/config-slots.ts
84
+ /** dsh-plus 聚合 bundle 的包名(各插件 row 均经其补丁层插入 profile)。 */
85
+ const DSH_PLUS_BUNDLE = "@dsh-plus/bundle-main";
86
+ /**
87
+ * 把一张配置卡片注册进插件页的两个配置槽位。
88
+ * 两个槽位都由 0.2.1-alpha.1 的插件页声明,任一缺席即报错——不做版本探测。
89
+ */
90
+ function injectPluginConfigCard(slots, reg) {
91
+ const base = {
92
+ locale: reg.ns,
93
+ inject: reg.inject
94
+ };
95
+ slots.inject("plugins.row.config", () => slots.register({
96
+ name: "plugins.row.config",
97
+ key: `${DSH_PLUS_BUNDLE}#${reg.rowId}`,
98
+ ...base
99
+ }, reg.component));
100
+ slots.inject("plugins.bundle.config", () => slots.register({
101
+ name: "plugins.bundle.config",
102
+ key: reg.pkg,
103
+ ...base
104
+ }, reg.component));
105
+ }
106
+ //#endregion
107
+ //#region ../shared/src/client/draft.ts
108
+ /**
109
+ * 单命名空间 staged 草稿(简单配置卡片共用):读 scope 快照、播种草稿、
110
+ * 脏判定、保存(revision fencing + 重新装载)与状态行。
111
+ *
112
+ * 语义与官方 staged 表单一致:Host 更新不覆盖在途编辑,只有保存才写回;
113
+ * 保存成功后按 Host 解析值重置草稿。`from`/`patch` 参与 effect 与 useMemo
114
+ * 依赖,必须是模块级稳定函数(不要内联箭头函数)。
115
+ * @module @dsh-plus/shared/client/draft
116
+ */
117
+ //#endregion
118
+ //#region ../shared/src/client/fetch.ts
119
+ async function parse(res, guard) {
120
+ const body = await res.json();
121
+ if (!res.ok) throw new Error(body.error ?? `HTTP ${res.status}`);
122
+ if (guard !== void 0 && !guard(body)) throw new Error(`响应结构不符合预期(${res.url})`);
123
+ return body;
124
+ }
125
+ /** GET 同源 JSON 端点。 */
126
+ async function getJson(route, guard) {
127
+ return parse(await fetch(route, { credentials: "same-origin" }), guard);
128
+ }
129
+ /** POST 同源 JSON 端点(body 可省略)。 */
130
+ async function postJson(route, body, guard) {
131
+ return parse(await fetch(route, {
132
+ method: "POST",
133
+ credentials: "same-origin",
134
+ headers: { "content-type": "application/json" },
135
+ ...body === void 0 ? {} : { body: JSON.stringify(body) }
136
+ }), guard);
137
+ }
138
+ //#endregion
139
+ //#region ../shared/src/client/fields.tsx
140
+ function TextField(props) {
141
+ const p = props.prefix ?? "dshp";
142
+ const invalid = props.invalid === true;
143
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
144
+ className: `${p}-field`,
145
+ children: [
146
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
147
+ className: `${p}-head`,
148
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("label", {
149
+ className: `${p}-label`,
150
+ htmlFor: props.id,
151
+ children: props.label
152
+ }), props.badge !== void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
153
+ className: `${p}-badge ${props.badge.set ? `${p}-badgeSet` : `${p}-badgeUnset`}`,
154
+ children: props.badge.text
155
+ }) : null]
156
+ }),
157
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
158
+ id: props.id,
159
+ className: `${p}-input${invalid ? ` ${p}-inputInvalid` : ""}`,
160
+ type: props.password === true ? "password" : "text",
161
+ inputMode: props.numeric === true ? "numeric" : void 0,
162
+ autoComplete: props.password === true ? "off" : void 0,
163
+ "aria-invalid": invalid || void 0,
164
+ value: props.value,
165
+ disabled: props.disabled === true,
166
+ onChange: (event) => props.onEdit(event.target.value)
167
+ }),
168
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
169
+ className: invalid ? `${p}-invalid` : `${p}-hint`,
170
+ children: invalid ? props.invalidLabel ?? "" : props.hint ?? ""
171
+ })
172
+ ]
173
+ });
174
+ }
175
+ //#endregion
10
176
  //#region ../../node_modules/.pnpm/lucide-react@1.38.0_react@18.2.0/node_modules/lucide-react/dist/esm/shared/src/utils/mergeClasses.mjs
11
177
  /**
12
178
  * @license lucide-react v1.38.0 - ISC
@@ -272,238 +438,6 @@ window.__ModuleLoader__.load({
272
438
  return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Layers, { ...lucideProps(props) });
273
439
  }
274
440
  //#endregion
275
- //#region ../shared/src/client/card.tsx
276
- const IDLE_STATUS = {
277
- kind: "idle",
278
- text: ""
279
- };
280
- /** 状态行 + 动作按钮(两种形态共用,类名随形态切换度量)。 */
281
- function CardFoot(props) {
282
- const p = props.prefix;
283
- const section = props.variant === "section";
284
- return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
285
- className: section ? `${p}-sectionFooter` : `${p}-footer`,
286
- children: [props.status !== void 0 && props.status.kind !== "idle" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
287
- className: `${p}-status${props.status.kind === "error" ? ` ${p}-statusError` : ""}`,
288
- role: "status",
289
- children: props.status.text
290
- }) : null, props.actions.map((action) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
291
- type: "button",
292
- className: `${p}-btn ${action.variant === "primary" ? `${p}-btnPrimary` : `${p}-btnGhost`}`,
293
- disabled: action.disabled === true,
294
- onClick: action.onClick,
295
- children: action.label
296
- }, action.key))]
297
- });
298
- }
299
- /** 只读提示 + 字段区 + 页脚(两种形态共用)。 */
300
- function CardBody(props) {
301
- const p = props.prefix;
302
- return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
303
- props.readOnlyNotice !== void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
304
- className: `${p}-readOnly`,
305
- role: "status",
306
- children: props.readOnlyNotice
307
- }) : null,
308
- props.children,
309
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)(CardFoot, { ...props })
310
- ] });
311
- }
312
- function CardChrome(props) {
313
- const p = props.prefix;
314
- const badge = props.statusBadge;
315
- if (props.variant === "section") return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
316
- className: `${p}-section`,
317
- "aria-label": props.title,
318
- children: [
319
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
320
- className: `${p}-sectionHead`,
321
- children: [
322
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("h3", {
323
- className: `${p}-sectionTitle`,
324
- children: props.title
325
- }),
326
- badge !== void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
327
- className: `${p}-sectionBadge ${badge.on ? `${p}-statusOn` : `${p}-statusOff`}`,
328
- children: badge.text
329
- }) : null,
330
- props.dirty ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
331
- className: `${p}-pending`,
332
- children: props.dirtyLabel
333
- }) : null
334
- ]
335
- }),
336
- props.description === "" ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
337
- className: `${p}-sectionDesc`,
338
- children: props.description
339
- }),
340
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
341
- className: `${p}-sectionBody`,
342
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(CardBody, { ...props })
343
- })
344
- ]
345
- });
346
- return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("li", {
347
- className: `${p}-card${props.open ? ` ${p}-cardOpen` : ""}`,
348
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
349
- type: "button",
350
- className: `${p}-header`,
351
- "aria-expanded": props.open,
352
- "aria-label": props.title,
353
- onClick: () => props.onToggle(!props.open),
354
- children: [
355
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
356
- className: `${p}-headText`,
357
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
358
- className: `${p}-name`,
359
- children: props.title
360
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
361
- className: `${p}-description`,
362
- children: props.description
363
- })]
364
- }),
365
- badge !== void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
366
- className: `${p}-statusBadge ${badge.on ? `${p}-statusOn` : `${p}-statusOff`}`,
367
- children: badge.text
368
- }) : null,
369
- props.dirty ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
370
- className: `${p}-pending`,
371
- children: props.dirtyLabel
372
- }) : null,
373
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconChevronDownOutlineRegular, { className: `${p}-chevron${props.open ? ` ${p}-chevronOpen` : ""}` })
374
- ]
375
- }), props.open ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
376
- className: `${p}-body`,
377
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(CardBody, { ...props })
378
- }) : null]
379
- });
380
- }
381
- /** 取值未到达时的占位:与 CardChrome 同形态,避免宿主页里闪一次卡片外壳。 */
382
- function CardLoading(props) {
383
- if (props.variant === "section") return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("section", {
384
- className: `${props.prefix}-section`,
385
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
386
- className: `${props.prefix}-readOnly`,
387
- role: "status",
388
- children: props.text
389
- })
390
- });
391
- return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("li", {
392
- className: `${props.prefix}-card`,
393
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
394
- className: `${props.prefix}-readOnly`,
395
- role: "status",
396
- children: props.text
397
- })
398
- });
399
- }
400
- //#endregion
401
- //#region ../shared/src/client/config-slots.ts
402
- /** dsh-plus 聚合 bundle 的包名(各插件 row 均经其补丁层插入 profile)。 */
403
- const DSH_PLUS_BUNDLE = "@dsh-plus/bundle-main";
404
- /**
405
- * 视图 → 外壳形态:插件页 page 视图渲染在官方页面容器内(宿主已画标题、图标、
406
- * 面包屑与页面级内边距),再套卡片会形成卡片套卡片并压缩移动端可用宽度,
407
- * 故用无边框分节;summary 与 legacy 槽位保持卡片形态。
408
- */
409
- function cardVariantFor(view) {
410
- return view === "page" ? "section" : "card";
411
- }
412
- /**
413
- * 把一张配置卡片同时注册进 legacy 与新版三个槽位。
414
- * 任一槽位在当前 dsh 版本未声明时对应 inject 挂起等待,版本不命中即 no-op。
415
- */
416
- function injectPluginConfigCard(slots, reg) {
417
- const base = {
418
- locale: reg.ns,
419
- inject: reg.inject
420
- };
421
- slots.inject("settings.plugin.item", () => slots.register({
422
- name: "settings.plugin.item",
423
- key: reg.ns,
424
- ...base
425
- }, reg.component));
426
- slots.inject("plugins.row.config", () => slots.register({
427
- name: "plugins.row.config",
428
- key: `${DSH_PLUS_BUNDLE}#${reg.rowId}`,
429
- ...base
430
- }, reg.component));
431
- slots.inject("plugins.bundle.config", () => slots.register({
432
- name: "plugins.bundle.config",
433
- key: reg.pkg,
434
- ...base
435
- }, reg.component));
436
- }
437
- //#endregion
438
- //#region ../shared/src/client/draft.ts
439
- /**
440
- * 单命名空间 staged 草稿(简单配置卡片共用):读 scope 快照、播种草稿、
441
- * 脏判定、保存(revision fencing + 重新装载)与状态行。
442
- *
443
- * 语义与官方 staged 表单一致:Host 更新不覆盖在途编辑,只有保存才写回;
444
- * 保存成功后按 Host 解析值重置草稿。`from`/`patch` 参与 effect 与 useMemo
445
- * 依赖,必须是模块级稳定函数(不要内联箭头函数)。
446
- * @module @dsh-plus/shared/client/draft
447
- */
448
- //#endregion
449
- //#region ../shared/src/client/fetch.ts
450
- async function parse(res, guard) {
451
- const body = await res.json();
452
- if (!res.ok) throw new Error(body.error ?? `HTTP ${res.status}`);
453
- if (guard !== void 0 && !guard(body)) throw new Error(`响应结构不符合预期(${res.url})`);
454
- return body;
455
- }
456
- /** GET 同源 JSON 端点。 */
457
- async function getJson(route, guard) {
458
- return parse(await fetch(route, { credentials: "same-origin" }), guard);
459
- }
460
- /** POST 同源 JSON 端点(body 可省略)。 */
461
- async function postJson(route, body, guard) {
462
- return parse(await fetch(route, {
463
- method: "POST",
464
- credentials: "same-origin",
465
- headers: { "content-type": "application/json" },
466
- ...body === void 0 ? {} : { body: JSON.stringify(body) }
467
- }), guard);
468
- }
469
- //#endregion
470
- //#region ../shared/src/client/fields.tsx
471
- function TextField(props) {
472
- const p = props.prefix ?? "dshp";
473
- const invalid = props.invalid === true;
474
- return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
475
- className: `${p}-field`,
476
- children: [
477
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
478
- className: `${p}-head`,
479
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("label", {
480
- className: `${p}-label`,
481
- htmlFor: props.id,
482
- children: props.label
483
- }), props.badge !== void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
484
- className: `${p}-badge ${props.badge.set ? `${p}-badgeSet` : `${p}-badgeUnset`}`,
485
- children: props.badge.text
486
- }) : null]
487
- }),
488
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
489
- id: props.id,
490
- className: `${p}-input${invalid ? ` ${p}-inputInvalid` : ""}`,
491
- type: props.password === true ? "password" : "text",
492
- inputMode: props.numeric === true ? "numeric" : void 0,
493
- autoComplete: props.password === true ? "off" : void 0,
494
- "aria-invalid": invalid || void 0,
495
- value: props.value,
496
- disabled: props.disabled === true,
497
- onChange: (event) => props.onEdit(event.target.value)
498
- }),
499
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
500
- className: invalid ? `${p}-invalid` : `${p}-hint`,
501
- children: invalid ? props.invalidLabel ?? "" : props.hint ?? ""
502
- })
503
- ]
504
- });
505
- }
506
- //#endregion
507
441
  //#region ../shared/src/client/scope.ts
508
442
  /**
509
443
  * remote.settings 直连实现的命名空间 scope(官方配置页 tab 同款模式)。
@@ -594,36 +528,33 @@ window.__ModuleLoader__.load({
594
528
  //#endregion
595
529
  //#region ../shared/src/client/styles.ts
596
530
  /**
597
- * 配置卡片样式工厂(各插件 client 的公共收编版)。
598
- * 视觉规则与迁移前逐字一致(类名前缀换为各插件自身,DOM 类名不变),
599
- * 另补移动端与可达性增强(767px 断点 + pointer:coarse,对齐 ui-mobile-fit 约定):
531
+ * 配置分节样式工厂(各插件 client 的公共收编版)。
532
+ *
533
+ * 目标宿主 dsh 0.2.1-alpha.1:插件页把配置视图放进已有页面级内边距的容器里
534
+ * (`div.detailSections[data-plugin-config]` 或 `section.detailSection[data-plugin-config]`),
535
+ * 外层无边框——故这里输出的是**无边框分节**(小节标题 13px/600、字段 12px 0、
536
+ * 横向零内边距、页脚非 sticky),度量对齐官方设置页
537
+ * (`@deepseek-ai/dsh-client-ui-primitives` 的 settings-form)。
538
+ *
539
+ * 移动端与可达性(767px 断点 + pointer:coarse,对齐 ui-mobile-fit 约定):
600
540
  * - 窄屏 input/textarea 16px(防 iOS 聚焦缩放)、可点目标 ≥44px;
601
- * - footer 按钮等宽换行、状态文字独占一行;
602
- * - 展开态 body 底部 sticky 保存栏(长表单滚动中始终可达)。
603
- * - 分节形态(-section,插件页 page 视图内嵌宿主页面):无边框/背景、横向零
604
- * 内边距,页脚不 sticky——官方插件页已提供页面级内边距,再叠一层卡片会
605
- * 缩窄移动端可用宽度(卡片套卡片)。
541
+ * - 页脚按钮等宽换行、状态文字独占一行。
606
542
  * 沿用官方 data-plugin / data-plugin-css 约定(HMR 据此卸载),不覆盖上游选择器。
607
543
  * @module @dsh-plus/shared/client/styles
608
544
  */
609
- /** 生成全套卡片 CSS;prefix 为插件类名前缀(如 'dne'),extra 为插件特有规则。 */
545
+ /** 生成全套分节 CSS;prefix 为插件类名前缀(如 'dne'),extra 为插件特有规则。 */
610
546
  function cardCss(prefix, extra = "") {
611
547
  return `
612
- .${prefix}-card{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-3);border-radius:12px;list-style:none;transition:border-color .16s,background .16s}
613
- .${prefix}-card:hover{border-color:var(--dsw-alias-label-dimmed)}
614
- .${prefix}-cardOpen{background:var(--dsw-alias-bg-layer-2);border-color:var(--dsw-alias-label-dimmed)}
615
- .${prefix}-header{appearance:none;width:100%;font:inherit;color:inherit;text-align:left;cursor:pointer;background:0 0;border:0;border-radius:12px;align-items:center;gap:12px;padding:14px 16px;display:flex}
616
- .${prefix}-header:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:-2px}
617
- .${prefix}-headText{flex-direction:column;flex:1;gap:4px;min-width:0;display:flex}
618
- .${prefix}-name{color:var(--dsw-alias-label-primary);font-size:15px;font-weight:600;line-height:1.4}
619
- .${prefix}-description{color:var(--dsw-alias-label-tertiary);font-size:13px;line-height:1.5}
620
- .${prefix}-chevron{color:var(--dsw-alias-label-tertiary);flex:none;transition:transform .16s;display:inline-flex}
621
- .${prefix}-chevronOpen{transform:rotate(180deg)}
548
+ .${prefix}-section{box-sizing:border-box;flex-direction:column;width:100%;min-width:0;padding:16px 0;display:flex}
549
+ .${prefix}-sectionHead{align-items:center;gap:8px;min-width:0;display:flex}
550
+ .${prefix}-sectionTitle{min-width:0;color:var(--dsw-alias-label-primary);flex:1;margin:0;font-size:13px;font-weight:600;line-height:1.5}
551
+ .${prefix}-sectionBadge{white-space:nowrap;border-radius:999px;flex:none;padding:1px 8px;font-size:11px;font-weight:500;line-height:17px}
552
+ .${prefix}-sectionDesc{color:var(--dsw-alias-label-tertiary);margin:4px 0 0;font-size:12px;line-height:1.5}
553
+ .${prefix}-sectionBody{flex-direction:column;min-width:0;display:flex}
554
+ .${prefix}-sectionFooter{align-items:center;gap:8px;padding-top:16px;display:flex;flex-wrap:wrap}
622
555
  .${prefix}-pending{white-space:nowrap;background:var(--dsw-alias-bg-module-platform);color:var(--dsw-alias-label-secondary);border-radius:999px;flex:none;padding:1px 8px;font-size:11px;font-weight:500;line-height:17px}
623
- .${prefix}-statusBadge{white-space:nowrap;border-radius:999px;flex:none;padding:1px 8px;font-size:11px;font-weight:500;line-height:17px}
624
556
  .${prefix}-statusOn{background:var(--dsw-alias-bg-module-platform);color:var(--dsw-alias-label-secondary)}
625
557
  .${prefix}-statusOff{color:var(--dsw-alias-label-tertiary)}
626
- .${prefix}-body{border-top:1px solid var(--dsw-alias-border-l2);margin:0 16px;padding-bottom:8px}
627
558
  .${prefix}-field{flex-direction:column;gap:6px;padding:12px 0;display:flex}
628
559
  .${prefix}-field+.${prefix}-field{border-top:1px solid var(--dsw-alias-border-l2)}
629
560
  .${prefix}-head{align-items:center;gap:8px;display:flex}
@@ -649,19 +580,9 @@ window.__ModuleLoader__.load({
649
580
  .${prefix}-checkRow input:checked::after{left:16px;background:var(--dsw-alias-bg-base)}
650
581
  .${prefix}-checkRow input:disabled{opacity:.4;cursor:default}
651
582
  .${prefix}-checkRow input:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:2px}
652
- /* 宿主内嵌分节形态(插件页 page 视图):官方设置页同构——无边框/背景,
653
- 横向零内边距(宽度交给宿主页面容器),小节标题 13px/600,页脚非 sticky。 */
654
- .${prefix}-section{box-sizing:border-box;flex-direction:column;width:100%;min-width:0;padding:16px 0;display:flex}
655
- .${prefix}-sectionHead{align-items:center;gap:8px;min-width:0;display:flex}
656
- .${prefix}-sectionTitle{min-width:0;color:var(--dsw-alias-label-primary);flex:1;margin:0;font-size:13px;font-weight:600;line-height:1.5}
657
- .${prefix}-sectionBadge{white-space:nowrap;border-radius:999px;flex:none;padding:1px 8px;font-size:11px;font-weight:500;line-height:17px}
658
- .${prefix}-sectionDesc{color:var(--dsw-alias-label-tertiary);margin:4px 0 0;font-size:12px;line-height:1.5}
659
- .${prefix}-sectionBody{flex-direction:column;min-width:0;display:flex}
660
- .${prefix}-sectionFooter{align-items:center;gap:8px;padding-top:16px;display:flex;flex-wrap:wrap}
661
583
  .${prefix}-groupLabel{color:var(--dsw-alias-label-secondary);font-size:12px;font-weight:600;padding:12px 0 2px;margin:0}
662
584
  .${prefix}-readOnly{color:var(--dsw-alias-label-tertiary);margin:12px 0 0;font-size:12px;line-height:1.5}
663
585
  .${prefix}-warn{color:var(--dsw-alias-label-error);margin:12px 0 0;font-size:12px;line-height:1.5}
664
- .${prefix}-footer{border-top:1px solid var(--dsw-alias-border-l2);justify-content:flex-end;align-items:center;gap:8px;padding:12px 0 4px;display:flex;flex-wrap:wrap}
665
586
  .${prefix}-status{min-width:0;color:var(--dsw-alias-label-secondary);flex:1;margin:0;font-size:12px;line-height:1.5}
666
587
  .${prefix}-statusError{color:var(--dsw-alias-label-error)}
667
588
  .${prefix}-btn{appearance:none;font:inherit;cursor:pointer;border:1px solid #0000;border-radius:8px;padding:5px 14px;font-size:13px;line-height:1.5}
@@ -671,16 +592,10 @@ window.__ModuleLoader__.load({
671
592
  .${prefix}-btn:disabled{opacity:.4;cursor:default}
672
593
  .${prefix}-btn:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:1px}
673
594
  @media (max-width:767px){
674
- .${prefix}-body{margin:0 10px}
675
- .${prefix}-header{padding:12px 12px}
676
595
  .${prefix}-input,.${prefix}-select{font-size:16px;height:40px}
677
596
  .${prefix}-checkRow{min-height:44px;padding:8px 0}
678
- .${prefix}-footer{position:sticky;bottom:0;background:var(--dsw-alias-bg-layer-2);margin:0 -10px;padding:10px 10px 6px;border-top:1px solid var(--dsw-alias-border-l2);border-bottom-left-radius:12px;border-bottom-right-radius:12px}
679
597
  .${prefix}-status{flex-basis:100%;flex:none}
680
598
  .${prefix}-btn{min-height:44px;flex:1;min-width:96px}
681
- .${prefix}-statusBadge{display:none}
682
- .${prefix}-sectionBadge{display:inline-block}
683
- .${prefix}-sectionFooter{position:static}
684
599
  }
685
600
  @media (pointer:coarse){
686
601
  .${prefix}-btn{min-height:44px}
@@ -711,8 +626,8 @@ ${extra}
711
626
  * settings 命名空间字面量(纯常量,零依赖,浏览器半可安全引入)。
712
627
  * 服务端直接以字面量注册(0.1.2-alpha.2 起 dsh-settings 对命名空间做编译期
713
628
  * 语法校验,见 config.ts);浏览器半把它作为配置卡片的注册键
714
- * (legacy settings.plugin.item keyed 槽位按「卡片编辑的 settings 命名空间」
715
- * 分发;0.1.6-alpha.2 起改挂插件页 row/bundle config,见 shared/config-slots),
629
+ * (插件页配置卡片挂在 row/bundle config 槽位上,与命名空间解耦,
630
+ * 见 shared/config-slots),
716
631
  * 同一字面量两处共用,防止漂移。
717
632
  * @module image-studio/ns
718
633
  */
@@ -1514,8 +1429,8 @@ ${extra}
1514
1429
  //#endregion
1515
1430
  //#region src/client/card.tsx
1516
1431
  /**
1517
- * 配置卡片(injectPluginConfigCard 三槽位,legacy key = settings 命名空间,
1518
- * 0.1.6-alpha.2 起为插件页 row/bundle config,view 分发 summary/page):
1432
+ * 配置卡片(injectPluginConfigCard 两槽位 = 插件页 row/bundle config,
1433
+ * view 分发 summary/page):
1519
1434
  * 三组预设(提供商/参数/提示词)+ 高级项(并发/超时/代理/画廊上限)的
1520
1435
  * staged draft 编辑;提供商预设逐条附 API Key 管理(凭据端点,值不回显)。
1521
1436
  * JSON 字段(extraHeaders/paramSpecs)以文本镜像编辑,保存时解析 +
@@ -1612,7 +1527,6 @@ ${extra}
1612
1527
  const { t, scope, api } = props;
1613
1528
  const snapshot = (0, react.useSyncExternalStore)((listener) => scope.subscribe(listener), () => scope.getSnapshot());
1614
1529
  const value = snapshot.value;
1615
- const [open, setOpen] = (0, react.useState)(props.view === "page");
1616
1530
  const [draft, setDraft] = (0, react.useState)(null);
1617
1531
  const [baseline, setBaseline] = (0, react.useState)("");
1618
1532
  const [saving, setSaving] = (0, react.useState)(false);
@@ -1626,10 +1540,8 @@ ${extra}
1626
1540
  }, [value, draft]);
1627
1541
  const dirty = (0, react.useMemo)(() => draft !== null && JSON.stringify(draft) !== baseline, [draft, baseline]);
1628
1542
  if (props.view === "summary") return t("card.summary");
1629
- const variant = cardVariantFor(props.view);
1630
1543
  if (value === void 0 || draft === null) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(CardLoading, {
1631
1544
  prefix: "imsc",
1632
- variant,
1633
1545
  text: t("common.loading")
1634
1546
  });
1635
1547
  const disabled = !snapshot.writable;
@@ -1688,9 +1600,6 @@ ${extra}
1688
1600
  prefix: "imsc",
1689
1601
  title: t("card.title"),
1690
1602
  description: t("card.description"),
1691
- open,
1692
- onToggle: setOpen,
1693
- variant,
1694
1603
  statusBadge: {
1695
1604
  text: draft.providers.length > 0 ? t("card.badgeOn").replace("{n}", String(draft.providers.length)) : t("card.badgeOff"),
1696
1605
  on: draft.providers.length > 0
@@ -4171,10 +4080,8 @@ ${extra}
4171
4080
  .imsc-loading{padding:14px 16px;margin:0;font-size:13px;color:var(--dsw-alias-label-tertiary)}
4172
4081
  .imsc-groupTitle { margin: 14px 0 6px; font-size: 13px; font-weight: 600; }
4173
4082
  .imsc-presetBox {
4174
- border: 1px solid var(--dsw-alias-border-l3);
4175
- border-radius: 10px;
4176
- padding: 10px;
4177
- margin-bottom: 10px;
4083
+ border-top: 1px solid var(--dsw-alias-border-l3);
4084
+ padding: 10px 0 2px;
4178
4085
  display: grid;
4179
4086
  gap: 8px;
4180
4087
  }
@@ -4196,14 +4103,7 @@ ${extra}
4196
4103
  }
4197
4104
  .imsc-credRow { display: flex; align-items: center; gap: 8px; }
4198
4105
  .imsc-credRow .imsc-input { flex: 1; min-width: 0; }
4199
- /* 分节形态(插件页 page 视图,无边框分节):预设块改为分隔线分组,去掉第二层内边距 */
4200
- .imsc-section .imsc-presetBox {
4201
- border: 0;
4202
- border-top: 1px solid var(--dsw-alias-border-l2);
4203
- border-radius: 0;
4204
- padding: 10px 0 2px;
4205
- margin-bottom: 0;
4206
- }
4106
+
4207
4107
 
4208
4108
  /* ── 移动端(≤767px,与 ui-mobile-fit 同断点)── */
4209
4109
  @media (max-width: 767px) {
@@ -4237,7 +4137,6 @@ ${extra}
4237
4137
  .ims-btn { min-height: 40px; }
4238
4138
  .ims-btnSmall { min-height: 32px; }
4239
4139
  .imsc-grid2 { grid-template-columns: 1fr; }
4240
- .imsc-section .imsc-presetBox { padding: 10px 0 2px; }
4241
4140
  }
4242
4141
  `;
4243
4142
  /** 注入面板 + 入口 + 卡片附加样式(重复调用幂等:已存在则跳过)。 */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dsh-plus/image-studio",
3
- "version": "0.1.23",
3
+ "version": "0.1.25",
4
4
  "description": "dsh-plus service+ui plugin: 图像工作室——OpenAI Images 协议文生图/图生图,全参数开关化,双预设体系,并发生图任务与可二次编辑画廊",
5
5
  "type": "module",
6
6
  "main": "lib/index.js",
@@ -20,24 +20,24 @@
20
20
  ],
21
21
  "dependencies": {
22
22
  "https-proxy-agent": "^9.1.0",
23
- "@dsh-plus/shared": "0.1.31"
23
+ "@dsh-plus/shared": "0.1.33"
24
24
  },
25
25
  "peerDependencies": {
26
- "@deepseek-ai/cordis": "^4.0.4",
27
- "@deepseek-ai/dsh-client-ui-primitives": "^0.2.0-rc.1",
28
- "@deepseek-ai/dsh-credentials": "^0.2.0-rc.1",
29
- "@deepseek-ai/dsh-host-webserver": "^0.2.0-rc.1",
30
- "@deepseek-ai/dsh-settings": "^0.2.0-rc.1",
31
- "@deepseek-ai/schemastery": "^3.18.4"
26
+ "@deepseek-ai/cordis": "^4.0.5-alpha.1",
27
+ "@deepseek-ai/dsh-client-ui-primitives": "^0.2.1-alpha.1",
28
+ "@deepseek-ai/dsh-credentials": "^0.2.1-alpha.1",
29
+ "@deepseek-ai/dsh-host-webserver": "^0.2.1-alpha.1",
30
+ "@deepseek-ai/dsh-settings": "^0.2.1-alpha.1",
31
+ "@deepseek-ai/schemastery": "^3.18.5-alpha.1"
32
32
  },
33
33
  "devDependencies": {
34
- "@deepseek-ai/cordis": "4.0.4",
35
- "@deepseek-ai/dsh-client-ui-primitives": "0.2.0-rc.1",
36
- "@deepseek-ai/dsh-credentials": "0.2.0-rc.1",
37
- "@deepseek-ai/dsh-host-webserver": "0.2.0-rc.1",
38
- "@deepseek-ai/dsh-session": "0.2.0-rc.1",
39
- "@deepseek-ai/dsh-settings": "0.2.0-rc.1",
40
- "@deepseek-ai/schemastery": "3.18.4",
34
+ "@deepseek-ai/cordis": "4.0.5-alpha.1",
35
+ "@deepseek-ai/dsh-client-ui-primitives": "0.2.1-alpha.1",
36
+ "@deepseek-ai/dsh-credentials": "0.2.1-alpha.1",
37
+ "@deepseek-ai/dsh-host-webserver": "0.2.1-alpha.1",
38
+ "@deepseek-ai/dsh-session": "0.2.1-alpha.1",
39
+ "@deepseek-ai/dsh-settings": "0.2.1-alpha.1",
40
+ "@deepseek-ai/schemastery": "3.18.5-alpha.1",
41
41
  "@types/node": "26.4.0",
42
42
  "@types/react": "~18.3.31",
43
43
  "react": "^18.2.0"
@@ -1,6 +1,6 @@
1
1
  /**
2
- * 配置卡片(injectPluginConfigCard 三槽位,legacy key = settings 命名空间,
3
- * 0.1.6-alpha.2 起为插件页 row/bundle config,view 分发 summary/page):
2
+ * 配置卡片(injectPluginConfigCard 两槽位 = 插件页 row/bundle config,
3
+ * view 分发 summary/page):
4
4
  * 三组预设(提供商/参数/提示词)+ 高级项(并发/超时/代理/画廊上限)的
5
5
  * staged draft 编辑;提供商预设逐条附 API Key 管理(凭据端点,值不回显)。
6
6
  * JSON 字段(extraHeaders/paramSpecs)以文本镜像编辑,保存时解析 +
@@ -13,7 +13,6 @@ import {
13
13
  CardChrome,
14
14
  CardLoading,
15
15
  type CardStatusState,
16
- cardVariantFor,
17
16
  IDLE_STATUS,
18
17
  type NamespaceSettingsApi,
19
18
  type PluginConfigViewProps,
@@ -153,8 +152,6 @@ export function StudioConfigCard(props: CardProps): ReactElement | string | null
153
152
  () => scope.getSnapshot(),
154
153
  )
155
154
  const value = snapshot.value as ImageStudioConfig | undefined
156
- // 0.1.6-alpha.2 插件页 page 视图为表单落地页,默认展开;旧槽位无 view,保持折叠。
157
- const [open, setOpen] = useState(props.view === 'page')
158
155
  const [draft, setDraft] = useState<Draft | null>(null)
159
156
  const [baseline, setBaseline] = useState('')
160
157
  const [saving, setSaving] = useState(false)
@@ -176,11 +173,8 @@ export function StudioConfigCard(props: CardProps): ReactElement | string | null
176
173
  // 插件页 summary 视图只出一行简介(hooks 已全部落定,可安全提前返回)。
177
174
  if (props.view === 'summary') return t('card.summary')
178
175
 
179
- // 插件页 page 视图内嵌宿主页面容器(已带页面级内边距与标题),用无边框分节。
180
- const variant = cardVariantFor(props.view)
181
-
182
176
  if (value === undefined || draft === null) {
183
- return <CardLoading prefix="imsc" variant={variant} text={t('common.loading')} />
177
+ return <CardLoading prefix="imsc" text={t('common.loading')} />
184
178
  }
185
179
 
186
180
  const disabled = !snapshot.writable
@@ -236,9 +230,6 @@ export function StudioConfigCard(props: CardProps): ReactElement | string | null
236
230
  prefix="imsc"
237
231
  title={t('card.title')}
238
232
  description={t('card.description')}
239
- open={open}
240
- onToggle={setOpen}
241
- variant={variant}
242
233
  statusBadge={{
243
234
  text:
244
235
  draft.providers.length > 0
@@ -2,8 +2,8 @@
2
2
  * 浏览器半入口:
3
3
  * - sidebar.footer.action:侧栏底部入口按钮(与文件/终端入口 flex 等分行宽);
4
4
  * - shell.overlay:图像工作室面板(文生图/图生图/画廊 + 任务条);
5
- * - 配置卡片:injectPluginConfigCard 三槽位(三组预设 + 凭据 + 高级项;
6
- * legacy settings.plugin.item 与 0.1.6-alpha.2 插件页 row/bundle config)。
5
+ * - 配置卡片:injectPluginConfigCard 两槽位(三组预设 + 凭据 + 高级项;
6
+ * 插件页 row/bundle config)。
7
7
  * 模式与 web-files 一致:CJS factory 产物、data-plugin-css 样式
8
8
  * 约定、slot 失配静默降级;配置读写经 ctx.remote.settings 直连(远程域名可用)。
9
9
  * @module @dsh-plus/image-studio/client
@@ -561,10 +561,8 @@ export const imageStudioCss = `
561
561
  .imsc-loading{padding:14px 16px;margin:0;font-size:13px;color:var(--dsw-alias-label-tertiary)}
562
562
  .imsc-groupTitle { margin: 14px 0 6px; font-size: 13px; font-weight: 600; }
563
563
  .imsc-presetBox {
564
- border: 1px solid var(--dsw-alias-border-l3);
565
- border-radius: 10px;
566
- padding: 10px;
567
- margin-bottom: 10px;
564
+ border-top: 1px solid var(--dsw-alias-border-l3);
565
+ padding: 10px 0 2px;
568
566
  display: grid;
569
567
  gap: 8px;
570
568
  }
@@ -586,14 +584,7 @@ export const imageStudioCss = `
586
584
  }
587
585
  .imsc-credRow { display: flex; align-items: center; gap: 8px; }
588
586
  .imsc-credRow .imsc-input { flex: 1; min-width: 0; }
589
- /* 分节形态(插件页 page 视图,无边框分节):预设块改为分隔线分组,去掉第二层内边距 */
590
- .imsc-section .imsc-presetBox {
591
- border: 0;
592
- border-top: 1px solid var(--dsw-alias-border-l2);
593
- border-radius: 0;
594
- padding: 10px 0 2px;
595
- margin-bottom: 0;
596
- }
587
+
597
588
 
598
589
  /* ── 移动端(≤767px,与 ui-mobile-fit 同断点)── */
599
590
  @media (max-width: 767px) {
@@ -627,7 +618,6 @@ export const imageStudioCss = `
627
618
  .ims-btn { min-height: 40px; }
628
619
  .ims-btnSmall { min-height: 32px; }
629
620
  .imsc-grid2 { grid-template-columns: 1fr; }
630
- .imsc-section .imsc-presetBox { padding: 10px 0 2px; }
631
621
  }
632
622
  `
633
623
 
package/src/ns.ts CHANGED
@@ -2,8 +2,8 @@
2
2
  * settings 命名空间字面量(纯常量,零依赖,浏览器半可安全引入)。
3
3
  * 服务端直接以字面量注册(0.1.2-alpha.2 起 dsh-settings 对命名空间做编译期
4
4
  * 语法校验,见 config.ts);浏览器半把它作为配置卡片的注册键
5
- * (legacy settings.plugin.item keyed 槽位按「卡片编辑的 settings 命名空间」
6
- * 分发;0.1.6-alpha.2 起改挂插件页 row/bundle config,见 shared/config-slots),
5
+ * (插件页配置卡片挂在 row/bundle config 槽位上,与命名空间解耦,
6
+ * 见 shared/config-slots),
7
7
  * 同一字面量两处共用,防止漂移。
8
8
  * @module image-studio/ns
9
9
  */