@dungsil/dsh-plugin-ui-model-picker 0.2.0 → 0.2.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.
@@ -1,4 +1,6 @@
1
1
  Chevron SVG artwork from @deepseek-ai/dsh-client-ui-primitives 0.2.1-rc.5
2
+ Menu transition compatibility styles adapted from
3
+ @deepseek-ai/dsh-client-ui-primitives 0.2.2-alpha.3 (MenuSurface.module.css)
2
4
 
3
5
  MIT License
4
6
 
Binary file
package/dist/client.js CHANGED
@@ -2,59 +2,104 @@ window.__ModuleLoader__.load({ id: "@dungsil/dsh-plugin-ui-model-picker", factor
2
2
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
3
  let react = require("react");
4
4
  let react_dom = require("react-dom");
5
+ let _deepseek_ai_dsh_client_ui_primitives = require("@deepseek-ai/dsh-client-ui-primitives");
5
6
  let react_jsx_runtime = require("react/jsx-runtime");
6
- // src/chevron.tsx
7
- const paths = {
8
- down: "M4 6L7.29289 9.29289C7.68342 9.68342 8.31658 9.68342 8.70711 9.29289L12 6",
9
- left: "M10 4L6.70711 7.29289C6.31658 7.68342 6.31658 8.31658 6.70711 8.70711L10 12",
10
- right: "M6 12L9.29289 8.70711C9.68342 8.31658 9.68342 7.68342 9.29289 7.29289L6 4"
11
- };
12
- function Chevron({ direction }) {
13
- return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("svg", {
14
- className: "dsh-codex-chevron",
15
- width: "14",
16
- height: "14",
17
- viewBox: "0 0 16 16",
18
- fill: "none",
19
- strokeWidth: "1",
20
- xmlns: "http://www.w3.org/2000/svg",
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" },
21
26
  "aria-hidden": "true",
22
- focusable: "false",
23
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", {
24
- d: paths[direction],
25
- stroke: "currentColor"
26
- })
27
+ dangerouslySetInnerHTML: { __html: rotate_ccw_default }
27
28
  });
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 = (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
+ });
29
67
  // src/styles.ts
30
- const styles = `
31
- .dsh-codex-picker { display: flex; align-items: center; min-width: 0; border-radius: 16px; color: var(--dsw-alias-label-primary, #252525); font: 13px/20px system-ui, sans-serif; }
32
- .dsh-codex-picker button { border: 0; background: transparent; color: inherit; font: inherit; cursor: pointer; height: 28px; padding: 0 6px; border-radius: 14px; min-width: 0; }
33
- .dsh-codex-picker:hover { background: var(--dsw-alias-interactive-bg-hover, #8881); }
34
- .dsh-codex-picker .dsh-codex-trigger { display: flex; gap: 5px; align-items: center; }
35
- .dsh-codex-chevron { display: inline-block; flex: 0 0 14px; vertical-align: middle; }
36
- .dsh-codex-name { display: var(--dsh-composer-model-text-display, block); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: min(220px, 32vw); }
37
- .dsh-codex-effort { color: var(--dsw-alias-label-tertiary, #777); }
38
- .dsh-codex-popover { position: fixed; inset: auto; margin: 0; box-sizing: border-box; width: 256px; max-width: calc(100vw - 16px); max-height: calc(100dvh - 16px); overflow-y: auto; padding: 8px 10px; border: 1px solid var(--dsw-alias-border-l1, #e8e8e8); border-radius: 16px; background: var(--dsw-alias-bg-layer-1, #fff); color: var(--dsw-alias-label-primary, #252525); box-shadow: 0 5px 12px #0000000d, 0 2px 4px #00000005; font: 13px/20px system-ui, sans-serif; }
39
- .dsh-codex-popover::backdrop { background: transparent; }
68
+ const styles = `${composerStyles}
69
+ .dsh-codex-picker { display: flex; align-items: center; min-width: 0; }
70
+ .dsh-codex-trigger { max-width: min(360px, 45cqw); font-weight: 400; outline: none; }
71
+ .dsh-codex-trigger:hover:not(:disabled) { background: var(--dsw-alias-interactive-bg-hover); }
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)); }
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; }
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); }
78
+ @media (prefers-reduced-motion: reduce) {
79
+ .dsh-codex-trigger .dsh-plugin-composer-chevron { transition: none; }
80
+ }
81
+ .dsh-codex-popover > :not([role=radiogroup]) { flex-shrink: 0; }
82
+ .dsh-codex-popover [role=radiogroup] { min-height: 0; overflow-y: auto; }
40
83
  .dsh-codex-header { display: grid; grid-template-columns: 24px minmax(0, 1fr) 24px; align-items: start; gap: 4px; }
41
- .dsh-codex-model, .dsh-codex-reset, .dsh-codex-back { border: 0; background: transparent; color: inherit; font: inherit; cursor: pointer; border-radius: 6px; }
84
+ .dsh-codex-model, .dsh-codex-reset, .dsh-codex-back { border: 0; background: transparent; color: inherit; font: inherit; cursor: pointer; border-radius: var(--dsw-radius-md); }
85
+ .dsh-codex-popover svg { flex: none; vertical-align: middle; }
42
86
  .dsh-codex-model { grid-column: 2; justify-self: center; min-width: 0; max-width: 100%; padding: 2px 10px 3px; text-align: center; }
43
- .dsh-codex-model strong { display: block; color: #3983ff; font-size: 14px; line-height: 20px; font-weight: 600; }
87
+ .dsh-codex-model strong { display: block; color: var(--dsw-alias-state-business-primary); font-size: 14px; line-height: 20px; font-weight: 600; }
44
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; }
45
89
  .dsh-codex-model:hover, .dsh-codex-reset:hover, .dsh-codex-back:hover { background: var(--dsw-alias-interactive-bg-hover, #f2f2f2); }
46
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; }
47
92
  .dsh-codex-back { padding: 4px 8px; color: var(--dsw-alias-label-tertiary, #777); }
48
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); }
49
94
  .dsh-codex-provider { font-size: 11px; padding-top: 10px; }
50
- .dsh-codex-option { display: flex; align-items: center; justify-content: space-between; gap: 12px; width: 100%; min-height: 30px; padding: 5px 10px; border: 0; border-radius: 9px; color: inherit; background: transparent; text-align: left; font: inherit; cursor: pointer; }
51
- .dsh-codex-option:hover, .dsh-codex-option[aria-checked=true] { background: var(--dsw-alias-interactive-bg-hover, #f4f4f4); }
95
+ .dsh-codex-option { box-sizing: border-box; display: flex; align-items: center; justify-content: space-between; gap: 6px; width: 100%; min-height: 34px; padding: 5px 7px; border: 0; border-radius: var(--dsw-radius-md); color: inherit; background: transparent; text-align: left; font: inherit; cursor: pointer; }
96
+ .dsh-codex-option:hover:not(:disabled), .dsh-codex-option:focus-visible { background: var(--dsw-alias-interactive-bg-hover); }
52
97
  .dsh-codex-option span:first-child { min-width: 0; overflow-wrap: anywhere; }
53
98
  .dsh-codex-option small { display: block; color: var(--dsw-alias-label-tertiary, #777); font-size: 11px; }
54
- .dsh-codex-option .dsh-codex-check { flex: 0 0 14px; }
99
+ .dsh-codex-option .dsh-codex-check { display: grid; place-items: center; flex: 0 0 14px; }
55
100
  .dsh-codex-slider { padding: 10px 2px 3px; }
56
101
  .dsh-codex-rail { position: relative; height: 28px; }
57
- .dsh-codex-track { position: absolute; inset: 3px 0; border-radius: 20px; background: linear-gradient(to right, #3983ff var(--dsh-codex-progress), var(--dsw-alias-interactive-bg-hover, #e8e8e8) var(--dsh-codex-progress)); display: flex; align-items: center; justify-content: space-between; padding: 0 12px; }
102
+ .dsh-codex-track { position: absolute; inset: 3px 0; border-radius: 20px; background: linear-gradient(to right, var(--dsw-alias-state-business-primary) var(--dsh-codex-progress), var(--dsw-alias-interactive-bg-hover) var(--dsh-codex-progress)); display: flex; align-items: center; justify-content: space-between; padding: 0 12px; }
58
103
  .dsh-codex-track span { width: 4px; height: 4px; border-radius: 50%; background: #b8b8b8; }
59
104
  .dsh-codex-track span[data-filled=true] { background: #ffffff80; }
60
105
  .dsh-codex-slider input { appearance: none; -webkit-appearance: none; position: relative; display: block; width: 100%; height: 28px; padding: 0; margin: 0; background: transparent; cursor: pointer; }
@@ -64,8 +109,8 @@ const styles = `
64
109
  .dsh-codex-slider input::-moz-range-thumb { width: 26px; height: 26px; border: 1px solid #0000000a; border-radius: 50%; background: #fff; box-shadow: 0 1px 3px #0002; }
65
110
  .dsh-codex-notice { padding: 6px 10px; margin: 0; font-size: 12px; overflow-wrap: anywhere; }
66
111
  .dsh-codex-popover [role=alert] { color: var(--dsw-alias-state-error-primary, #b54424); }
67
- .dsh-codex-picker button:focus-visible, .dsh-codex-popover :focus-visible { outline: 2px solid var(--dsw-focus-ring-color, #3186ce); outline-offset: 2px; }
68
- .dsh-codex-picker button:disabled, .dsh-codex-popover :disabled { opacity: .5; cursor: default; }
112
+ .dsh-codex-popover :focus-visible { outline: 2px solid var(--dsw-focus-ring-color, var(--dsw-alias-state-business-primary)); outline-offset: -2px; }
113
+ .dsh-codex-popover :disabled { color: var(--dsw-alias-label-dimmed); cursor: default; }
69
114
  `;
70
115
  // src/client.tsx
71
116
  const name = "dungsil-ui-model-picker";
@@ -123,8 +168,10 @@ const copy = {
123
168
  };
124
169
  function apply(ctx) {
125
170
  function Picker({ locked, directory }) {
126
- const state = (0, react.useSyncExternalStore)(directory.store.subscribe, directory.store.getSnapshot);
127
- const locale = (0, react.useSyncExternalStore)((fn) => ctx.locale.subscribe(fn), () => ctx.locale.getSnapshot().active);
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);
128
175
  const text = copy[locale.startsWith("ko") ? "ko" : locale.startsWith("zh") ? "zh" : "en"];
129
176
  const [panel, setPanel] = (0, react.useState)(null);
130
177
  const [draft, setDraft] = (0, react.useState)(0);
@@ -156,13 +203,12 @@ function apply(ctx) {
156
203
  }, [directory]);
157
204
  const close = () => {
158
205
  setPanel(null);
159
- trigger.current?.focus();
206
+ if (trigger.current) (0, _deepseek_ai_dsh_client_ui_primitives.focusWithoutRing)(trigger.current);
160
207
  };
161
- (0, react.useEffect)(() => {
208
+ (0, _deepseek_ai_dsh_client_ui_primitives.useDismissOnOutsidePointer)(anchor, panel !== null, () => setPanel(null), popup);
209
+ (0, react.useLayoutEffect)(() => {
162
210
  if (!panel || !popup.current || !anchor.current) return;
163
211
  const element = popup.current;
164
- element.setAttribute("popover", "auto");
165
- element.showPopover();
166
212
  const position = () => {
167
213
  const box = anchor.current.getBoundingClientRect();
168
214
  element.style.left = `${Math.max(8, Math.min(box.right - element.offsetWidth, window.innerWidth - element.offsetWidth - 8))}px`;
@@ -172,13 +218,9 @@ function apply(ctx) {
172
218
  position();
173
219
  const observer = new ResizeObserver(position);
174
220
  observer.observe(element);
175
- const toggle = (event) => {
176
- if (event.newState === "closed") setPanel(null);
177
- };
178
221
  const scroll = (event) => {
179
222
  if (!element.contains(event.target)) close();
180
223
  };
181
- element.addEventListener("toggle", toggle);
182
224
  window.addEventListener("resize", close);
183
225
  window.addEventListener("scroll", scroll, true);
184
226
  const keydown = (event) => {
@@ -206,8 +248,6 @@ function apply(ctx) {
206
248
  window.removeEventListener("resize", close);
207
249
  window.removeEventListener("scroll", scroll, true);
208
250
  element.removeEventListener("keydown", keydown);
209
- element.removeEventListener("toggle", toggle);
210
- element.hidePopover();
211
251
  };
212
252
  }, [panel]);
213
253
  (0, react.useEffect)(() => {
@@ -237,9 +277,13 @@ function apply(ctx) {
237
277
  };
238
278
  const show = (button) => {
239
279
  trigger.current = button;
280
+ if (panel) {
281
+ close();
282
+ return;
283
+ }
240
284
  setDraft(Math.max(0, effortIndex));
241
285
  setFailed(false);
242
- setPanel(panel ? null : "effort");
286
+ setPanel("effort");
243
287
  directory.load().catch(() => {});
244
288
  };
245
289
  const selectEffort = (index) => {
@@ -255,24 +299,20 @@ function apply(ctx) {
255
299
  className: "dsh-codex-picker",
256
300
  ref: anchor,
257
301
  "aria-busy": busy,
258
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
259
- type: "button",
302
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ComposerTrigger, {
260
303
  className: "dsh-codex-trigger",
304
+ icon: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconDataOutlineRegular, { size: 16 }),
305
+ label: model?.name ?? current?.model ?? text.model,
306
+ detail: effortLabel,
261
307
  disabled,
262
308
  "aria-label": `${text.choose}: ${model?.name ?? current?.model ?? text.model}${effortLabel ? `, ${effortLabel}` : ""}`,
309
+ title: `${model?.name ?? current?.model ?? text.model}${effortLabel ? ` ${effortLabel}` : ""}`,
263
310
  "aria-haspopup": "dialog",
264
311
  "aria-expanded": panel !== null,
265
312
  "aria-controls": panel ? id : void 0,
266
- onClick: (event) => show(event.currentTarget),
267
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
268
- className: "dsh-codex-name",
269
- children: panel ? text.choose : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [model?.name ?? current?.model ?? text.model, effortLabel && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [" ", /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
270
- className: "dsh-codex-effort",
271
- children: effortLabel
272
- })] })] })
273
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Chevron, { direction: "down" })]
313
+ onClick: (event) => show(event.currentTarget)
274
314
  })
275
- }), panel && (0, react_dom.createPortal)(/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
315
+ }), panel && (0, react_dom.createPortal)(/* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_deepseek_ai_dsh_client_ui_primitives.MenuSurface, {
276
316
  id,
277
317
  ref: popup,
278
318
  role: "dialog",
@@ -284,7 +324,7 @@ function apply(ctx) {
284
324
  className: "dsh-codex-back",
285
325
  onClick: () => setPanel("effort"),
286
326
  children: [
287
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Chevron, { direction: "left" }),
327
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconChevronLeftOutlineRegular, { size: 14 }),
288
328
  " ",
289
329
  text.effort
290
330
  ]
@@ -299,7 +339,7 @@ function apply(ctx) {
299
339
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("strong", { children: efforts[draft]?.name ?? effortLabel ?? text.default }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", { children: [
300
340
  model?.name ?? current?.model ?? text.model,
301
341
  " ",
302
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Chevron, { direction: "right" })
342
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconChevronRightOutlineRegular, { size: 14 })
303
343
  ] })]
304
344
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
305
345
  type: "button",
@@ -313,16 +353,7 @@ function apply(ctx) {
313
353
  model: current.model
314
354
  });
315
355
  },
316
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("svg", {
317
- width: "16",
318
- height: "16",
319
- viewBox: "0 0 16 16",
320
- fill: "none",
321
- stroke: "currentColor",
322
- strokeWidth: "1.2",
323
- "aria-hidden": "true",
324
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", { d: "M3 4a5.5 5.5 0 1 1-1 6M3 1v3h3" })
325
- })
356
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(IconResetOutlineRegular, {})
326
357
  })]
327
358
  }),
328
359
  state.status === "loading" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
@@ -376,7 +407,7 @@ function apply(ctx) {
376
407
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", { children: [option.name, option.description && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("small", { children: option.description })] }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
377
408
  className: "dsh-codex-check",
378
409
  "aria-hidden": "true",
379
- children: provider.id === current?.provider && option.id === current?.model ? "✓" : ""
410
+ children: provider.id === current?.provider && option.id === current?.model && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconCheckOutlineRegular, { size: 14 })
380
411
  })]
381
412
  }, option.id))]
382
413
  }, provider.id))
@@ -440,12 +471,7 @@ function apply(ctx) {
440
471
  locked: props.locked,
441
472
  directory: ctx.modelDirectories.directoryFor(props.sessionId)
442
473
  }, props.sessionId) : null));
443
- ctx.effect(() => {
444
- const style = document.createElement("style");
445
- style.textContent = styles;
446
- document.head.append(style);
447
- return () => style.remove();
448
- }, "ui-model-picker: styles");
474
+ ctx.effect(() => installStyles(styles), "ui-model-picker: styles");
449
475
  }
450
476
  exports.apply = apply;
451
477
  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.0",
3
+ "version": "0.2.2",
4
4
  "description": "Model and reasoning effort picker for the DeepSeek Harness composer.",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -36,13 +36,17 @@
36
36
  "@deepseek-ai/dsh-client-ui-session": "0.2.1-rc.5",
37
37
  "@deepseek-ai/dsh-client-ui-slots": "0.2.1-rc.5",
38
38
  "@dungsil/dsh-tsconfig": "0.0.0",
39
+ "@dungsil/dsh-tsdown": "0.0.0",
40
+ "@dungsil/dsh-ui": "0.0.0",
39
41
  "@types/react": "18.3.31",
40
42
  "@types/react-dom": "18.3.7",
41
- "happy-dom": "21.0.4",
42
43
  "react": "18.3.1",
43
44
  "react-dom": "18.3.1",
44
45
  "tsdown": "0.23.4"
45
46
  },
47
+ "peerDependencies": {
48
+ "@deepseek-ai/dsh-client-ui-primitives": "^0.2.1-rc.5"
49
+ },
46
50
  "engines": {
47
51
  "dsh": "^0.2.1-rc.5",
48
52
  "node": ">=24.9.0"
@@ -84,7 +88,6 @@
84
88
  },
85
89
  "scripts": {
86
90
  "build": "tsdown",
87
- "typecheck": "tsc --noEmit",
88
- "test": "node --test test/*.test.mjs"
91
+ "typecheck": "tsc --noEmit"
89
92
  }
90
93
  }