@lynn123411/dsh-model-submenu 0.1.2 → 0.1.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/lib/client.js CHANGED
@@ -9,7 +9,7 @@ window.__ModuleLoader__.load({
9
9
  let _deepseek_ai_dsh_client_ui_primitives = require("@deepseek-ai/dsh-client-ui-primitives");
10
10
  let react_jsx_runtime = require("react/jsx-runtime");
11
11
  //#region \0dsh-css:/Users/tny/Desktop/work/my-dsh/plugins/dsh-model-submenu/src/client/ModelSubmenu.module.css.mjs
12
- const css = ".FOsK3a_root{min-width:0;position:relative}.FOsK3a_trigger{min-width:0;max-width:min(360px,45cqw);height:28px;color:var(--dsw-alias-label-secondary);cursor:pointer;background:0 0;border:none;border-radius:24px;outline:none;align-items:center;gap:4px;padding:0 4px 0 8px;font-size:13px;font-weight:500;line-height:20px;display:flex}.FOsK3a_trigger:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover)}.FOsK3a_trigger:focus-visible{box-shadow:0 0 0 2px var(--dsw-alias-border-l3)}.FOsK3a_trigger:disabled{color:var(--dsw-alias-label-dimmed);cursor:default}.FOsK3a_triggerLabel{text-overflow:ellipsis;white-space:nowrap;min-width:0;overflow:hidden}.FOsK3a_triggerEffort{text-overflow:ellipsis;white-space:nowrap;min-width:0;color:var(--dsw-alias-label-caption);flex-shrink:1000;overflow:hidden}.FOsK3a_triggerIcon{flex:none;display:none}@container (width<=360px){.FOsK3a_triggerIcon{display:block}.FOsK3a_triggerLabel,.FOsK3a_triggerEffort{display:none}}.FOsK3a_chevron{color:var(--dsw-alias-label-caption);flex:none;transition:transform .12s}.FOsK3a_chevronOpen{transform:rotate(180deg)}.FOsK3a_menu{z-index:1100;background:var(--dsw-specific-menu);--dsw-elevation-stroke-color:var(--dsw-alias-border-l1);width:max-content;min-width:min(240px,100vw - 32px);max-width:min(420px,100vw - 32px);max-height:min(360px,100vh - 96px);box-shadow:var(--dsw-elevation-prominent);color:var(--dsw-alias-label-primary);--dsh-scrollbar-thumb:var(--dsw-alias-scrollbar-bg-l2);--dsh-scrollbar-thumb-hover:var(--dsw-alias-scrollbar-hover-l2);border:0;border-radius:20px;flex-direction:column;padding:4px;display:flex;position:fixed;overflow:hidden}.FOsK3a_status,.FOsK3a_empty{color:var(--dsw-alias-label-tertiary);padding:10px;font-size:13px;line-height:20px}.FOsK3a_error,.FOsK3a_warning{background:var(--dsw-alias-interactive-bg-hover-danger);color:var(--dsw-alias-state-error-primary);border-radius:8px;justify-content:space-between;align-items:flex-start;gap:8px;margin-bottom:4px;padding:7px 8px;font-size:12px;line-height:18px;display:flex}.FOsK3a_warning{background:var(--dsw-alias-bg-module-platform);color:var(--dsw-alias-state-warn-label)}.FOsK3a_retry{color:inherit;font:inherit;cursor:pointer;background:0 0;border:none;flex:none;padding:0;font-weight:600}.FOsK3a_groups{min-height:0;overflow-y:auto}.FOsK3a_option{box-sizing:border-box;width:auto;min-width:100%;min-height:38px;color:inherit;text-align:left;cursor:pointer;background:0 0;border:none;border-radius:10px;outline:none;align-items:center;gap:8px;padding:6px 8px;display:flex}.FOsK3a_option:hover:not(:disabled),.FOsK3a_option:focus-visible{background:var(--dsw-alias-interactive-bg-hover)}.FOsK3a_selected{background:0 0}.FOsK3a_option:disabled{color:var(--dsw-alias-label-dimmed);cursor:default}.FOsK3a_optionCopy{flex-direction:column;flex:1;min-width:0;display:flex}.FOsK3a_modelName{color:inherit;text-overflow:ellipsis;white-space:nowrap;font-size:14px;font-weight:500;line-height:20px;overflow:hidden}.FOsK3a_check{color:var(--dsw-alias-label-primary);flex:0 0 18px;place-items:center;display:grid}.FOsK3a_cell{box-sizing:border-box;width:auto;min-width:100%;height:40px;color:var(--dsw-alias-label-primary);cursor:pointer;text-align:left;background:0 0;border:none;border-radius:10px;align-items:center;gap:8px;padding:0 10px;font-size:14px;line-height:22px;display:flex}.FOsK3a_cell:hover{background:var(--dsw-alias-interactive-bg-hover)}.FOsK3a_cellLabel{white-space:nowrap;flex:none}.FOsK3a_cellValue{text-overflow:ellipsis;white-space:nowrap;text-align:right;min-width:0;color:var(--dsw-alias-label-tertiary);flex:auto;overflow:hidden}.FOsK3a_cellChevron{color:var(--dsw-alias-label-tertiary);flex:none}";
12
+ const css = ".FOsK3a_root{min-width:0;position:relative}.FOsK3a_trigger{min-width:0;max-width:min(360px,45cqw);height:28px;color:var(--dsw-alias-label-secondary);cursor:pointer;background:0 0;border:none;border-radius:24px;outline:none;align-items:center;gap:4px;padding:0 4px 0 8px;font-size:13px;font-weight:500;line-height:20px;display:flex}.FOsK3a_trigger:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover)}.FOsK3a_trigger:focus-visible{box-shadow:0 0 0 2px var(--dsw-alias-border-l3)}.FOsK3a_trigger:disabled{color:var(--dsw-alias-label-dimmed);cursor:default}.FOsK3a_triggerLabel{text-overflow:ellipsis;white-space:nowrap;min-width:0;overflow:hidden}.FOsK3a_triggerEffort{text-overflow:ellipsis;white-space:nowrap;min-width:0;color:var(--dsw-alias-label-caption);flex-shrink:1000;overflow:hidden}.FOsK3a_triggerIcon{flex:none;display:none}@container (width<=360px){.FOsK3a_triggerIcon{display:block}.FOsK3a_triggerLabel,.FOsK3a_triggerEffort{display:none}}.FOsK3a_chevron{color:var(--dsw-alias-label-caption);flex:none;transition:transform .12s}.FOsK3a_chevronOpen{transform:rotate(180deg)}.FOsK3a_menu{z-index:1100;--dsw-elevation-stroke-color:var(--dsw-alias-border-l1);width:max-content;min-width:min(240px,100vw - 32px);max-width:min(420px,100vw - 32px);max-height:min(360px,100vh - 96px);box-shadow:var(--dsw-elevation-prominent);color:var(--dsw-alias-label-primary);--dsh-scrollbar-thumb:var(--dsw-alias-scrollbar-bg-l2);--dsh-scrollbar-thumb-hover:var(--dsw-alias-scrollbar-hover-l2);border:0;flex-direction:column;padding:4px;display:flex;position:fixed;overflow:hidden}.FOsK3a_status,.FOsK3a_empty{color:var(--dsw-alias-label-tertiary);padding:10px;font-size:13px;line-height:20px}.FOsK3a_error,.FOsK3a_warning{background:var(--dsw-alias-interactive-bg-hover-danger);color:var(--dsw-alias-state-error-primary);border-radius:8px;justify-content:space-between;align-items:flex-start;gap:8px;margin-bottom:4px;padding:7px 8px;font-size:12px;line-height:18px;display:flex}.FOsK3a_warning{background:var(--dsw-alias-bg-module-platform);color:var(--dsw-alias-state-warn-label)}.FOsK3a_retry{color:inherit;font:inherit;cursor:pointer;background:0 0;border:none;flex:none;padding:0;font-weight:600}.FOsK3a_groups{min-height:0;overflow-y:auto}.FOsK3a_option{box-sizing:border-box;width:auto;min-width:100%;min-height:38px;color:inherit;text-align:left;cursor:pointer;background:0 0;border:none;border-radius:10px;outline:none;align-items:center;gap:8px;padding:6px 8px;display:flex}.FOsK3a_option:hover:not(:disabled),.FOsK3a_option:focus-visible{background:var(--dsw-alias-interactive-bg-hover)}.FOsK3a_selected{background:0 0}.FOsK3a_option:disabled{color:var(--dsw-alias-label-dimmed);cursor:default}.FOsK3a_optionCopy{flex-direction:column;flex:1;min-width:0;display:flex}.FOsK3a_modelName{color:inherit;text-overflow:ellipsis;white-space:nowrap;font-size:14px;font-weight:500;line-height:20px;overflow:hidden}.FOsK3a_check{color:var(--dsw-alias-label-primary);flex:0 0 18px;place-items:center;display:grid}.FOsK3a_cell{box-sizing:border-box;width:auto;min-width:100%;height:40px;color:var(--dsw-alias-label-primary);cursor:pointer;text-align:left;background:0 0;border:none;border-radius:10px;align-items:center;gap:8px;padding:0 10px;font-size:14px;line-height:22px;display:flex}.FOsK3a_cell:hover{background:var(--dsw-alias-interactive-bg-hover)}.FOsK3a_cellLabel{white-space:nowrap;flex:none}.FOsK3a_cellValue{text-overflow:ellipsis;white-space:nowrap;text-align:right;min-width:0;color:var(--dsw-alias-label-tertiary);flex:auto;overflow:hidden}.FOsK3a_cellChevron{color:var(--dsw-alias-label-tertiary);flex:none}";
13
13
  const tagId = "@lynn123411/dsh-model-submenu/ModelSubmenu.module.css";
14
14
  if (typeof document !== "undefined") {
15
15
  let tag = document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId) + "]");
@@ -328,7 +328,7 @@ window.__ModuleLoader__.load({
328
328
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconChevronDownOutlineRegular, { className: cls(ModelSubmenu_module_css_default.chevron, open && ModelSubmenu_module_css_default.chevronOpen) })
329
329
  ]
330
330
  }),
331
- open && (0, react_dom.createPortal)(/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
331
+ open && (0, react_dom.createPortal)(/* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_deepseek_ai_dsh_client_ui_primitives.MenuSurface, {
332
332
  ref: menuRef,
333
333
  id: `${id}-menu`,
334
334
  className: ModelSubmenu_module_css_default.menu,
package/lib/client.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"client.js","names":["useSyncExternalStore","useState","useRef","useId","useMemo","css","IconChevronLeftOutlineRegular","IconDataOutlineRegular","IconChevronDownOutlineRegular","createPortal","Fragment","IconChevronRightOutlineRegular","IconCheckOutlineRegular","Toast","IconWarningOutlineRegular"],"sources":["../src/client/ModelSubmenu.tsx","../src/client/locales.ts","../src/client/index.ts"],"sourcesContent":["import { Fragment, useEffect, useId, useLayoutEffect, useMemo, useRef, useState, useSyncExternalStore } from 'react'\nimport { createPortal } from 'react-dom'\nimport {\n IconCheckOutlineRegular,\n IconChevronDownOutlineRegular,\n IconChevronLeftOutlineRegular,\n IconChevronRightOutlineRegular,\n IconDataOutlineRegular,\n IconWarningOutlineRegular,\n Toast,\n} from '@deepseek-ai/dsh-client-ui-primitives'\nimport type { ModelDirectoryState, ModelSelectInjected } from '@deepseek-ai/dsh-client-ui-model-selection/client'\nimport type { PropsLocale } from '@deepseek-ai/dsh-client-ui-slots'\nimport css from './ModelSubmenu.module.css'\n\ntype ModelSubmenuProps = ModelSelectInjected & { locked: boolean } & PropsLocale<'modelSubmenu'>\n\ntype Selection = Parameters<ModelSelectInjected['select']>[0]\ntype ProviderGroup = ModelDirectoryState['groups'][number]\ntype CatalogModel = ProviderGroup['models'][number]\n\n/** Which list the open menu is showing. */\ntype Pane = 'root' | 'providers' | 'models' | 'effort'\n\n/** Unplaced portal card: hidden but laid out at a fixed origin so offsetWidth/offsetHeight are real. */\nconst MEASURE_STYLE = {\n visibility: 'hidden',\n left: 0,\n top: 0,\n} as const\n\nconst cls = (...parts: readonly (string | false | undefined)[]): string => parts.filter((part) => part !== false && part !== undefined).join(' ')\n\n/**\n * The composer's model seat (`conversation.input.model`), taken over from the\n * built-in occupant with a provider level: the root pane keeps the built-in's\n * two cells — 供应商 in place of 模型, plus the native 推理等级 — the provider\n * cell drills into the catalog's providers, and a provider drills into its\n * models before submitting. The trigger, the menu surface, the keyboard\n * contract (arrows move, Tab settles, Escape and Shift+Tab leave a drilled pane\n * first), the effort list and the failure surfaces are the built-in ones.\n */\nexport function ModelSubmenu({ locked, available, directory, load, select, t }: ModelSubmenuProps) {\n const state = useSyncExternalStore((fn) => directory.subscribe(fn), () => directory.getSnapshot())\n const [open, setOpen] = useState(false)\n const [pane, setPane] = useState<Pane>('root')\n const [providerId, setProviderId] = useState<string | null>(null)\n const lastActionRef = useRef<'load' | 'select'>('load')\n const [toast, setToast] = useState<{ seq: number; text: string } | null>(null)\n const toastSeq = useRef(0)\n const rootRef = useRef<HTMLDivElement | null>(null)\n const triggerRef = useRef<HTMLButtonElement | null>(null)\n const menuRef = useRef<HTMLDivElement | null>(null)\n const [menuPos, setMenuPos] = useState<{ left: number; top: number } | null>(null)\n const itemRefs = useRef(new Map<string, HTMLButtonElement>())\n const focusIntent = useRef<string | null>(null)\n const id = useId()\n\n const groups = state.groups\n const current = state.current\n const currentGroup = current === null ? undefined : groups.find((group) => group.id === current.provider)\n const currentModel = currentGroup?.models.find((model) => model.id === current?.model)\n const reasoning = currentModel?.reasoning\n const effectiveEffort = current?.reasoningEffort ?? reasoning?.defaultEffort\n const effortLabel = reasoning === undefined\n ? undefined\n : effectiveEffort === undefined\n ? t('effort.providerDefault')\n : reasoning.efforts.find((level) => level.id === effectiveEffort)?.name ?? effectiveEffort\n const effortChoices = useMemo(() => reasoning === undefined ? [] : [\n ...reasoning.defaultEffort === undefined\n ? [{ key: 'provider-default', effort: undefined as string | undefined, label: t('effort.providerDefault') }]\n : [],\n ...reasoning.efforts.map((level) => ({ key: `effort:${level.id}`, effort: level.id as string | undefined, label: level.name })),\n ], [reasoning, t])\n\n const shownGroup = pane === 'models' && providerId !== null ? groups.find((group) => group.id === providerId) : undefined\n const busy = state.status === 'selecting'\n\n const reload = () => {\n lastActionRef.current = 'load'\n load()\n }\n\n useEffect(() => {\n if (!open) return\n const closeOutside = (event: MouseEvent) => {\n if (rootRef.current?.contains(event.target as Node) === true) return\n if (menuRef.current?.contains(event.target as Node) === true) return\n setOpen(false)\n setPane('root')\n }\n document.addEventListener('mousedown', closeOutside)\n return () => {\n document.removeEventListener('mousedown', closeOutside)\n }\n }, [open])\n\n useEffect(() => {\n const intent = focusIntent.current\n focusIntent.current = null\n if (!open || intent === null) return\n if (intent === 'initial') {\n const checked = menuRef.current?.querySelector<HTMLElement>('[role=\"menuitemradio\"][aria-checked=\"true\"]:not([disabled]), [role=\"menuitem\"][aria-current=\"true\"]:not([disabled])')\n const first = [...itemRefs.current].find(([key]) => !key.startsWith('back:'))?.[1]\n ;(checked ?? first ?? triggerRef.current)?.focus()\n return\n }\n ;(itemRefs.current.get(intent) ?? triggerRef.current)?.focus()\n }, [open, pane])\n\n useLayoutEffect(() => {\n if (!open) {\n setMenuPos(null)\n return\n }\n const place = () => {\n const rect = triggerRef.current?.getBoundingClientRect()\n if (rect === undefined) return\n const MARGIN = 12\n const lw = menuRef.current?.offsetWidth ?? 0\n const lh = menuRef.current?.offsetHeight ?? 0\n let x = rect.right - lw\n let y = rect.top - 8 - lh\n if (lw > 0) x = Math.min(Math.max(x, MARGIN), window.innerWidth - lw - MARGIN)\n if (lh > 0) y = Math.min(Math.max(y, MARGIN), window.innerHeight - lh - MARGIN)\n setMenuPos({ left: x, top: y })\n }\n place()\n window.addEventListener('scroll', place, true)\n window.addEventListener('resize', place)\n return () => {\n window.removeEventListener('scroll', place, true)\n window.removeEventListener('resize', place)\n }\n }, [open, pane, state])\n\n if (!available) return null\n\n const show = () => {\n setPane('root')\n setProviderId(null)\n setOpen(true)\n reload()\n }\n const close = (restoreFocus = false) => {\n setOpen(false)\n setPane('root')\n setProviderId(null)\n if (restoreFocus) queueMicrotask(() => {\n triggerRef.current?.focus()\n })\n }\n const drill = (next: Pane) => {\n focusIntent.current = 'initial'\n setPane(next)\n }\n /** Leave the shown pane for its parent, handing the keyboard back to the row that opened it. */\n const back = () => {\n if (pane === 'models') {\n focusIntent.current = providerId === null ? null : `provider:${providerId}`\n setPane('providers')\n return\n }\n focusIntent.current = pane === 'effort' ? 'root:effort' : 'root:provider'\n setPane('root')\n }\n const moveFocus = (offset: number) => {\n const items = [...itemRefs.current.values()]\n if (items.length === 0) return\n const active = items.findIndex((item) => item === document.activeElement)\n items[active === -1 ? offset > 0 ? 0 : items.length - 1 : (active + offset + items.length) % items.length]?.focus()\n }\n const onRootKeyDown = (event: React.KeyboardEvent) => {\n if (event.key === 'Escape' && open) {\n event.preventDefault()\n if (pane !== 'root') back()\n else close(true)\n return\n }\n if (!open) return\n if (event.key === 'Tab') {\n if (event.shiftKey) {\n event.preventDefault()\n if (pane !== 'root') back()\n else close(true)\n return\n }\n const focused = document.activeElement\n const rows = [...itemRefs.current.values()]\n if (focused instanceof HTMLButtonElement && rows.includes(focused)) {\n event.preventDefault()\n focused.click()\n return\n }\n if (focused !== triggerRef.current) return\n event.preventDefault()\n const checked = menuRef.current?.querySelector<HTMLElement>('[role=\"menuitemradio\"][aria-checked=\"true\"]:not([disabled]), [role=\"menuitem\"][aria-current=\"true\"]:not([disabled])')\n ;(checked ?? rows.find((item) => !item.disabled))?.focus()\n return\n }\n if (event.key === 'ArrowDown' || event.key === 'ArrowUp') {\n event.preventDefault()\n moveFocus(event.key === 'ArrowDown' ? 1 : -1)\n }\n }\n const onBlur = (event: React.FocusEvent) => {\n if (event.relatedTarget instanceof Node && (rootRef.current?.contains(event.relatedTarget) === true || menuRef.current?.contains(event.relatedTarget) === true)) return\n close()\n }\n const settleSelection = (result: Awaited<ReturnType<ModelSelectInjected['select']>>) => {\n if (result === undefined) return\n if (result.ok) {\n if (rootRef.current !== null) close(true)\n return\n }\n const { error } = result\n toastSeq.current += 1\n setToast({\n seq: toastSeq.current,\n text: error.code === 'session/writer-held' ? t('error.sessionInUse') : t('error.action', { message: `${error.code}: ${error.message}` }),\n })\n }\n const submit = (selection: Selection) => {\n lastActionRef.current = 'select'\n select(selection).then(settleSelection)\n }\n /** A model commits outright; its reasoning levels stay behind the root's effort cell. */\n const chooseModel = (provider: string, model: CatalogModel) => {\n if (current?.provider === provider && current.model === model.id) {\n close(true)\n return\n }\n submit({ provider, model: model.id })\n }\n const chooseEffort = (effort: string | undefined) => {\n if (current === null) return\n if (effectiveEffort === effort) {\n close(true)\n return\n }\n submit({ provider: current.provider, model: current.model, ...effort === undefined ? {} : { reasoningEffort: effort } })\n }\n const waiting = current === null && state.status === 'loading'\n const modelLabel = waiting ? t('trigger.loading') : currentModel?.name ?? (current === null ? t('trigger.fallback') : `${current.provider}/${current.model}`)\n const triggerLabel = effortLabel === undefined ? modelLabel : `${modelLabel} · ${effortLabel}`\n const triggerAria = waiting\n ? t('trigger.loading')\n : current === null\n ? t('trigger.selectAria')\n : effortLabel === undefined\n ? t('trigger.aria', { model: modelLabel })\n : t('trigger.ariaEffort', { model: modelLabel, effort: effortLabel })\n\n itemRefs.current = new Map()\n const itemRef = (key: string) => (node: HTMLButtonElement | null) => {\n if (node === null) itemRefs.current.delete(key)\n else itemRefs.current.set(key, node)\n }\n const backRow = () => (\n <button ref={itemRef('back')} type=\"button\" role=\"menuitem\" className={css.cell} onClick={back}>\n <IconChevronLeftOutlineRegular className={css.cellChevron} />\n <span className={css.cellLabel}>{t('back')}</span>\n </button>\n )\n return (\n <div ref={rootRef} className={css.root} onKeyDown={onRootKeyDown} onBlur={onBlur}>\n <button\n ref={triggerRef}\n type=\"button\"\n className={css.trigger}\n aria-label={triggerAria}\n aria-haspopup=\"menu\"\n aria-expanded={open}\n aria-controls={open ? `${id}-menu` : undefined}\n title={triggerLabel}\n disabled={locked}\n onClick={() => {\n if (open) close()\n else show()\n }}\n >\n <IconDataOutlineRegular className={css.triggerIcon} size={16} />\n <span className={css.triggerLabel}>{modelLabel}</span>\n {effortLabel !== undefined && <span className={css.triggerEffort}>{effortLabel}</span>}\n <IconChevronDownOutlineRegular className={cls(css.chevron, open && css.chevronOpen)} />\n </button>\n {open && createPortal((\n <div\n ref={menuRef}\n id={`${id}-menu`}\n className={css.menu}\n style={menuPos ?? MEASURE_STYLE}\n role=\"menu\"\n aria-label={pane === 'models' && shownGroup !== undefined ? shownGroup.name : pane === 'effort' ? t('menu.effort') : t('menu.aria')}\n aria-busy={state.status === 'loading' || busy}\n >\n {pane === 'root' && (\n <Fragment>\n <button ref={itemRef('root:provider')} type=\"button\" role=\"menuitem\" className={css.cell} onClick={() => drill('providers')}>\n <span className={css.cellLabel}>{t('menu.provider')}</span>\n <span className={css.cellValue}>{currentGroup?.name ?? current?.provider ?? ''}</span>\n <IconChevronRightOutlineRegular className={css.cellChevron} />\n </button>\n {reasoning !== undefined && (\n <button ref={itemRef('root:effort')} type=\"button\" role=\"menuitem\" className={css.cell} onClick={() => drill('effort')}>\n <span className={css.cellLabel}>{t('menu.effort')}</span>\n <span className={css.cellValue}>{effortLabel}</span>\n <IconChevronRightOutlineRegular className={css.cellChevron} />\n </button>\n )}\n </Fragment>\n )}\n {pane === 'providers' && (\n <Fragment>\n {state.status === 'loading' && <div className={css.status}>{t('status.loading')}</div>}\n {state.error !== null && lastActionRef.current === 'load' && (\n <div className={css.error}>\n <span>{t('error.action', { message: state.error })}</span>\n <button type=\"button\" className={css.retry} onClick={reload}>{t('action.reload')}</button>\n </div>\n )}\n {state.failures.map((failure) => (\n <div className={css.warning} key={failure.id}>\n <span>{t('warning.groupLoad', { name: failure.name, message: failure.message })}</span>\n <button type=\"button\" className={css.retry} onClick={reload}>{t('action.reload')}</button>\n </div>\n ))}\n {state.status === 'ready' && groups.length === 0 && <div className={css.empty}>{t('empty.models')}</div>}\n <div className={cls(css.groups, 'scrollable')}>\n {groups.map((group) => {\n const mine = current?.provider === group.id\n return (\n <button\n key={group.id}\n ref={itemRef(`provider:${group.id}`)}\n type=\"button\"\n role=\"menuitem\"\n aria-current={mine ? 'true' : undefined}\n className={css.cell}\n title={group.name}\n onClick={() => {\n setProviderId(group.id)\n drill('models')\n }}\n >\n <span className={css.cellLabel}>{group.name}</span>\n <span className={css.cellValue}>{mine ? currentModel?.name ?? current?.model ?? '' : t('provider.modelCount', { count: String(group.models.length) })}</span>\n {mine && <span className={css.check}><IconCheckOutlineRegular /></span>}\n <IconChevronRightOutlineRegular className={css.cellChevron} />\n </button>\n )\n })}\n </div>\n </Fragment>\n )}\n {pane === 'models' && shownGroup !== undefined && (\n <Fragment>\n {backRow()}\n <div className={cls(css.groups, 'scrollable')}>\n {shownGroup.models.map((model) => {\n const selected = current?.provider === shownGroup.id && current.model === model.id\n return (\n <button\n key={model.id}\n ref={itemRef(`model:${shownGroup.id}/${model.id}`)}\n type=\"button\"\n role=\"menuitemradio\"\n aria-checked={selected}\n className={cls(css.option, selected && css.selected)}\n title={model.name}\n disabled={busy}\n onClick={() => chooseModel(shownGroup.id, model)}\n >\n <span className={css.optionCopy}><span className={css.modelName}>{model.name}</span></span>\n <span className={css.check}>{selected ? <IconCheckOutlineRegular /> : null}</span>\n </button>\n )\n })}\n </div>\n </Fragment>\n )}\n {pane === 'effort' && (\n <Fragment>\n {backRow()}\n {state.error !== null && lastActionRef.current === 'load' && (\n <div className={css.error}>\n <span>{t('error.action', { message: state.error })}</span>\n <button type=\"button\" className={css.retry} onClick={reload}>{t('action.reload')}</button>\n </div>\n )}\n {effortChoices.length === 0\n ? <div className={css.empty}>{t('empty.efforts')}</div>\n : effortChoices.map((level) => (\n <button\n key={level.key}\n ref={itemRef(`effort:${level.key}`)}\n type=\"button\"\n role=\"menuitemradio\"\n aria-checked={effectiveEffort === level.effort}\n className={cls(css.option, effectiveEffort === level.effort && css.selected)}\n disabled={busy}\n onClick={() => chooseEffort(level.effort)}\n >\n <span className={css.optionCopy}><span className={css.modelName}>{level.label}</span></span>\n <span className={css.check}>{effectiveEffort === level.effort ? <IconCheckOutlineRegular /> : null}</span>\n </button>\n ))}\n </Fragment>\n )}\n </div>\n ), document.body)}\n {toast !== null && (\n <Toast\n key={toast.seq}\n text={toast.text}\n icon={<IconWarningOutlineRegular />}\n anchor={rootRef.current?.closest('[data-composer-card]') ?? null}\n onDone={() => {\n setToast(null)\n }}\n />\n )}\n </div>\n )\n}","/** Locale bundles for the composer model seat this plugin takes over. */\n\n/** Dictionary namespace owned by this plugin. */\nexport const NS = 'modelSubmenu'\n\n/** Locale keys the seat renders. */\nexport type ModelSubmenuLocaleKey =\n | 'back'\n | 'provider.modelCount'\n | 'action.reload'\n | 'trigger.fallback'\n | 'trigger.loading'\n | 'trigger.selectAria'\n | 'trigger.aria'\n | 'trigger.ariaEffort'\n | 'menu.aria'\n | 'menu.provider'\n | 'menu.effort'\n | 'effort.providerDefault'\n | 'status.loading'\n | 'error.action'\n | 'error.sessionInUse'\n | 'warning.groupLoad'\n | 'empty.models'\n | 'empty.efforts'\n\ndeclare module '@deepseek-ai/dsh-client-ui-slots' {\n interface LocaleNamespaceMap {\n /** The composer model seat's copy. */\n modelSubmenu: ModelSubmenuLocaleKey\n }\n}\n\n/** Simplified Chinese dictionary (the key-set source of truth). */\nexport const zh: Record<ModelSubmenuLocaleKey, string> = {\n 'back': '返回',\n 'provider.modelCount': '{count} 个模型',\n 'action.reload': '重新加载',\n 'trigger.fallback': '选择模型',\n 'trigger.loading': '正在加载模型…',\n 'trigger.selectAria': '选择模型',\n 'trigger.aria': '选择模型,当前 {model}',\n 'trigger.ariaEffort': '选择模型,当前 {model},推理等级 {effort}',\n 'menu.aria': '供应商与推理等级',\n 'menu.provider': '供应商',\n 'menu.effort': '推理等级',\n 'effort.providerDefault': 'Default',\n 'status.loading': '正在刷新模型列表…',\n 'error.action': '模型操作失败:{message}',\n 'error.sessionInUse': '当前会话已被占用,可能是其他正在运行的 DSH 导致的(如其他 dsh web、桌面端),请退出其他正在运行的 DSH 后重试。',\n 'warning.groupLoad': '{name} 加载失败:{message}',\n 'empty.models': '没有可用的模型。',\n 'empty.efforts': '当前模型未提供推理等级。',\n}\n\n/** English dictionary, checked complete against the zh key set. */\nexport const en: Record<ModelSubmenuLocaleKey, string> = {\n 'back': 'Back',\n 'provider.modelCount': '{count} models',\n 'action.reload': 'Reload',\n 'trigger.fallback': 'Select model',\n 'trigger.loading': 'Loading models…',\n 'trigger.selectAria': 'Select model',\n 'trigger.aria': 'Select model, current {model}',\n 'trigger.ariaEffort': 'Select model, current {model}, reasoning effort {effort}',\n 'menu.aria': 'Provider and reasoning effort',\n 'menu.provider': 'Provider',\n 'menu.effort': 'Effort',\n 'effort.providerDefault': 'Default',\n 'status.loading': 'Refreshing model list…',\n 'error.action': 'Model operation failed: {message}',\n 'error.sessionInUse': 'This session is already in use, possibly by another running DSH instance (such as dsh web or the desktop app). Quit other running DSH instances and try again.',\n 'warning.groupLoad': '{name} failed to load: {message}',\n 'empty.models': 'No models available.',\n 'empty.efforts': 'This model provides no reasoning effort levels.',\n}","import type { Context as ClientContext } from '@deepseek-ai/cordis'\n// Type-only: `slots` and its LocaleNamespaceMap merge come from the renderer and\n// the slot package; the composer seat's SlotMap entry and owner props from\n// ui-conversation; the `modelDirectories` service and the seat's injected face\n// from ui-model-selection's browser half.\nimport type {} from '@deepseek-ai/dsh-client-ui-renderer/client'\nimport type {} from '@deepseek-ai/dsh-client-locale/client'\nimport type {} from '@deepseek-ai/dsh-api-remotes/client'\nimport type {} from '@deepseek-ai/dsh-client-ui-conversation/client'\nimport type {} from '@deepseek-ai/dsh-client-ui-model-selection/client'\nimport { ModelSubmenu } from './ModelSubmenu.tsx'\nimport { NS, en, zh } from './locales.ts'\n\nexport { ModelSubmenu } from './ModelSubmenu.tsx'\n\n/**\n * Cordis services required by the browser half. `slots` is the contribution\n * registry, `sessions` tells whether a session may select a model, and\n * `modelDirectories` owns the per-session catalog snapshot this seat renders\n * from. `remote` / `remote.session` are declared because a service method runs\n * on the calling context: `directoryFor` reads `this.ctx.remote.session` while\n * building the directory, so the seat must carry that service too.\n */\nexport const inject = ['locale', 'modelDirectories', 'remote', 'remote.session', 'sessions', 'slots']\n\n/**\n * Client plugin body: register this plugin's dictionaries, then take over the\n * composer model seat below the built-in occupant's priority so this menu\n * renders in its place.\n * @param ctx - client root context.\n */\nexport function apply(ctx: ClientContext): void {\n ctx.effect(() => ctx.locale.register(NS, { zh, en }), 'dsh-model-submenu: dictionaries')\n ctx.inject(['slots', 'modelDirectories'], (scope) => {\n const models = scope.modelDirectories\n const sessions = scope.sessions\n scope.slots.inject('conversation.input.model', () => scope.slots.register({\n name: 'conversation.input.model',\n priority: -100,\n registrant: '@lynn123411/dsh-model-submenu',\n locale: NS,\n inject: (sessionId) => {\n // The seat's inject parameter is typed as a bare string; the service\n // faces carry the branded SessionId of that same runtime value.\n const key = sessionId as Parameters<typeof models.directoryFor>[0]\n const directory = models.directoryFor(key)\n const available = sessions.subagentAddress(key) === undefined\n return {\n available,\n directory: directory.store,\n load: () => {\n if (available) directory.load().catch(() => {})\n },\n select: (selection) => available ? directory.select(selection) : Promise.resolve(undefined),\n }\n },\n }, ModelSubmenu))\n })\n}"],"mappings":"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"}
1
+ {"version":3,"file":"client.js","names":["useSyncExternalStore","useState","useRef","useId","useMemo","css","IconChevronLeftOutlineRegular","IconDataOutlineRegular","IconChevronDownOutlineRegular","createPortal","MenuSurface","Fragment","IconChevronRightOutlineRegular","IconCheckOutlineRegular","Toast","IconWarningOutlineRegular"],"sources":["../src/client/ModelSubmenu.tsx","../src/client/locales.ts","../src/client/index.ts"],"sourcesContent":["import { Fragment, useEffect, useId, useLayoutEffect, useMemo, useRef, useState, useSyncExternalStore } from 'react'\nimport { createPortal } from 'react-dom'\nimport {\n IconCheckOutlineRegular,\n IconChevronDownOutlineRegular,\n IconChevronLeftOutlineRegular,\n IconChevronRightOutlineRegular,\n IconDataOutlineRegular,\n IconWarningOutlineRegular,\n MenuSurface,\n Toast,\n} from '@deepseek-ai/dsh-client-ui-primitives'\nimport type { ModelDirectoryState, ModelSelectInjected } from '@deepseek-ai/dsh-client-ui-model-selection/client'\nimport type { PropsLocale } from '@deepseek-ai/dsh-client-ui-slots'\nimport css from './ModelSubmenu.module.css'\n\ntype ModelSubmenuProps = ModelSelectInjected & { locked: boolean } & PropsLocale<'modelSubmenu'>\n\ntype Selection = Parameters<ModelSelectInjected['select']>[0]\ntype ProviderGroup = ModelDirectoryState['groups'][number]\ntype CatalogModel = ProviderGroup['models'][number]\n\n/** Which list the open menu is showing. */\ntype Pane = 'root' | 'providers' | 'models' | 'effort'\n\n/** Unplaced portal card: hidden but laid out at a fixed origin so offsetWidth/offsetHeight are real. */\nconst MEASURE_STYLE = {\n visibility: 'hidden',\n left: 0,\n top: 0,\n} as const\n\nconst cls = (...parts: readonly (string | false | undefined)[]): string => parts.filter((part) => part !== false && part !== undefined).join(' ')\n\n/**\n * The composer's model seat (`conversation.input.model`), taken over from the\n * built-in occupant with a provider level: the root pane keeps the built-in's\n * two cells — 供应商 in place of 模型, plus the native 推理等级 — the provider\n * cell drills into the catalog's providers, and a provider drills into its\n * models before submitting. The trigger, the menu surface, the keyboard\n * contract (arrows move, Tab settles, Escape and Shift+Tab leave a drilled pane\n * first), the effort list and the failure surfaces are the built-in ones.\n */\nexport function ModelSubmenu({ locked, available, directory, load, select, t }: ModelSubmenuProps) {\n const state = useSyncExternalStore((fn) => directory.subscribe(fn), () => directory.getSnapshot())\n const [open, setOpen] = useState(false)\n const [pane, setPane] = useState<Pane>('root')\n const [providerId, setProviderId] = useState<string | null>(null)\n const lastActionRef = useRef<'load' | 'select'>('load')\n const [toast, setToast] = useState<{ seq: number; text: string } | null>(null)\n const toastSeq = useRef(0)\n const rootRef = useRef<HTMLDivElement | null>(null)\n const triggerRef = useRef<HTMLButtonElement | null>(null)\n const menuRef = useRef<HTMLDivElement | null>(null)\n const [menuPos, setMenuPos] = useState<{ left: number; top: number } | null>(null)\n const itemRefs = useRef(new Map<string, HTMLButtonElement>())\n const focusIntent = useRef<string | null>(null)\n const id = useId()\n\n const groups = state.groups\n const current = state.current\n const currentGroup = current === null ? undefined : groups.find((group) => group.id === current.provider)\n const currentModel = currentGroup?.models.find((model) => model.id === current?.model)\n const reasoning = currentModel?.reasoning\n const effectiveEffort = current?.reasoningEffort ?? reasoning?.defaultEffort\n const effortLabel = reasoning === undefined\n ? undefined\n : effectiveEffort === undefined\n ? t('effort.providerDefault')\n : reasoning.efforts.find((level) => level.id === effectiveEffort)?.name ?? effectiveEffort\n const effortChoices = useMemo(() => reasoning === undefined ? [] : [\n ...reasoning.defaultEffort === undefined\n ? [{ key: 'provider-default', effort: undefined as string | undefined, label: t('effort.providerDefault') }]\n : [],\n ...reasoning.efforts.map((level) => ({ key: `effort:${level.id}`, effort: level.id as string | undefined, label: level.name })),\n ], [reasoning, t])\n\n const shownGroup = pane === 'models' && providerId !== null ? groups.find((group) => group.id === providerId) : undefined\n const busy = state.status === 'selecting'\n\n const reload = () => {\n lastActionRef.current = 'load'\n load()\n }\n\n useEffect(() => {\n if (!open) return\n const closeOutside = (event: MouseEvent) => {\n if (rootRef.current?.contains(event.target as Node) === true) return\n if (menuRef.current?.contains(event.target as Node) === true) return\n setOpen(false)\n setPane('root')\n }\n document.addEventListener('mousedown', closeOutside)\n return () => {\n document.removeEventListener('mousedown', closeOutside)\n }\n }, [open])\n\n useEffect(() => {\n const intent = focusIntent.current\n focusIntent.current = null\n if (!open || intent === null) return\n if (intent === 'initial') {\n const checked = menuRef.current?.querySelector<HTMLElement>('[role=\"menuitemradio\"][aria-checked=\"true\"]:not([disabled]), [role=\"menuitem\"][aria-current=\"true\"]:not([disabled])')\n const first = [...itemRefs.current].find(([key]) => !key.startsWith('back:'))?.[1]\n ;(checked ?? first ?? triggerRef.current)?.focus()\n return\n }\n ;(itemRefs.current.get(intent) ?? triggerRef.current)?.focus()\n }, [open, pane])\n\n useLayoutEffect(() => {\n if (!open) {\n setMenuPos(null)\n return\n }\n const place = () => {\n const rect = triggerRef.current?.getBoundingClientRect()\n if (rect === undefined) return\n const MARGIN = 12\n const lw = menuRef.current?.offsetWidth ?? 0\n const lh = menuRef.current?.offsetHeight ?? 0\n let x = rect.right - lw\n let y = rect.top - 8 - lh\n if (lw > 0) x = Math.min(Math.max(x, MARGIN), window.innerWidth - lw - MARGIN)\n if (lh > 0) y = Math.min(Math.max(y, MARGIN), window.innerHeight - lh - MARGIN)\n setMenuPos({ left: x, top: y })\n }\n place()\n window.addEventListener('scroll', place, true)\n window.addEventListener('resize', place)\n return () => {\n window.removeEventListener('scroll', place, true)\n window.removeEventListener('resize', place)\n }\n }, [open, pane, state])\n\n if (!available) return null\n\n const show = () => {\n setPane('root')\n setProviderId(null)\n setOpen(true)\n reload()\n }\n const close = (restoreFocus = false) => {\n setOpen(false)\n setPane('root')\n setProviderId(null)\n if (restoreFocus) queueMicrotask(() => {\n triggerRef.current?.focus()\n })\n }\n const drill = (next: Pane) => {\n focusIntent.current = 'initial'\n setPane(next)\n }\n /** Leave the shown pane for its parent, handing the keyboard back to the row that opened it. */\n const back = () => {\n if (pane === 'models') {\n focusIntent.current = providerId === null ? null : `provider:${providerId}`\n setPane('providers')\n return\n }\n focusIntent.current = pane === 'effort' ? 'root:effort' : 'root:provider'\n setPane('root')\n }\n const moveFocus = (offset: number) => {\n const items = [...itemRefs.current.values()]\n if (items.length === 0) return\n const active = items.findIndex((item) => item === document.activeElement)\n items[active === -1 ? offset > 0 ? 0 : items.length - 1 : (active + offset + items.length) % items.length]?.focus()\n }\n const onRootKeyDown = (event: React.KeyboardEvent) => {\n if (event.key === 'Escape' && open) {\n event.preventDefault()\n if (pane !== 'root') back()\n else close(true)\n return\n }\n if (!open) return\n if (event.key === 'Tab') {\n if (event.shiftKey) {\n event.preventDefault()\n if (pane !== 'root') back()\n else close(true)\n return\n }\n const focused = document.activeElement\n const rows = [...itemRefs.current.values()]\n if (focused instanceof HTMLButtonElement && rows.includes(focused)) {\n event.preventDefault()\n focused.click()\n return\n }\n if (focused !== triggerRef.current) return\n event.preventDefault()\n const checked = menuRef.current?.querySelector<HTMLElement>('[role=\"menuitemradio\"][aria-checked=\"true\"]:not([disabled]), [role=\"menuitem\"][aria-current=\"true\"]:not([disabled])')\n ;(checked ?? rows.find((item) => !item.disabled))?.focus()\n return\n }\n if (event.key === 'ArrowDown' || event.key === 'ArrowUp') {\n event.preventDefault()\n moveFocus(event.key === 'ArrowDown' ? 1 : -1)\n }\n }\n const onBlur = (event: React.FocusEvent) => {\n if (event.relatedTarget instanceof Node && (rootRef.current?.contains(event.relatedTarget) === true || menuRef.current?.contains(event.relatedTarget) === true)) return\n close()\n }\n const settleSelection = (result: Awaited<ReturnType<ModelSelectInjected['select']>>) => {\n if (result === undefined) return\n if (result.ok) {\n if (rootRef.current !== null) close(true)\n return\n }\n const { error } = result\n toastSeq.current += 1\n setToast({\n seq: toastSeq.current,\n text: error.code === 'session/writer-held' ? t('error.sessionInUse') : t('error.action', { message: `${error.code}: ${error.message}` }),\n })\n }\n const submit = (selection: Selection) => {\n lastActionRef.current = 'select'\n select(selection).then(settleSelection)\n }\n /** A model commits outright; its reasoning levels stay behind the root's effort cell. */\n const chooseModel = (provider: string, model: CatalogModel) => {\n if (current?.provider === provider && current.model === model.id) {\n close(true)\n return\n }\n submit({ provider, model: model.id })\n }\n const chooseEffort = (effort: string | undefined) => {\n if (current === null) return\n if (effectiveEffort === effort) {\n close(true)\n return\n }\n submit({ provider: current.provider, model: current.model, ...effort === undefined ? {} : { reasoningEffort: effort } })\n }\n const waiting = current === null && state.status === 'loading'\n const modelLabel = waiting ? t('trigger.loading') : currentModel?.name ?? (current === null ? t('trigger.fallback') : `${current.provider}/${current.model}`)\n const triggerLabel = effortLabel === undefined ? modelLabel : `${modelLabel} · ${effortLabel}`\n const triggerAria = waiting\n ? t('trigger.loading')\n : current === null\n ? t('trigger.selectAria')\n : effortLabel === undefined\n ? t('trigger.aria', { model: modelLabel })\n : t('trigger.ariaEffort', { model: modelLabel, effort: effortLabel })\n\n itemRefs.current = new Map()\n const itemRef = (key: string) => (node: HTMLButtonElement | null) => {\n if (node === null) itemRefs.current.delete(key)\n else itemRefs.current.set(key, node)\n }\n const backRow = () => (\n <button ref={itemRef('back')} type=\"button\" role=\"menuitem\" className={css.cell} onClick={back}>\n <IconChevronLeftOutlineRegular className={css.cellChevron} />\n <span className={css.cellLabel}>{t('back')}</span>\n </button>\n )\n return (\n <div ref={rootRef} className={css.root} onKeyDown={onRootKeyDown} onBlur={onBlur}>\n <button\n ref={triggerRef}\n type=\"button\"\n className={css.trigger}\n aria-label={triggerAria}\n aria-haspopup=\"menu\"\n aria-expanded={open}\n aria-controls={open ? `${id}-menu` : undefined}\n title={triggerLabel}\n disabled={locked}\n onClick={() => {\n if (open) close()\n else show()\n }}\n >\n <IconDataOutlineRegular className={css.triggerIcon} size={16} />\n <span className={css.triggerLabel}>{modelLabel}</span>\n {effortLabel !== undefined && <span className={css.triggerEffort}>{effortLabel}</span>}\n <IconChevronDownOutlineRegular className={cls(css.chevron, open && css.chevronOpen)} />\n </button>\n {open && createPortal((\n <MenuSurface\n ref={menuRef}\n id={`${id}-menu`}\n className={css.menu}\n style={menuPos ?? MEASURE_STYLE}\n role=\"menu\"\n aria-label={pane === 'models' && shownGroup !== undefined ? shownGroup.name : pane === 'effort' ? t('menu.effort') : t('menu.aria')}\n aria-busy={state.status === 'loading' || busy}\n >\n {pane === 'root' && (\n <Fragment>\n <button ref={itemRef('root:provider')} type=\"button\" role=\"menuitem\" className={css.cell} onClick={() => drill('providers')}>\n <span className={css.cellLabel}>{t('menu.provider')}</span>\n <span className={css.cellValue}>{currentGroup?.name ?? current?.provider ?? ''}</span>\n <IconChevronRightOutlineRegular className={css.cellChevron} />\n </button>\n {reasoning !== undefined && (\n <button ref={itemRef('root:effort')} type=\"button\" role=\"menuitem\" className={css.cell} onClick={() => drill('effort')}>\n <span className={css.cellLabel}>{t('menu.effort')}</span>\n <span className={css.cellValue}>{effortLabel}</span>\n <IconChevronRightOutlineRegular className={css.cellChevron} />\n </button>\n )}\n </Fragment>\n )}\n {pane === 'providers' && (\n <Fragment>\n {state.status === 'loading' && <div className={css.status}>{t('status.loading')}</div>}\n {state.error !== null && lastActionRef.current === 'load' && (\n <div className={css.error}>\n <span>{t('error.action', { message: state.error })}</span>\n <button type=\"button\" className={css.retry} onClick={reload}>{t('action.reload')}</button>\n </div>\n )}\n {state.failures.map((failure) => (\n <div className={css.warning} key={failure.id}>\n <span>{t('warning.groupLoad', { name: failure.name, message: failure.message })}</span>\n <button type=\"button\" className={css.retry} onClick={reload}>{t('action.reload')}</button>\n </div>\n ))}\n {state.status === 'ready' && groups.length === 0 && <div className={css.empty}>{t('empty.models')}</div>}\n <div className={cls(css.groups, 'scrollable')}>\n {groups.map((group) => {\n const mine = current?.provider === group.id\n return (\n <button\n key={group.id}\n ref={itemRef(`provider:${group.id}`)}\n type=\"button\"\n role=\"menuitem\"\n aria-current={mine ? 'true' : undefined}\n className={css.cell}\n title={group.name}\n onClick={() => {\n setProviderId(group.id)\n drill('models')\n }}\n >\n <span className={css.cellLabel}>{group.name}</span>\n <span className={css.cellValue}>{mine ? currentModel?.name ?? current?.model ?? '' : t('provider.modelCount', { count: String(group.models.length) })}</span>\n {mine && <span className={css.check}><IconCheckOutlineRegular /></span>}\n <IconChevronRightOutlineRegular className={css.cellChevron} />\n </button>\n )\n })}\n </div>\n </Fragment>\n )}\n {pane === 'models' && shownGroup !== undefined && (\n <Fragment>\n {backRow()}\n <div className={cls(css.groups, 'scrollable')}>\n {shownGroup.models.map((model) => {\n const selected = current?.provider === shownGroup.id && current.model === model.id\n return (\n <button\n key={model.id}\n ref={itemRef(`model:${shownGroup.id}/${model.id}`)}\n type=\"button\"\n role=\"menuitemradio\"\n aria-checked={selected}\n className={cls(css.option, selected && css.selected)}\n title={model.name}\n disabled={busy}\n onClick={() => chooseModel(shownGroup.id, model)}\n >\n <span className={css.optionCopy}><span className={css.modelName}>{model.name}</span></span>\n <span className={css.check}>{selected ? <IconCheckOutlineRegular /> : null}</span>\n </button>\n )\n })}\n </div>\n </Fragment>\n )}\n {pane === 'effort' && (\n <Fragment>\n {backRow()}\n {state.error !== null && lastActionRef.current === 'load' && (\n <div className={css.error}>\n <span>{t('error.action', { message: state.error })}</span>\n <button type=\"button\" className={css.retry} onClick={reload}>{t('action.reload')}</button>\n </div>\n )}\n {effortChoices.length === 0\n ? <div className={css.empty}>{t('empty.efforts')}</div>\n : effortChoices.map((level) => (\n <button\n key={level.key}\n ref={itemRef(`effort:${level.key}`)}\n type=\"button\"\n role=\"menuitemradio\"\n aria-checked={effectiveEffort === level.effort}\n className={cls(css.option, effectiveEffort === level.effort && css.selected)}\n disabled={busy}\n onClick={() => chooseEffort(level.effort)}\n >\n <span className={css.optionCopy}><span className={css.modelName}>{level.label}</span></span>\n <span className={css.check}>{effectiveEffort === level.effort ? <IconCheckOutlineRegular /> : null}</span>\n </button>\n ))}\n </Fragment>\n )}\n </MenuSurface>\n ), document.body)}\n {toast !== null && (\n <Toast\n key={toast.seq}\n text={toast.text}\n icon={<IconWarningOutlineRegular />}\n anchor={rootRef.current?.closest('[data-composer-card]') ?? null}\n onDone={() => {\n setToast(null)\n }}\n />\n )}\n </div>\n )\n}","/** Locale bundles for the composer model seat this plugin takes over. */\n\n/** Dictionary namespace owned by this plugin. */\nexport const NS = 'modelSubmenu'\n\n/** Locale keys the seat renders. */\nexport type ModelSubmenuLocaleKey =\n | 'back'\n | 'provider.modelCount'\n | 'action.reload'\n | 'trigger.fallback'\n | 'trigger.loading'\n | 'trigger.selectAria'\n | 'trigger.aria'\n | 'trigger.ariaEffort'\n | 'menu.aria'\n | 'menu.provider'\n | 'menu.effort'\n | 'effort.providerDefault'\n | 'status.loading'\n | 'error.action'\n | 'error.sessionInUse'\n | 'warning.groupLoad'\n | 'empty.models'\n | 'empty.efforts'\n\ndeclare module '@deepseek-ai/dsh-client-ui-slots' {\n interface LocaleNamespaceMap {\n /** The composer model seat's copy. */\n modelSubmenu: ModelSubmenuLocaleKey\n }\n}\n\n/** Simplified Chinese dictionary (the key-set source of truth). */\nexport const zh: Record<ModelSubmenuLocaleKey, string> = {\n 'back': '返回',\n 'provider.modelCount': '{count} 个模型',\n 'action.reload': '重新加载',\n 'trigger.fallback': '选择模型',\n 'trigger.loading': '正在加载模型…',\n 'trigger.selectAria': '选择模型',\n 'trigger.aria': '选择模型,当前 {model}',\n 'trigger.ariaEffort': '选择模型,当前 {model},推理等级 {effort}',\n 'menu.aria': '供应商与推理等级',\n 'menu.provider': '供应商',\n 'menu.effort': '推理等级',\n 'effort.providerDefault': 'Default',\n 'status.loading': '正在刷新模型列表…',\n 'error.action': '模型操作失败:{message}',\n 'error.sessionInUse': '当前会话已被占用,可能是其他正在运行的 DSH 导致的(如其他 dsh web、桌面端),请退出其他正在运行的 DSH 后重试。',\n 'warning.groupLoad': '{name} 加载失败:{message}',\n 'empty.models': '没有可用的模型。',\n 'empty.efforts': '当前模型未提供推理等级。',\n}\n\n/** English dictionary, checked complete against the zh key set. */\nexport const en: Record<ModelSubmenuLocaleKey, string> = {\n 'back': 'Back',\n 'provider.modelCount': '{count} models',\n 'action.reload': 'Reload',\n 'trigger.fallback': 'Select model',\n 'trigger.loading': 'Loading models…',\n 'trigger.selectAria': 'Select model',\n 'trigger.aria': 'Select model, current {model}',\n 'trigger.ariaEffort': 'Select model, current {model}, reasoning effort {effort}',\n 'menu.aria': 'Provider and reasoning effort',\n 'menu.provider': 'Provider',\n 'menu.effort': 'Effort',\n 'effort.providerDefault': 'Default',\n 'status.loading': 'Refreshing model list…',\n 'error.action': 'Model operation failed: {message}',\n 'error.sessionInUse': 'This session is already in use, possibly by another running DSH instance (such as dsh web or the desktop app). Quit other running DSH instances and try again.',\n 'warning.groupLoad': '{name} failed to load: {message}',\n 'empty.models': 'No models available.',\n 'empty.efforts': 'This model provides no reasoning effort levels.',\n}","import type { Context as ClientContext } from '@deepseek-ai/cordis'\n// Type-only: `slots` and its LocaleNamespaceMap merge come from the renderer and\n// the slot package; the composer seat's SlotMap entry and owner props from\n// ui-conversation; the `modelDirectories` service and the seat's injected face\n// from ui-model-selection's browser half.\nimport type {} from '@deepseek-ai/dsh-client-ui-renderer/client'\nimport type {} from '@deepseek-ai/dsh-client-locale/client'\nimport type {} from '@deepseek-ai/dsh-api-remotes/client'\nimport type {} from '@deepseek-ai/dsh-client-ui-conversation/client'\nimport type {} from '@deepseek-ai/dsh-client-ui-model-selection/client'\nimport { ModelSubmenu } from './ModelSubmenu.tsx'\nimport { NS, en, zh } from './locales.ts'\n\nexport { ModelSubmenu } from './ModelSubmenu.tsx'\n\n/**\n * Cordis services required by the browser half. `slots` is the contribution\n * registry, `sessions` tells whether a session may select a model, and\n * `modelDirectories` owns the per-session catalog snapshot this seat renders\n * from. `remote` / `remote.session` are declared because a service method runs\n * on the calling context: `directoryFor` reads `this.ctx.remote.session` while\n * building the directory, so the seat must carry that service too.\n */\nexport const inject = ['locale', 'modelDirectories', 'remote', 'remote.session', 'sessions', 'slots']\n\n/**\n * Client plugin body: register this plugin's dictionaries, then take over the\n * composer model seat below the built-in occupant's priority so this menu\n * renders in its place.\n * @param ctx - client root context.\n */\nexport function apply(ctx: ClientContext): void {\n ctx.effect(() => ctx.locale.register(NS, { zh, en }), 'dsh-model-submenu: dictionaries')\n ctx.inject(['slots', 'modelDirectories'], (scope) => {\n const models = scope.modelDirectories\n const sessions = scope.sessions\n scope.slots.inject('conversation.input.model', () => scope.slots.register({\n name: 'conversation.input.model',\n priority: -100,\n registrant: '@lynn123411/dsh-model-submenu',\n locale: NS,\n inject: (sessionId) => {\n // The seat's inject parameter is typed as a bare string; the service\n // faces carry the branded SessionId of that same runtime value.\n const key = sessionId as Parameters<typeof models.directoryFor>[0]\n const directory = models.directoryFor(key)\n const available = sessions.subagentAddress(key) === undefined\n return {\n available,\n directory: directory.store,\n load: () => {\n if (available) directory.load().catch(() => {})\n },\n select: (selection) => available ? directory.select(selection) : Promise.resolve(undefined),\n }\n },\n }, ModelSubmenu))\n })\n}"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lynn123411/dsh-model-submenu",
3
- "version": "0.1.2",
3
+ "version": "0.1.3",
4
4
  "license": "MIT",
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -1,7 +1,8 @@
1
1
  /*
2
2
  * The composer model seat's shape, values, and tokens follow the seat this
3
- * plugin takes over; every declaration below is the shipped one so the two
4
- * render identically.
3
+ * plugin takes over. The menu surface renders through the primitives'
4
+ * MenuSurface, which owns the fill, the backdrop blur, the radius, and the
5
+ * macOS backing — so nothing below paints the panel itself.
5
6
  */
6
7
  .root {
7
8
  min-width: 0;
@@ -84,7 +85,6 @@
84
85
 
85
86
  .menu {
86
87
  z-index: 1100;
87
- background: var(--dsw-specific-menu);
88
88
  --dsw-elevation-stroke-color: var(--dsw-alias-border-l1);
89
89
  width: max-content;
90
90
  min-width: min(240px, 100vw - 32px);
@@ -95,7 +95,6 @@
95
95
  --dsh-scrollbar-thumb: var(--dsw-alias-scrollbar-bg-l2);
96
96
  --dsh-scrollbar-thumb-hover: var(--dsw-alias-scrollbar-hover-l2);
97
97
  border: 0;
98
- border-radius: 20px;
99
98
  flex-direction: column;
100
99
  padding: 4px;
101
100
  display: flex;
@@ -7,6 +7,7 @@ import {
7
7
  IconChevronRightOutlineRegular,
8
8
  IconDataOutlineRegular,
9
9
  IconWarningOutlineRegular,
10
+ MenuSurface,
10
11
  Toast,
11
12
  } from '@deepseek-ai/dsh-client-ui-primitives'
12
13
  import type { ModelDirectoryState, ModelSelectInjected } from '@deepseek-ai/dsh-client-ui-model-selection/client'
@@ -286,7 +287,7 @@ export function ModelSubmenu({ locked, available, directory, load, select, t }:
286
287
  <IconChevronDownOutlineRegular className={cls(css.chevron, open && css.chevronOpen)} />
287
288
  </button>
288
289
  {open && createPortal((
289
- <div
290
+ <MenuSurface
290
291
  ref={menuRef}
291
292
  id={`${id}-menu`}
292
293
  className={css.menu}
@@ -408,7 +409,7 @@ export function ModelSubmenu({ locked, available, directory, load, select, t }:
408
409
  ))}
409
410
  </Fragment>
410
411
  )}
411
- </div>
412
+ </MenuSurface>
412
413
  ), document.body)}
413
414
  {toast !== null && (
414
415
  <Toast