@dungsil/dsh-plugin-ui-model-picker 0.2.1 → 0.2.3
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/dist/client.js +91 -86
- package/package.json +4 -5
package/dist/client.js
CHANGED
|
@@ -4,29 +4,79 @@ let react = require("react");
|
|
|
4
4
|
let react_dom = require("react-dom");
|
|
5
5
|
let _deepseek_ai_dsh_client_ui_primitives = require("@deepseek-ai/dsh-client-ui-primitives");
|
|
6
6
|
let react_jsx_runtime = require("react/jsx-runtime");
|
|
7
|
+
// ../../tools/ui/src/client.ts
|
|
8
|
+
function useLocaleSnapshot(locale) {
|
|
9
|
+
const subscribe = (0, react.useCallback)((listener) => locale.subscribe(listener), [locale]);
|
|
10
|
+
const getSnapshot = (0, react.useCallback)(() => locale.getSnapshot(), [locale]);
|
|
11
|
+
return (0, react.useSyncExternalStore)(subscribe, getSnapshot);
|
|
12
|
+
}
|
|
13
|
+
/** Each effect owns its sheet, even when another plugin installs the same defaults. */
|
|
14
|
+
function installStyles(css) {
|
|
15
|
+
const style = document.createElement("style");
|
|
16
|
+
style.textContent = css;
|
|
17
|
+
document.head.append(style);
|
|
18
|
+
return () => style.remove();
|
|
19
|
+
}
|
|
20
|
+
// ../../tools/ui/src/icons/rotate-ccw.svg
|
|
21
|
+
var rotate_ccw_default = "<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\">\n <path d=\"M5 7a9 9 0 1 1-1 9M5 3v4h4\"/>\n</svg>\n";
|
|
22
|
+
// ../../tools/ui/src/icons.ts
|
|
23
|
+
function IconResetOutlineRegular() {
|
|
24
|
+
return (0, react.createElement)("span", {
|
|
25
|
+
style: { display: "inline-flex" },
|
|
26
|
+
"aria-hidden": "true",
|
|
27
|
+
dangerouslySetInnerHTML: { __html: rotate_ccw_default }
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
// ../../tools/ui/src/composer.tsx
|
|
31
|
+
const composerStyles = `
|
|
32
|
+
:where(.dsh-plugin-composer-trigger) { display: flex; align-items: center; gap: 4px; min-width: 0; height: 28px; padding: 0 4px 0 8px; border: 0; border-radius: var(--dsw-radius-sm); background: transparent; color: var(--dsw-alias-label-secondary); font: inherit; font-size: 13px; line-height: 20px; cursor: pointer; }
|
|
33
|
+
:where(.dsh-plugin-composer-trigger):disabled { color: var(--dsw-alias-label-dimmed); cursor: default; }
|
|
34
|
+
.dsh-plugin-composer-icon, .dsh-plugin-composer-chevron { display: inline-flex; flex: none; }
|
|
35
|
+
.dsh-plugin-composer-label, .dsh-plugin-composer-detail { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
36
|
+
.dsh-plugin-composer-chevron, .dsh-plugin-composer-detail { color: var(--dsw-alias-label-caption); }
|
|
37
|
+
.dsh-plugin-composer-trigger[aria-expanded=true] .dsh-plugin-composer-chevron { transform: rotate(180deg); }
|
|
38
|
+
`;
|
|
39
|
+
const ComposerTrigger = /* @__PURE__ */ (0, react.forwardRef)(function ComposerTrigger({ className = "", icon, label, detail, ...props }, ref) {
|
|
40
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
41
|
+
...props,
|
|
42
|
+
ref,
|
|
43
|
+
type: "button",
|
|
44
|
+
className: `dsh-plugin-composer-trigger ${className}`,
|
|
45
|
+
children: [
|
|
46
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
47
|
+
className: "dsh-plugin-composer-icon",
|
|
48
|
+
"aria-hidden": "true",
|
|
49
|
+
children: icon
|
|
50
|
+
}),
|
|
51
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
52
|
+
className: "dsh-plugin-composer-label",
|
|
53
|
+
children: label
|
|
54
|
+
}),
|
|
55
|
+
detail && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
56
|
+
className: "dsh-plugin-composer-detail",
|
|
57
|
+
children: detail
|
|
58
|
+
}),
|
|
59
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
60
|
+
className: "dsh-plugin-composer-chevron",
|
|
61
|
+
"aria-hidden": "true",
|
|
62
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconChevronDownOutlineRegular, {})
|
|
63
|
+
})
|
|
64
|
+
]
|
|
65
|
+
});
|
|
66
|
+
});
|
|
7
67
|
// src/styles.ts
|
|
8
|
-
const styles =
|
|
68
|
+
const styles = `${composerStyles}
|
|
9
69
|
.dsh-codex-picker { display: flex; align-items: center; min-width: 0; }
|
|
10
|
-
.dsh-codex-trigger {
|
|
70
|
+
.dsh-codex-trigger { max-width: min(360px, 45cqw); font-weight: 400; outline: none; }
|
|
11
71
|
.dsh-codex-trigger:hover:not(:disabled) { background: var(--dsw-alias-interactive-bg-hover); }
|
|
12
72
|
.dsh-codex-trigger:focus-visible:not([data-dsh-automatic-focus]) { box-shadow: 0 0 0 2px var(--dsw-focus-ring-color, var(--dsw-alias-state-business-primary)); }
|
|
13
|
-
.dsh-codex-trigger
|
|
14
|
-
.dsh-codex-trigger
|
|
15
|
-
.dsh-codex-
|
|
16
|
-
.dsh-codex-trigger
|
|
17
|
-
.dsh-codex-name, .dsh-codex-effort { display: var(--dsh-composer-model-text-display, block); min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
18
|
-
.dsh-codex-effort { color: var(--dsw-alias-label-caption); flex-shrink: 1000; }
|
|
73
|
+
.dsh-codex-trigger .dsh-plugin-composer-icon { display: var(--dsh-composer-model-icon-display, none); }
|
|
74
|
+
.dsh-codex-trigger .dsh-plugin-composer-chevron { transition: transform .12s; }
|
|
75
|
+
.dsh-codex-trigger .dsh-plugin-composer-label, .dsh-codex-trigger .dsh-plugin-composer-detail { display: var(--dsh-composer-model-text-display, block); }
|
|
76
|
+
.dsh-codex-trigger .dsh-plugin-composer-detail { flex-shrink: 1000; }
|
|
19
77
|
.dsh-codex-popover { position: fixed; z-index: 1100; display: flex; flex-direction: column; inset: auto; margin: 0; box-sizing: border-box; width: 256px; max-width: calc(100vw - 32px); max-height: min(360px, calc(100dvh - 96px)); overflow: hidden; padding: 4px; border: 0; --dsw-elevation-stroke-color: var(--dsw-alias-border-l1); --dsh-scrollbar-thumb: var(--dsw-alias-scrollbar-bg-l2); --dsh-scrollbar-thumb-hover: var(--dsw-alias-scrollbar-hover-l2); background: transparent; color: var(--dsw-alias-label-primary); box-shadow: var(--dsw-elevation-prominent); font: 13px/20px var(--dsw-font-family, system-ui); }
|
|
20
|
-
/* rc.5 has no MenuSurface phase API. Match the newer shared menu fades without
|
|
21
|
-
animating the container: container opacity would change its backdrop blur.
|
|
22
|
-
Old hosts forward phase to the div; newer hosts consume it for their own CSS. */
|
|
23
|
-
.dsh-codex-popover[phase=enter] > * { animation: dsh-codex-menu-in 40ms ease-out; }
|
|
24
|
-
.dsh-codex-popover[phase=dismiss] > * { animation: dsh-codex-menu-out 80ms ease-in both; }
|
|
25
|
-
@keyframes dsh-codex-menu-in { from { opacity: 0; } to { opacity: 1; } }
|
|
26
|
-
@keyframes dsh-codex-menu-out { from { opacity: 1; } to { opacity: 0; } }
|
|
27
78
|
@media (prefers-reduced-motion: reduce) {
|
|
28
|
-
.dsh-codex-
|
|
29
|
-
.dsh-codex-chevron { transition: none; }
|
|
79
|
+
.dsh-codex-trigger .dsh-plugin-composer-chevron { transition: none; }
|
|
30
80
|
}
|
|
31
81
|
.dsh-codex-popover > :not([role=radiogroup]) { flex-shrink: 0; }
|
|
32
82
|
.dsh-codex-popover [role=radiogroup] { min-height: 0; overflow-y: auto; }
|
|
@@ -38,6 +88,7 @@ const styles = `
|
|
|
38
88
|
.dsh-codex-model > span { display: block; color: var(--dsw-alias-label-tertiary, #777); font-size: 12px; line-height: 17px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
39
89
|
.dsh-codex-model:hover, .dsh-codex-reset:hover, .dsh-codex-back:hover { background: var(--dsw-alias-interactive-bg-hover, #f2f2f2); }
|
|
40
90
|
.dsh-codex-reset { display: grid; place-items: center; width: 24px; height: 24px; color: var(--dsw-alias-label-tertiary, #999); }
|
|
91
|
+
.dsh-codex-reset svg { width: 16px; height: 16px; }
|
|
41
92
|
.dsh-codex-back { padding: 4px 8px; color: var(--dsw-alias-label-tertiary, #777); }
|
|
42
93
|
.dsh-codex-popover h2, .dsh-codex-provider { margin: 0; padding: 6px 10px; font-size: 12px; font-weight: 400; color: var(--dsw-alias-label-tertiary, #777); }
|
|
43
94
|
.dsh-codex-provider { font-size: 11px; padding-top: 10px; }
|
|
@@ -117,11 +168,12 @@ const copy = {
|
|
|
117
168
|
};
|
|
118
169
|
function apply(ctx) {
|
|
119
170
|
function Picker({ locked, directory }) {
|
|
120
|
-
const
|
|
121
|
-
const
|
|
171
|
+
const subscribe = (0, react.useCallback)((listener) => directory.store.subscribe(listener), [directory]);
|
|
172
|
+
const getSnapshot = (0, react.useCallback)(() => directory.store.getSnapshot(), [directory]);
|
|
173
|
+
const state = (0, react.useSyncExternalStore)(subscribe, getSnapshot);
|
|
174
|
+
const { active: locale } = useLocaleSnapshot(ctx.locale);
|
|
122
175
|
const text = copy[locale.startsWith("ko") ? "ko" : locale.startsWith("zh") ? "zh" : "en"];
|
|
123
|
-
const [
|
|
124
|
-
const [exiting, setExiting] = (0, react.useState)(false);
|
|
176
|
+
const [requestedPanel, setPanel] = (0, react.useState)(null);
|
|
125
177
|
const [draft, setDraft] = (0, react.useState)(0);
|
|
126
178
|
const [failed, setFailed] = (0, react.useState)(false);
|
|
127
179
|
const trigger = (0, react.useRef)(null);
|
|
@@ -137,9 +189,10 @@ function apply(ctx) {
|
|
|
137
189
|
id: void 0,
|
|
138
190
|
name: text.default
|
|
139
191
|
}] : [], ...reasoning.efforts] : [];
|
|
192
|
+
const panel = requestedPanel === "effort" && !efforts.length ? "model" : requestedPanel;
|
|
140
193
|
const effective = current?.reasoningEffort ?? reasoning?.defaultEffort;
|
|
141
194
|
const effortIndex = efforts.findIndex((item) => item.id === effective);
|
|
142
|
-
const effortLabel = efforts[effortIndex]?.name ?? state.retainedEffort;
|
|
195
|
+
const effortLabel = efforts.length ? efforts[effortIndex]?.name ?? state.retainedEffort : void 0;
|
|
143
196
|
const busy = state.status === "selecting";
|
|
144
197
|
const disabled = locked || busy;
|
|
145
198
|
(0, react.useEffect)(() => {
|
|
@@ -150,27 +203,10 @@ function apply(ctx) {
|
|
|
150
203
|
};
|
|
151
204
|
}, [directory]);
|
|
152
205
|
const close = () => {
|
|
153
|
-
|
|
206
|
+
setPanel(null);
|
|
154
207
|
if (trigger.current) (0, _deepseek_ai_dsh_client_ui_primitives.focusWithoutRing)(trigger.current);
|
|
155
208
|
};
|
|
156
|
-
(0, _deepseek_ai_dsh_client_ui_primitives.useDismissOnOutsidePointer)(anchor, panel !== null
|
|
157
|
-
(0, react.useLayoutEffect)(() => {
|
|
158
|
-
if (!exiting || !popup.current) return;
|
|
159
|
-
const element = popup.current;
|
|
160
|
-
element.inert = true;
|
|
161
|
-
let cancelled = false;
|
|
162
|
-
const animations = element.getAnimations({ subtree: true }).filter((animation) => {
|
|
163
|
-
const name = animation.animationName;
|
|
164
|
-
return name?.includes("dsh-context-menu-out") || name === "dsh-codex-menu-out";
|
|
165
|
-
});
|
|
166
|
-
Promise.all(animations.map((animation) => animation.finished.catch(() => {}))).then(() => {
|
|
167
|
-
if (!cancelled) setPanel(null);
|
|
168
|
-
});
|
|
169
|
-
return () => {
|
|
170
|
-
cancelled = true;
|
|
171
|
-
element.inert = false;
|
|
172
|
-
};
|
|
173
|
-
}, [exiting]);
|
|
209
|
+
(0, _deepseek_ai_dsh_client_ui_primitives.useDismissOnOutsidePointer)(anchor, panel !== null, () => setPanel(null), popup);
|
|
174
210
|
(0, react.useLayoutEffect)(() => {
|
|
175
211
|
if (!panel || !popup.current || !anchor.current) return;
|
|
176
212
|
const element = popup.current;
|
|
@@ -216,10 +252,10 @@ function apply(ctx) {
|
|
|
216
252
|
};
|
|
217
253
|
}, [panel]);
|
|
218
254
|
(0, react.useEffect)(() => {
|
|
219
|
-
if (locked)
|
|
255
|
+
if (locked) setPanel(null);
|
|
220
256
|
}, [locked]);
|
|
221
257
|
(0, react.useEffect)(() => {
|
|
222
|
-
|
|
258
|
+
setPanel(null);
|
|
223
259
|
}, [
|
|
224
260
|
current?.provider,
|
|
225
261
|
current?.model,
|
|
@@ -242,11 +278,10 @@ function apply(ctx) {
|
|
|
242
278
|
};
|
|
243
279
|
const show = (button) => {
|
|
244
280
|
trigger.current = button;
|
|
245
|
-
if (panel
|
|
281
|
+
if (panel) {
|
|
246
282
|
close();
|
|
247
283
|
return;
|
|
248
284
|
}
|
|
249
|
-
setExiting(false);
|
|
250
285
|
setDraft(Math.max(0, effortIndex));
|
|
251
286
|
setFailed(false);
|
|
252
287
|
setPanel("effort");
|
|
@@ -265,43 +300,27 @@ function apply(ctx) {
|
|
|
265
300
|
className: "dsh-codex-picker",
|
|
266
301
|
ref: anchor,
|
|
267
302
|
"aria-busy": busy,
|
|
268
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.
|
|
269
|
-
type: "button",
|
|
303
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ComposerTrigger, {
|
|
270
304
|
className: "dsh-codex-trigger",
|
|
305
|
+
icon: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconDataOutlineRegular, { size: 16 }),
|
|
306
|
+
label: model?.name ?? current?.model ?? text.model,
|
|
307
|
+
detail: effortLabel,
|
|
271
308
|
disabled,
|
|
272
|
-
"aria-label": `${text.choose}: ${model?.name ?? current?.model ?? text.model}${effortLabel ? `, ${effortLabel}` : ""}`,
|
|
309
|
+
"aria-label": `${efforts.length ? text.choose : text.model}: ${model?.name ?? current?.model ?? text.model}${effortLabel ? `, ${effortLabel}` : ""}`,
|
|
273
310
|
title: `${model?.name ?? current?.model ?? text.model}${effortLabel ? ` ${effortLabel}` : ""}`,
|
|
274
311
|
"aria-haspopup": "dialog",
|
|
275
|
-
"aria-expanded": panel !== null
|
|
276
|
-
"aria-controls": panel
|
|
277
|
-
onClick: (event) => show(event.currentTarget)
|
|
278
|
-
children: [
|
|
279
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconDataOutlineRegular, {
|
|
280
|
-
className: "dsh-codex-trigger-icon",
|
|
281
|
-
size: 16
|
|
282
|
-
}),
|
|
283
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
284
|
-
className: "dsh-codex-name",
|
|
285
|
-
children: model?.name ?? current?.model ?? text.model
|
|
286
|
-
}),
|
|
287
|
-
effortLabel && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
288
|
-
className: "dsh-codex-effort",
|
|
289
|
-
children: effortLabel
|
|
290
|
-
}),
|
|
291
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconChevronDownOutlineRegular, { className: "dsh-codex-chevron" })
|
|
292
|
-
]
|
|
312
|
+
"aria-expanded": panel !== null,
|
|
313
|
+
"aria-controls": panel ? id : void 0,
|
|
314
|
+
onClick: (event) => show(event.currentTarget)
|
|
293
315
|
})
|
|
294
316
|
}), panel && (0, react_dom.createPortal)(/* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_deepseek_ai_dsh_client_ui_primitives.MenuSurface, {
|
|
295
317
|
id,
|
|
296
318
|
ref: popup,
|
|
297
319
|
role: "dialog",
|
|
298
|
-
"aria-hidden": exiting || void 0,
|
|
299
|
-
"data-picker-phase": exiting ? "dismiss" : "enter",
|
|
300
|
-
phase: exiting ? "dismiss" : "enter",
|
|
301
320
|
"aria-label": panel === "model" ? text.model : text.effort,
|
|
302
321
|
className: "dsh-codex-popover",
|
|
303
322
|
children: [
|
|
304
|
-
panel === "model" ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
323
|
+
panel === "model" ? efforts.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
305
324
|
type: "button",
|
|
306
325
|
className: "dsh-codex-back",
|
|
307
326
|
onClick: () => setPanel("effort"),
|
|
@@ -335,16 +354,7 @@ function apply(ctx) {
|
|
|
335
354
|
model: current.model
|
|
336
355
|
});
|
|
337
356
|
},
|
|
338
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(
|
|
339
|
-
width: "16",
|
|
340
|
-
height: "16",
|
|
341
|
-
viewBox: "0 0 16 16",
|
|
342
|
-
fill: "none",
|
|
343
|
-
stroke: "currentColor",
|
|
344
|
-
strokeWidth: "1.2",
|
|
345
|
-
"aria-hidden": "true",
|
|
346
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", { d: "M3 4a5.5 5.5 0 1 1-1 6M3 1v3h3" })
|
|
347
|
-
})
|
|
357
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(IconResetOutlineRegular, {})
|
|
348
358
|
})]
|
|
349
359
|
}),
|
|
350
360
|
state.status === "loading" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
@@ -462,12 +472,7 @@ function apply(ctx) {
|
|
|
462
472
|
locked: props.locked,
|
|
463
473
|
directory: ctx.modelDirectories.directoryFor(props.sessionId)
|
|
464
474
|
}, props.sessionId) : null));
|
|
465
|
-
ctx.effect(() =>
|
|
466
|
-
const style = document.createElement("style");
|
|
467
|
-
style.textContent = styles;
|
|
468
|
-
document.head.append(style);
|
|
469
|
-
return () => style.remove();
|
|
470
|
-
}, "ui-model-picker: styles");
|
|
475
|
+
ctx.effect(() => installStyles(styles), "ui-model-picker: styles");
|
|
471
476
|
}
|
|
472
477
|
exports.apply = apply;
|
|
473
478
|
exports.inject = inject;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dungsil/dsh-plugin-ui-model-picker",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.3",
|
|
4
4
|
"description": "Model and reasoning effort picker for the DeepSeek Harness composer.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -32,14 +32,14 @@
|
|
|
32
32
|
"@deepseek-ai/dsh-client-store": "0.2.1-rc.5",
|
|
33
33
|
"@deepseek-ai/dsh-client-ui-conversation": "0.2.1-rc.5",
|
|
34
34
|
"@deepseek-ai/dsh-client-ui-model-selection": "0.2.1-rc.5",
|
|
35
|
-
"@deepseek-ai/dsh-client-ui-primitives": "0.2.1-rc.5",
|
|
36
35
|
"@deepseek-ai/dsh-client-ui-renderer": "0.2.1-rc.5",
|
|
37
36
|
"@deepseek-ai/dsh-client-ui-session": "0.2.1-rc.5",
|
|
38
37
|
"@deepseek-ai/dsh-client-ui-slots": "0.2.1-rc.5",
|
|
39
38
|
"@dungsil/dsh-tsconfig": "0.0.0",
|
|
39
|
+
"@dungsil/dsh-tsdown": "0.0.0",
|
|
40
|
+
"@dungsil/dsh-ui": "0.0.0",
|
|
40
41
|
"@types/react": "18.3.31",
|
|
41
42
|
"@types/react-dom": "18.3.7",
|
|
42
|
-
"happy-dom": "21.0.4",
|
|
43
43
|
"react": "18.3.1",
|
|
44
44
|
"react-dom": "18.3.1",
|
|
45
45
|
"tsdown": "0.23.4"
|
|
@@ -88,7 +88,6 @@
|
|
|
88
88
|
},
|
|
89
89
|
"scripts": {
|
|
90
90
|
"build": "tsdown",
|
|
91
|
-
"typecheck": "tsc --noEmit"
|
|
92
|
-
"test": "node --test test/*.test.mjs"
|
|
91
|
+
"typecheck": "tsc --noEmit"
|
|
93
92
|
}
|
|
94
93
|
}
|