@dsh-plus/image-studio 0.1.1 → 0.1.2

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.
@@ -3,6 +3,7 @@
3
3
  * 请求参数回放、衍生链源图、下载/删除/二次编辑)。
4
4
  * @module image-studio/client/panel/gallery
5
5
  */
6
+ import { Modal } from '@deepseek-ai/dsh-client-ui-primitives'
6
7
  import { IconDownload, IconRefreshOutline16, IconTrashOutline16 } from '@dsh-plus/shared/client'
7
8
  import { type ReactElement, useState } from 'react'
8
9
  import type { GalleryItem } from '../../gallery/store.ts'
@@ -52,18 +53,17 @@ function GalleryDetail(props: {
52
53
  }
53
54
 
54
55
  const paramRows = Object.entries(item.params)
56
+ // 官方 Modal 承载(嵌套 portal:层级高于工作台,遮罩/Escape 由 Modal 处理)。
55
57
  return (
56
- // biome-ignore lint/a11y/noStaticElementInteractions: 背板点击关闭是指针便利交互,键盘用户走关闭/取消按钮(同 web-terminal 既有约定)
57
- <div className="ims-detailBackdrop" role="presentation" onClick={onClose}>
58
- {/* biome-ignore lint/a11y/useKeyWithClickEvents: 阻断冒泡仅防误触背板关闭,无实际点击行为 */}
59
- <div
60
- className="ims-detail"
61
- role="dialog"
62
- aria-modal="true"
63
- aria-label={item.prompt.slice(0, 40)}
64
- onClick={(event) => event.stopPropagation()}
65
- >
66
- <div className="ims-detailHead">
58
+ <Modal
59
+ open
60
+ onClose={onClose}
61
+ title={item.prompt.slice(0, 40)}
62
+ headless
63
+ className="ims-detailModal"
64
+ >
65
+ <div className="ims-sub">
66
+ <div className="ims-subHead">
67
67
  <span className="ims-detailMeta">
68
68
  {t('gallery.detail.model')}:{item.model} · {t('gallery.detail.endpoint')}:
69
69
  {item.endpoint} · {t('gallery.detail.time')}:{fmtTime(item.createdAt)}
@@ -127,7 +127,7 @@ function GalleryDetail(props: {
127
127
  )}
128
128
  </div>
129
129
  </div>
130
- <div className="ims-detailFoot">
130
+ <div className="ims-subFoot">
131
131
  {error !== null ? (
132
132
  <p className="ims-status ims-statusError" role="alert">
133
133
  {error}
@@ -156,7 +156,7 @@ function GalleryDetail(props: {
156
156
  )}
157
157
  </div>
158
158
  </div>
159
- </div>
159
+ </Modal>
160
160
  )
161
161
  }
162
162
 
@@ -7,6 +7,7 @@
7
7
  * 响应式:桌面居中模态(≤1100px),≤767px 全屏抽屉(见 styles.ts)。
8
8
  * @module image-studio/client/panel/panel
9
9
  */
10
+ import { Modal } from '@deepseek-ai/dsh-client-ui-primitives'
10
11
  import type { NamespaceSettingsApi, Scope } from '@dsh-plus/shared/client'
11
12
  import { IconBrush, IconCloseOutline16, IconImage, IconSparkles } from '@dsh-plus/shared/client'
12
13
  import {
@@ -103,8 +104,6 @@ export function StudioPanel(props: StudioPanelProps): ReactElement | null {
103
104
  return () => clearInterval(timer)
104
105
  }, [open, providers, reloadPresets, reloadGallery, reloadTasks])
105
106
 
106
- if (!open) return null
107
-
108
107
  // wire 的 params 与 ParamEntry 结构同源(kind 宽化为 string),边界处一次性窄化。
109
108
  const catalog = (providers?.params ?? []) as unknown as readonly ParamEntry[]
110
109
  const protocols = providers?.protocols ?? []
@@ -115,17 +114,17 @@ export function StudioPanel(props: StudioPanelProps): ReactElement | null {
115
114
  { key: 'gallery', label: t('tab.gallery'), icon: <IconImage size={15} /> },
116
115
  ]
117
116
 
117
+ // 官方 Modal 承载:portal 到 body(z-index 1000,移动端层叠/开关与外壳一致),
118
+ // 遮罩点击与 Escape 关闭由 Modal 处理;headless 模式自绘头部标签条。
118
119
  return (
119
- // biome-ignore lint/a11y/noStaticElementInteractions: 背板点击关闭是指针便利交互,键盘用户走关闭/取消按钮(同 web-terminal 既有约定)
120
- <div className="ims-backdrop" role="presentation" onClick={() => studio.setOpen(false)}>
121
- {/* biome-ignore lint/a11y/useKeyWithClickEvents: 阻断冒泡仅防误触背板关闭,无实际点击行为 */}
122
- <div
123
- className="ims-panel"
124
- role="dialog"
125
- aria-modal="true"
126
- aria-label={t('panel.title')}
127
- onClick={(event) => event.stopPropagation()}
128
- >
120
+ <Modal
121
+ open={open}
122
+ onClose={() => studio.setOpen(false)}
123
+ title={t('panel.title')}
124
+ headless
125
+ className="ims-modal"
126
+ >
127
+ <div className="ims-panel">
129
128
  <header className="ims-head">
130
129
  <div className="ims-tabs" role="tablist" aria-label={t('panel.title')}>
131
130
  {tabs.map((item) => (
@@ -215,6 +214,6 @@ export function StudioPanel(props: StudioPanelProps): ReactElement | null {
215
214
  }}
216
215
  />
217
216
  </div>
218
- </div>
217
+ </Modal>
219
218
  )
220
219
  }
@@ -3,6 +3,7 @@
3
3
  * 扁平化全部画廊条目的图片,倒序排列;底部确认条显示已选数量。
4
4
  * @module image-studio/client/panel/picker
5
5
  */
6
+ import { Modal } from '@deepseek-ai/dsh-client-ui-primitives'
6
7
  import { type ReactElement, useState } from 'react'
7
8
  import type { GalleryItem } from '../../gallery/store.ts'
8
9
  import { imageUrl } from '../api.ts'
@@ -56,19 +57,12 @@ export function ImagePicker(props: ImagePickerProps): ReactElement {
56
57
  setSelected((current) => (current.includes(imageId) ? [] : [imageId]))
57
58
  }
58
59
 
60
+ // 官方 Modal 承载(嵌套 portal:层级高于工作台,遮罩/Escape 由 Modal 处理)。
59
61
  return (
60
- // biome-ignore lint/a11y/noStaticElementInteractions: 背板点击关闭是指针便利交互,键盘用户走关闭/取消按钮(同 web-terminal 既有约定)
61
- <div className="ims-pickerBackdrop" role="presentation" onClick={onClose}>
62
- {/* biome-ignore lint/a11y/useKeyWithClickEvents: 阻断冒泡仅防误触背板关闭,无实际点击行为 */}
63
- <div
64
- className="ims-picker"
65
- role="dialog"
66
- aria-modal="true"
67
- aria-label={title}
68
- onClick={(event) => event.stopPropagation()}
69
- >
70
- <div className="ims-pickerHead">
71
- <h3 className="ims-pickerTitle">{title}</h3>
62
+ <Modal open onClose={onClose} title={title} headless className="ims-pickerModal">
63
+ <div className="ims-sub">
64
+ <div className="ims-subHead">
65
+ <h3 className="ims-subTitle">{title}</h3>
72
66
  <button type="button" className="ims-btn ims-btnGhost" onClick={onClose}>
73
67
  {t('common.close')}
74
68
  </button>
@@ -98,7 +92,7 @@ export function ImagePicker(props: ImagePickerProps): ReactElement {
98
92
  })}
99
93
  </div>
100
94
  )}
101
- <div className="ims-pickerFoot">
95
+ <div className="ims-subFoot">
102
96
  <button
103
97
  type="button"
104
98
  className="ims-btn ims-btnPrimary"
@@ -112,6 +106,6 @@ export function ImagePicker(props: ImagePickerProps): ReactElement {
112
106
  </button>
113
107
  </div>
114
108
  </div>
115
- </div>
109
+ </Modal>
116
110
  )
117
111
  }