dsh-task-ledger 0.0.95 → 0.0.97
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 +3618 -116
- package/dist/client.js.map +1 -1
- package/dist/host/repositories/ledger.repository.d.ts +8 -2
- package/dist/host/repositories/ledger.repository.js +4 -1
- package/dist/host/repositories/records.d.ts +10 -2
- package/dist/host/repositories/records.js +11 -2
- package/dist/host/routes.js +1 -0
- package/dist/host/services/dates.d.ts +7 -2
- package/dist/host/services/dates.js +29 -6
- package/dist/host/services/history.service.js +1 -1
- package/dist/host/services/trend.service.d.ts +4 -1
- package/dist/host/services/trend.service.js +9 -1
- package/package.json +4 -1
- package/skill/README.md +2 -2
- package/skill/SKILL.md +34 -13
- package/skill/assets/worklog.md +1 -0
- package/skill/package.json +1 -1
- package/skill/references/state-model.md +6 -1
- package/skill/references/troubleshooting.md +5 -5
- package/skill/scripts/ledgerkit/actions/claim.py +7 -2
- package/skill/scripts/ledgerkit/actions/close_task.py +8 -0
- package/skill/scripts/ledgerkit/actions/handoff.py +5 -2
- package/skill/scripts/ledgerkit/actions/list_tasks.py +4 -1
- package/skill/scripts/ledgerkit/actions/log_progress.py +6 -2
- package/skill/scripts/ledgerkit/actions/new_task.py +7 -1
- package/skill/scripts/ledgerkit/actions/query_history.py +3 -1
- package/skill/scripts/ledgerkit/actions/release.py +6 -2
- package/skill/scripts/ledgerkit/actions/result.py +2 -0
- package/skill/scripts/ledgerkit/actions/show_task.py +31 -4
- package/skill/scripts/ledgerkit/actions/validate.py +6 -49
- package/skill/scripts/ledgerkit/core/history_md.py +18 -13
- package/skill/scripts/ledgerkit/core/time.py +2 -1
- package/skill/scripts/ledgerkit/core/worklog_md.py +137 -8
- package/skill/scripts/ledgerkit/shell/cli.py +24 -2
- package/skill/scripts/ledgerkit/shell/render.py +48 -4
- package/skill/scripts/ledgerkit/store/worklog_store.py +15 -4
package/dist/client.js
CHANGED
|
@@ -4,8 +4,3481 @@ window.__ModuleLoader__.load({
|
|
|
4
4
|
var module = { exports: {} };
|
|
5
5
|
var exports = module.exports;
|
|
6
6
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
7
|
+
//#region \0rolldown/runtime.js
|
|
8
|
+
var __create = Object.create;
|
|
9
|
+
var __defProp = Object.defineProperty;
|
|
10
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
11
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
12
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
13
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
14
|
+
var __commonJSMin = (cb, mod) => () => (mod || (cb((mod = { exports: {} }).exports, mod, mod.exports), cb = null), mod.exports);
|
|
15
|
+
var __copyProps = (to, from, except, desc) => {
|
|
16
|
+
if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
|
|
17
|
+
key = keys[i];
|
|
18
|
+
if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
|
|
19
|
+
get: ((k) => from[k]).bind(null, key),
|
|
20
|
+
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
return to;
|
|
24
|
+
};
|
|
25
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule || !__hasOwnProp.call(mod, "default") ? __defProp(target, "default", {
|
|
26
|
+
value: mod,
|
|
27
|
+
enumerable: true
|
|
28
|
+
}) : target, mod));
|
|
29
|
+
//#endregion
|
|
7
30
|
let react = require("react");
|
|
31
|
+
react = __toESM(react, 1);
|
|
32
|
+
let react_jsx_runtime = require("react/jsx-runtime");
|
|
33
|
+
let react_dom = require("react-dom");
|
|
34
|
+
react_dom = __toESM(react_dom, 1);
|
|
8
35
|
let _deepseek_ai_dsh_client_ui_primitives = require("@deepseek-ai/dsh-client-ui-primitives");
|
|
36
|
+
//#region ../../node_modules/.pnpm/dsh-plugin-core@0.5.0_@babel+runtime@8.0.8_@codemirror+autocomplete@6.20.4_@codemirror+_bddbf1bc7ba0e94be71f734653121d0c/node_modules/dsh-plugin-core/dist/design/tokens-css.generated.js
|
|
37
|
+
const TOKENS_CSS_TEMPLATE = "\n/* ── 文字(宿主 label 四档 + 反色面用字)────────────────────────────── */\nbody{\n --dshpc-fg:var(--dsw-alias-label-primary,#1f2328);\n --dshpc-fg-2:var(--dsw-alias-label-secondary,#5c6370);\n --dshpc-fg-3:var(--dsw-alias-label-tertiary,#767d87);\n --dshpc-fg-4:var(--dsw-alias-label-caption,#9aa1ab);\n --dshpc-fg-dim:var(--dsw-alias-label-dimmed,#b9bfc7);\n /* 反色面上的字(实心钮 / 角标):暗色下是 bluish-1000,故用 -foreground 而非 -inverted */\n --dshpc-fg-inverse:var(--dsw-alias-label-primary-foreground,#fff);\n\n /* ── 面(宿主 bg-layer 三档 + 下沉轨道底)──────────────────────────── */\n --dshpc-surface-1:var(--dsw-alias-bg-layer-1,#fff);\n --dshpc-surface-2:var(--dsw-alias-bg-layer-2,#fff);\n --dshpc-surface-3:var(--dsw-alias-bg-layer-3,#fff);\n /* 「选中亮片」的底盘色(配 --dshpc-shadow-raised 用) */\n --dshpc-surface-raised:var(--dsw-alias-bg-layer-1,#fff);\n /* 轨道 / 下沉底(官方分段控件轨道用的就是这条) */\n --dshpc-surface-sunken:var(--dsw-alias-interactive-bg-hover,rgba(38,49,72,.06));\n /* 整页 / 编辑器底(bg-base) */\n --dshpc-surface-base:var(--dsw-alias-bg-base,#fff);\n /* 自绘浮层 / 菜单卡的不透明底(= base;不要用半透明的 specific-menu) */\n --dshpc-surface-menu:var(--dshpc-surface-base);\n /* markdown 代码块面 / 字体(会话镜像里用到) */\n --dshpc-code-surface:var(--dsw-alias-markdown-code-block,rgba(128,128,128,.10));\n --dshpc-code-font:var(--dsw-font-markdown-code-block-small,12px/18px var(--ds-font-family-code,monospace));\n /* 警告文字色(宿主 state-warn-label) */\n --dshpc-warning-label:var(--dsw-alias-state-warn-label,#f5a623);\n /* 固定中性实面(自绘浮层、深色主题下必须自己变的那几个)——只有它需要暗色覆盖 */\n --dshpc-solid:var(--dsw-static-neutral-00,#fff);\n --dshpc-on-solid:var(--dsw-alias-label-primary,#1f2328);\n /* 交付文件卡那种「浅底盘 + hover 加深」两拍 */\n --dshpc-plate:var(--dsw-static-neutral-50,#fafafa);\n --dshpc-plate-hover:var(--dsw-static-neutral-100,#f5f5f5);\n /* ⚠️ 这些**固定中性面一律用 rgba 字面量**(2026-10-19 真机教训):不要写成\n 「rgba 回退行 + 嵌 --dsw-static-* 的 color-mix 行」两条同名声明——自定义属性**后者恒胜**,\n 哪怕它的值在宿主里算不出来(static 变量 invalid)⇒ 整条 token 作废、rgba 兜底一起被废,\n 0.2.6 里 Segmented 轨道全透明就是这么来的。要跟宿主主题联动的面用 alias token(那些实测有效)。 */\n --dshpc-icon-plate:rgba(255,255,255,.5);\n /* 表头底:浅色主题**偏深**,且必须**比斑马纹(--dshpc-plate)再深一档**——\n 两者不能撞色(用户 2026-10-02:表头跟斑马纹一模一样)。 */\n --dshpc-head-bg:var(--dsw-static-neutral-100,#f5f5f5);\n /* 图标小底板(产出物):浅色下要**看得见**(原先取 plate ⇒ 在白底上等于没有);hover 加倍。 */\n --dshpc-chip-bg:rgba(15,15,15,.07);\n --dshpc-chip-bg-hover:rgba(15,15,15,.14);\n /* 展开行:**带透明度的蓝**——不是灰、也不是纯色,透出卡片底色,一眼看出「这是展开的」\n (用户 2026-10-02:灰色跟斑马纹分不出来)。内容区再淡一档,形成「行深 / 内容浅」的区隔。 */\n --dshpc-open-bg:rgba(37,99,235,.10);\n --dshpc-open-bg-soft:rgba(37,99,235,.05);\n --dshpc-card-hover:rgba(37,99,235,.07);\n\n /* ── 描边四档(宿主真值:l1 4% / l2 10% / l3 12% / l4 16%)────────── */\n --dshpc-border-faint:var(--dsw-alias-border-l1,#0000000a);\n --dshpc-border:var(--dsw-alias-border-l2,#0000001a);\n --dshpc-border-strong:var(--dsw-alias-border-l3,#0000001f);\n --dshpc-border-heavy:var(--dsw-alias-border-l4,#00000029);\n\n /* ── 品牌 / 语义色 ────────────────────────────────────────────────── */\n /* 品牌「面」色:明色近黑、暗色近白(官方 Switch 选中态即此),**不是蓝色** */\n --dshpc-accent:var(--dsw-alias-brand-primary,#0f1115);\n /* 蓝色:强调 / 选中 / 焦点,一律走这条 */\n --dshpc-business:var(--dsw-alias-state-business-primary,#3b5bdb);\n --dshpc-success:var(--dsw-alias-state-success-primary,#22c55e);\n /* ⚠️ 是 state-warn(不是 state-warning,后者宿主无此定义) */\n --dshpc-warning:var(--dsw-alias-state-warn-primary,#f59e0b);\n --dshpc-danger:var(--dsw-alias-state-error-primary,#ec1313);\n --dshpc-link:var(--dsw-alias-link,#3b5bdb);\n /* 语义色**实面**上的字(角标 / 实心提示):宿主红绿黄三色都是中调 ⇒ 白字两个主题都可读,\n 故这是一条与主题无关的常量;不要拿 --dshpc-fg-inverse 顶——它在暗色下是近黑,压在红底上看不清。 */\n --dshpc-on-signal:#fff;\n /* 黄底上的字:黄色是中高明度,白字看不清 ⇒ 固定深色(与主题无关)。 */\n --dshpc-on-warning:#1f2328;\n\n /* ── 实心按钮的 hover / active 派生态(2026-10-19 用户点名)─────────────────\n 原实现是 :hover 直接压 opacity .9:黑底压 10% 几乎看不出来,用户原话「完全感觉不到颜色变了」。\n ⇒ 改成对底色做**明确的混色**(压 22% / 34%),不用 opacity:\n · 亮色主题:黑底(--dshpc-accent)掺白提亮;红 / 绿 / 黄 / 蓝底掺黑压深;\n · 暗色主题:反过来(暗底掺白、亮底掺黑)。\n 混色对象是**固定中性色字面量**(#fff / #000),不依赖宿主 static-neutral 是否存在;\n 旧内核不认 color-mix 时整条声明作废 ⇒ 回落各档原色(可接受:仍可点,只是没有 hover 反馈)。 */\n --dshpc-accent-hover:color-mix(in srgb,var(--dshpc-accent) 78%,#ffffff);\n --dshpc-accent-active:color-mix(in srgb,var(--dshpc-accent) 64%,#ffffff);\n --dshpc-danger-hover:color-mix(in srgb,var(--dshpc-danger) 78%,#000000);\n --dshpc-danger-active:color-mix(in srgb,var(--dshpc-danger) 64%,#000000);\n --dshpc-success-hover:color-mix(in srgb,var(--dshpc-success) 78%,#000000);\n --dshpc-success-active:color-mix(in srgb,var(--dshpc-success) 64%,#000000);\n --dshpc-warning-hover:color-mix(in srgb,var(--dshpc-warning) 78%,#000000);\n --dshpc-warning-active:color-mix(in srgb,var(--dshpc-warning) 64%,#000000);\n --dshpc-business-hover:color-mix(in srgb,var(--dshpc-business) 78%,#000000);\n --dshpc-business-active:color-mix(in srgb,var(--dshpc-business) 64%,#000000);\n /* 语义色**浅底**:状态色系的「一块底色」——执行记录页每条流水账的块底就是它\n (用户 2026-10-04:正常态给同色系很浅的透明底、失败用红底透出来)。\n 用 「color-mix」 现算而不写死 rgba:状态色本身跟随宿主 alias,主题一换自动成立。\n ⚠️ **深色下要更淡**:用户 2026-10-04「深色风格的绿色和红色好像都有点深」⇒ dark 段\n 把这四条压到 5%(更贴近面板底、存在感更弱);浅色段维持 8%。两端各自给值,不共用一条曲线。\n 命名收在 tokens.ts 单点(本仓硬规矩:业务文件不许自造 --dshpc-*)。 */\n --dshpc-success-soft:color-mix(in srgb,var(--dshpc-success) 8%,transparent);\n --dshpc-warning-soft:color-mix(in srgb,var(--dshpc-warning) 8%,transparent);\n --dshpc-danger-soft:color-mix(in srgb,var(--dshpc-danger) 8%,transparent);\n --dshpc-business-soft:color-mix(in srgb,var(--dshpc-business) 8%,transparent);\n\n /* ⚠️ 2026-10-18 用户拍板:宿主 alias 的 hover(暗色白 8% / 亮色 6%)**太弱**,\n 「移上去要仔细看才看得出来」⇒ 不再委托宿主 hover 别名,改为自掺中性色并加重:\n 亮色掺黑 10%、暗色掺白 14%(active 再加一档)。按钮 / 分段轨道 / 各类 hover 底同时受益。\n ⚠️ 必须保留 rgba 兜底行在前(本文件惯例,见 icon-plate 注释):掺的是**固定中性色**\n (neutral-900=#0f0f0f / neutral-00=#fff),预计算无损;旧内核不认 color-mix 时走兜底,\n 否则整条 background:var(--seg-track) 作废 ⇒ 分段轨道透明(真踩过:预览站轨道消失)。 */\n --dshpc-hover:rgba(15,15,15,.10);\n --dshpc-active:rgba(15,15,15,.18);\n /* 分段控件轨道底:专用 token(rgba 字面量、不借 --dshpc-hover 中转)——\n 2026-10-19 教训:变量链中间任何一环 invalid ⇒ background 整条作废、轨道全透明。\n 亮色:黑 7%(比 hover 的 10% 淡一档,选中白片才跳得出)。 */\n --dshpc-seg-track:rgba(15,15,15,.07);\n --dshpc-mask:var(--dsw-alias-bg-mask-1,#0000003d);\n /* 「选中面」(2026-10-06,任务日程页首创)= 当前底色**朝更深掺 12% 文字色**:\n 浅色主题下文字色是黑 ⇒ 选中面比常态底色**深一档**。深色分支见 body[data-ds-dark-theme](朝背景色掺)。\n 语义:标记「正在看的东西」,比常态明显、又不许盖住内容(不许用半透明叠状态色)。 */\n --dshpc-selected-bg:color-mix(in srgb,var(--dshpc-surface-1) 88%,var(--dshpc-fg));\n /* 任务日程页本月格默认底(2026-10-06 → 续2):浅色下给**淡蓝**(business 8% 透白底)——\n 参照用户参考稿里未选中日程块 / Tuesday 列的那种蓝、再浅一点点;\n 相邻月补位格仍走 --dshpc-surface-2(更灰),不受影响。\n 深色段维持 #23262e(用户:深色 UI 已差不多,不动)。 */\n --dshpc-cal-cell-bg:color-mix(in srgb,var(--dshpc-business) 8%,var(--dshpc-surface-1));\n /* 任务日程页「点开某天」展开的面板底(2026-10-06 续):浅色下**无限接近白、只带一丁点灰**\n (neutral-50 = #fafafa)——面板里装半透明执行记录列表,底再深整片就发糊发灰;\n 深色段沿用原 selected-bg 暗值,保持不动。 */\n --dshpc-cal-panel-bg:var(--dsw-static-neutral-50,#fafafa);\n /* 任务日程页本月格 hover 底(浅色段,2026-10-06 续3):不再走灰色通用交互底——\n 鼠标移上去应是「更亮一点点的蓝」(与深色段同语义:hover = 提亮的蓝,不是灰下去)。\n 浓度**介于**表头蓝(14%)与未选中格蓝(8%)之间、略偏表头一侧:business 12% 透白底\n (比表头浅一点、比未选中格深一点)。 */\n --dshpc-cal-cell-hover:color-mix(in srgb,var(--dshpc-business) 12%,var(--dshpc-surface-1));\n\n /* ── 投影 / 焦点 ──────────────────────────────────────────────────── */\n --dshpc-shadow-1:var(--dsw-elevation-soft,0 4px 16px 0 #00000008);\n /* 亮片自带的浮起感(选中态用;与 --dshpc-surface-raised 配对) */\n --dshpc-shadow-raised:var(--dsw-elevation-soft,0 4px 16px 0 #00000008);\n --dshpc-shadow-2:var(--dsw-shadow-lv3,0 12px 32px 0 #00000014);\n /* 键盘焦点环。⚠️ 不用宿主 --dsw-focus-ring-color:它默认值是 transparent(兜底不生效、会隐身) */\n --dshpc-focus:var(--dsw-alias-state-business-primary,#3b5bdb);\n\n /* ── 圆角(宿主真值 4 / 8 / 12 / 16 / 20 / 28)─────────────────────── */\n --dshpc-radius-xs:var(--dsw-radius-xs,4px);\n --dshpc-radius-sm:var(--dsw-radius-sm,8px);\n --dshpc-radius-md:var(--dsw-radius-md,12px);\n --dshpc-radius-lg:var(--dsw-radius-lg,16px);\n --dshpc-radius-xl:var(--dsw-radius-xl,20px);\n --dshpc-radius-panel:var(--dsw-radius-panel,28px);\n /* 全圆(胶囊标签):宿主的 radius 档最大只有 28px,撑不满 24px 高的 chip */\n --dshpc-radius-pill:999px;\n\n /* ── 间距四拍(只许用这四档,不许出现 5 / 7 / 9px)────────────────── */\n --dshpc-space-1:4px;\n --dshpc-space-2:8px;\n --dshpc-space-3:12px;\n --dshpc-space-4:16px;\n\n /* ── 控件高度:离散三档(控件用 size=\"sm|md|lg\" 选;调用点不许自定义高度,\n 真不够用才允许在调用点本地覆盖 --dshpc-control-h-*,属例外而非常态)── */\n --dshpc-control-h-sm:24px;\n --dshpc-control-h-md:28px;\n --dshpc-control-h-lg:32px;\n\n /* ── 字号 / 行高:直绑宿主字号族(宿主真值 11 / 12 / 13 / 14 / 16)───── */\n --dshpc-font-xs:var(--dsw-font-xxxs-11-font-size,11px);\n --dshpc-font-sm:var(--dsw-font-xxs-12-font-size,12px);\n --dshpc-font-md:var(--dsw-font-xs-13-font-size,13px);\n --dshpc-font-lg:var(--dsw-font-s-14-font-size,14px);\n --dshpc-font-xl:var(--dsw-font-base-16-font-size,16px);\n --dshpc-line-xs:var(--dsw-font-xxxs-11-line-height,14px);\n --dshpc-line-sm:var(--dsw-font-xxs-12-line-height,18px);\n --dshpc-line-md:var(--dsw-font-xs-13-line-height,20px);\n --dshpc-line-lg:var(--dsw-font-s-14-line-height,22px);\n --dshpc-line-xl:var(--dsw-font-base-16-line-height,24px);\n --dshpc-font-mono:var(--ds-font-family-code,monospace);\n\n /* ── 层级阶梯(业务文件不许再写裸 z-index)───────────────────────── */\n /* 页面级预览分栏 → 抽屉(新建/编辑)→ 弹窗/确认框 → 浮层菜单 → 浮层提示 */\n /* 内容层吸顶(天标签 / 表头这类「跟着滚但压住同层内容」的元素):只压同层兄弟,\n 必须低于下面所有浮层档 —— 所以它不是「开新浮层档」,而是内容层内部的排序位。 */\n --dshpc-z-sticky:10;\n --dshpc-z-dock:1030;\n --dshpc-z-drawer:1040;\n --dshpc-z-modal:1070;\n --dshpc-z-menu:1100;\n --dshpc-z-tip:1200;\n\n /* ── 动效 ─────────────────────────────────────────────────────────── */\n --dshpc-dur:var(--ds-transition-duration,.2s);\n --dshpc-dur-fast:var(--ds-transition-duration-fast,.12s);\n --dshpc-ease:var(--ds-ease-in-out,cubic-bezier(.4,0,.2,1));\n /* 运行中状态的脉动时长(2026-10-06 统一前后两端:任务配置里的绿呼吸 → 蓝、放慢;\n 执行记录里的蓝闪 → 放慢一点。两者用同一个值,动画形状本就一致)。 */\n --dshpc-dur-run:500ms;\n}\n\n/* ── 明暗差异的**唯一**落点 ──────────────────────────────────────────────\n 判据 = body[data-ds-dark-theme](宿主 0.2.0-rc.2 源码核实:启动脚本 toggleAttribute 写入,\n 唯一明暗判据;插件禁止用 prefers-color-scheme —— 它跟的是系统、不是用户在宿主里的选择)。\n 下面只放 alias 表达不了的「固定中性面」;颜色若能靠 alias 自动跟随,一律不要写在这里。 */\nbody[data-ds-dark-theme]{\n --dshpc-solid:var(--dsw-static-neutral-900,#0f0f0f);\n --dshpc-on-solid:var(--dsw-static-neutral-00,#fff);\n /* 实心按钮 hover / active(暗色版):黑底(浅色主题的近黑 → 暗色下的近白)掺黑压深;\n 红 / 绿 / 黄 / 蓝掺白提亮。与亮色段方向相反,保证两种主题下「一眼看出变了」。 */\n --dshpc-accent-hover:color-mix(in srgb,var(--dshpc-accent) 80%,#000000);\n --dshpc-accent-active:color-mix(in srgb,var(--dshpc-accent) 66%,#000000);\n --dshpc-danger-hover:color-mix(in srgb,var(--dshpc-danger) 78%,#ffffff);\n --dshpc-danger-active:color-mix(in srgb,var(--dshpc-danger) 64%,#ffffff);\n --dshpc-success-hover:color-mix(in srgb,var(--dshpc-success) 78%,#ffffff);\n --dshpc-success-active:color-mix(in srgb,var(--dshpc-success) 64%,#ffffff);\n --dshpc-warning-hover:color-mix(in srgb,var(--dshpc-warning) 78%,#ffffff);\n --dshpc-warning-active:color-mix(in srgb,var(--dshpc-warning) 64%,#ffffff);\n --dshpc-business-hover:color-mix(in srgb,var(--dshpc-business) 78%,#ffffff);\n --dshpc-business-active:color-mix(in srgb,var(--dshpc-business) 64%,#ffffff);\n /* 暗色 hover 掺白 14% / active 24%(对齐上面 2026-10-18 的加重拍板)。rgba 兜底行同上。 */\n --dshpc-hover:rgba(255,255,255,.14);\n --dshpc-active:rgba(255,255,255,.24);\n /* 分段轨道(暗色版):白 10%——比 hover 淡一档,选中亮片才跳得出。 */\n --dshpc-seg-track:rgba(255,255,255,.10);\n --dshpc-plate:var(--dsw-static-neutral-850,#212123);\n --dshpc-plate-hover:var(--dsw-static-neutral-800,#292929);\n --dshpc-icon-plate:rgba(255,255,255,.05);\n /* 暗色主题**反过来**:表头要比卡片面**亮**、比斑马纹再**浅一档**(用户:纯黑背景没法看)。 */\n --dshpc-head-bg:var(--dshpc-surface-2);\n /* 暗色底板**微亮**;hover **更亮**(原先 hover 取 plate-hover 反而更淡 ⇒ 鼠标移上去就没了)。 */\n --dshpc-chip-bg:rgba(255,255,255,.08);\n --dshpc-chip-bg-hover:rgba(255,255,255,.16);\n /* 暗色下蓝色要更亮、透明度略高才压得住深底。 */\n --dshpc-open-bg:rgba(96,165,250,.18);\n --dshpc-open-bg-soft:rgba(96,165,250,.08);\n --dshpc-card-hover:rgba(96,165,250,.13);\n /* 语义色**浅底**(深色版):用户嫌深色的绿 / 红「有点深」⇒ 压到 **5%**(浅色段是 8%),\n 更贴近面板底色、存在感更弱;块底与状态色竖条仍同源(竖条是实色,不受这条影响)。 */\n --dshpc-success-soft:color-mix(in srgb,var(--dshpc-success) 5%,transparent);\n --dshpc-warning-soft:color-mix(in srgb,var(--dshpc-warning) 5%,transparent);\n --dshpc-danger-soft:color-mix(in srgb,var(--dshpc-danger) 5%,transparent);\n --dshpc-business-soft:color-mix(in srgb,var(--dshpc-business) 5%,transparent);\n /* 「选中面」(深色版,2026-10-06):掺 **~40% 背景色**(--dshpc-surface-base)⇒ 无限接近页面背景的黑、\n 只比背景略深一点点(用户:深色下展开区压着任务透明绿会发灰,底色要尽量贴近背景才不显灰)。\n ⚠️ 深色下不能掺文字色 —— 那是白,会变亮,选中反而比本月日期浅。 */\n --dshpc-selected-bg:color-mix(in srgb,var(--dshpc-surface-1) 60%,var(--dshpc-surface-base));\n /* 任务日程页本月格的默认底(深色版,2026-10-06):深的、带点灰蓝的暗色(用户给的参考图 ≈ #23262e),\n 比原来的卡片面更沉、更偏蓝灰;选中格仍走 --dshpc-selected-bg(更暗一档),层级不变。 */\n --dshpc-cal-cell-bg:#23262e;\n /* 任务日程页本月格 hover 底(深色段,2026-10-06):原先走 --dshpc-hover(宿主浅色叠加)在深底上显得\n 「灰发亮」,不好看 ⇒ 换成更贴底的蓝调微亮(与 open-bg-soft 同族),hover 时不刺眼、又有反馈。 */\n --dshpc-cal-cell-hover:rgba(96,165,250,.12);\n /* 任务日程页展开面板底(深色段,2026-10-06 续):与原 selected-bg 暗值一致,深色 UI 不动 */\n --dshpc-cal-panel-bg:color-mix(in srgb,var(--dshpc-surface-1) 60%,var(--dshpc-surface-base));\n}\n";
|
|
38
|
+
//#endregion
|
|
39
|
+
//#region ../../node_modules/.pnpm/dsh-plugin-core@0.5.0_@babel+runtime@8.0.8_@codemirror+autocomplete@6.20.4_@codemirror+_bddbf1bc7ba0e94be71f734653121d0c/node_modules/dsh-plugin-core/dist/design/style-kit.js
|
|
40
|
+
/** 全生态统一的 CSS 变量前缀。 */
|
|
41
|
+
const CSS_PREFIX = "dshpc";
|
|
42
|
+
/** token 域固定名:变量定义必须先于消费它的规则出现。 */
|
|
43
|
+
const TOKENS_DOMAIN = "tokens";
|
|
44
|
+
/**
|
|
45
|
+
* 领一套本插件专属的样式设施。
|
|
46
|
+
*
|
|
47
|
+
* 为什么是工厂而不是模块级单例:单例只有一个固定 style id,
|
|
48
|
+
* 多个插件同处一页时会抢同一个 `<style>` 标签、后挂载的覆盖先挂载的(见需求文档 §5.2)。
|
|
49
|
+
*/
|
|
50
|
+
function createStyleKit(options) {
|
|
51
|
+
const { id } = options;
|
|
52
|
+
if (id === "") throw new Error("dsh-plugin-core/design: id 不能为空");
|
|
53
|
+
const tokensCss = TOKENS_CSS_TEMPLATE;
|
|
54
|
+
const domains = /* @__PURE__ */ new Map();
|
|
55
|
+
let tag = null;
|
|
56
|
+
let dirty = true;
|
|
57
|
+
const composeCss = () => {
|
|
58
|
+
const entries = [...domains.entries()];
|
|
59
|
+
entries.sort((a, b) => a[0] === TOKENS_DOMAIN ? -1 : b[0] === TOKENS_DOMAIN ? 1 : 0);
|
|
60
|
+
return entries.map(([, css]) => css).join("\n");
|
|
61
|
+
};
|
|
62
|
+
const flush = () => {
|
|
63
|
+
if (tag === null) return;
|
|
64
|
+
tag.textContent = composeCss();
|
|
65
|
+
dirty = false;
|
|
66
|
+
};
|
|
67
|
+
const ensureStyles = () => {
|
|
68
|
+
if (typeof document === "undefined") return;
|
|
69
|
+
if (tag === null || !tag.isConnected) {
|
|
70
|
+
const head = document.head;
|
|
71
|
+
if (head === null) return;
|
|
72
|
+
const found = document.getElementById(id);
|
|
73
|
+
if (found !== null) tag = found;
|
|
74
|
+
else {
|
|
75
|
+
const el = document.createElement("style");
|
|
76
|
+
el.id = id;
|
|
77
|
+
head.appendChild(el);
|
|
78
|
+
tag = el;
|
|
79
|
+
}
|
|
80
|
+
dirty = true;
|
|
81
|
+
}
|
|
82
|
+
if (dirty) flush();
|
|
83
|
+
};
|
|
84
|
+
const registerStyle = (domain, css) => {
|
|
85
|
+
if (domains.get(domain) === css) return;
|
|
86
|
+
domains.set(domain, css);
|
|
87
|
+
dirty = true;
|
|
88
|
+
if (tag?.isConnected === true) flush();
|
|
89
|
+
};
|
|
90
|
+
const dispose = () => {
|
|
91
|
+
if (tag?.isConnected === true) tag.remove();
|
|
92
|
+
tag = null;
|
|
93
|
+
domains.clear();
|
|
94
|
+
dirty = true;
|
|
95
|
+
};
|
|
96
|
+
return {
|
|
97
|
+
id,
|
|
98
|
+
tokensCss,
|
|
99
|
+
cssVar: (name) => `--${CSS_PREFIX}-${name}`,
|
|
100
|
+
registerStyle,
|
|
101
|
+
ensureStyles,
|
|
102
|
+
dispose,
|
|
103
|
+
applyStyle: (domain, css) => {
|
|
104
|
+
registerStyle(domain, css);
|
|
105
|
+
ensureStyles();
|
|
106
|
+
}
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
//#endregion
|
|
110
|
+
//#region ../../node_modules/.pnpm/dsh-plugin-core@0.5.0_@babel+runtime@8.0.8_@codemirror+autocomplete@6.20.4_@codemirror+_bddbf1bc7ba0e94be71f734653121d0c/node_modules/dsh-plugin-core/dist/ui/controls/segmented-css.generated.js
|
|
111
|
+
const SEGMENTED_CSS = "\n/* ── 分段控件 P2 ─────────────────────────────────────────────────────\n 结构照兄弟项目 dsh-task-dispatch-table 的 Segmented 皮肤(item 无边框、hover 只提亮文字),\n 前缀 / 变量名换成本仓口径。用户额外要的两处(兄弟没有):weekday 方块间隔(现为 2px);段内中性计数 __count。\n ⚠️ 2026-10-19 两次误判均已澄清:① 「宿主只认单行 CSS」——假,多行一直正常;\n ② 「宿主吃掉 token 块之后第一条规则」——也假,真因是 tokens 模板字符串结尾多了一个反斜杠,\n 注入文本里留下字面反引号,把紧随其后的那条规则的选择器污染掉了(见 dsh-host.md §9)。\n 样式照常多行书写,不必压行;也不需要任何「牺牲规则」。 */\n/* 外观只有一套(2026-10-26):原 variant 的 default / inset 两档在 CSS 里只差 1px 内距,\n 且 default 比文档承诺矮 2px,却让下游以为「有得选」而反复对图 ⇒ 整轴删除。\n padding 3px 是尺寸契约的一部分:item 高度 = 控制高 − 6px,加起来正好 24 / 28 / 32。 */\n.dshpc-seg{display:inline-flex;align-items:center;gap:2px;padding:3px;border-radius:var(--dshpc-radius-md);--seg-thumb:var(--dshpc-surface-raised);background:var(--dshpc-seg-track);}\n.dshpc-seg__item{appearance:none;display:inline-flex;align-items:center;gap:4px;box-sizing:border-box;height:calc(var(--dshpc-control-h-sm) - 6px);padding:0 12px;border:0;border-radius:var(--dshpc-radius-sm);background:transparent;color:var(--dshpc-fg-2);font-family:inherit;font-size:var(--dshpc-font-xs);font-weight:500;white-space:nowrap;cursor:pointer;flex:none;transition:color var(--dshpc-dur-fast) var(--dshpc-ease),background-color var(--dshpc-dur-fast) var(--dshpc-ease),box-shadow var(--dshpc-dur-fast) var(--dshpc-ease);}\n.dshpc-seg--md .dshpc-seg__item{height:calc(var(--dshpc-control-h-md) - 6px);}\n.dshpc-seg--lg .dshpc-seg__item{height:calc(var(--dshpc-control-h-lg) - 6px);}\n.dshpc-seg__item:hover:not([aria-pressed='true']):not(:disabled){color:var(--dshpc-fg);}\n.dshpc-seg__item[aria-pressed='true']{background:var(--seg-thumb);box-shadow:var(--dshpc-shadow-raised);color:var(--dshpc-fg);font-weight:600;}\n.dshpc-seg__item:focus-visible{outline:2px solid var(--dshpc-focus);outline-offset:-2px;}\n.dshpc-seg__item:disabled{cursor:default;opacity:.4;}\n/* 段内角标(如「异常」的数量):语义色实面 + 反白字,0 由组件侧不渲染。必须是正圆(用户 2026-10-03)。 */\n.dshpc-seg__badge{display:inline-flex;align-items:center;justify-content:center;flex:none;width:16px;height:16px;padding:0;overflow:hidden;border-radius:50%;background:var(--dshpc-danger);color:var(--dshpc-on-signal);font-size:10px;line-height:16px;font-weight:500;font-variant-numeric:tabular-nums;}\n/* 段内中性计数(如筛选条「全部 11」):纯文字、无底无边(对齐 task-ledger .dtl-seg__num 拍板口径);0 由组件侧不渲染。 */\n.dshpc-seg__count{display:inline;flex:none;margin-left:3px;padding:0;border:0;border-radius:0;background:none;color:var(--dshpc-fg-3);font-size:10px;line-height:1;font-weight:400;font-variant-numeric:tabular-nums;}\n/* block:撑满父宽(表单行用),各段等分 */\n.dshpc-seg--block{display:flex;width:100%;}\n.dshpc-seg--block .dshpc-seg__item{flex:1 1 auto;justify-content:center;}\n/* weekday:星期多选方块。基础插件的特殊化定制(用户 2026-10-01:原 WeekdayPicker 即「蓝底 + 近似方形」):\n 每格正方形(宽 = 段高)、选中品牌蓝反白字、**无外描边**(2026-10-18 重申)、\n 方块之间间距 gap:2px(2026-10-20 用户定稿:方块改小后 6px 显得太宽。10-18 曾从 2px 放宽到 6px,\n 两次都是用户拍板 —— 别自作主张改回去)。 */\n.dshpc-seg--weekday{--seg-track:var(--dshpc-seg-track);gap:2px;border:0;padding:3px;background:var(--seg-track);}\n.dshpc-seg--weekday .dshpc-seg__item{width:calc(var(--dshpc-control-h-lg) - 8px);padding:0;justify-content:center;}\n.dshpc-seg--weekday .dshpc-seg__item[aria-pressed='true']{background:var(--dshpc-business);color:var(--dshpc-fg-inverse);box-shadow:var(--dshpc-shadow-raised);}\n\n/* ── 单选滑动块(2026-10-26 用户:点选后选中底应「滑过去」,不是旧段消失、新段直接亮)。\n 结构 = 一块绝对定位的共用底 + 各段透明;位置/尺寸由组件量出后内联,这里只管外观与过渡。\n --slide 只在单选挂上:多选(如星期)每段各自着色,没有唯一滑块可滑,保持原样。 */\n.dshpc-seg--slide{position:relative;}\n.dshpc-seg--slide .dshpc-seg__item{position:relative;z-index:1;}\n.dshpc-seg--slide .dshpc-seg__item[aria-pressed='true']{background:transparent;box-shadow:none;}\n.dshpc-seg__thumb{position:absolute;z-index:0;border-radius:var(--dshpc-radius-sm);background:var(--seg-thumb);box-shadow:var(--dshpc-shadow-raised);pointer-events:none;transition:left var(--dshpc-dur) var(--dshpc-ease),top var(--dshpc-dur) var(--dshpc-ease),width var(--dshpc-dur) var(--dshpc-ease),height var(--dshpc-dur) var(--dshpc-ease);}\n.dshpc-seg--weekday.dshpc-seg--slide .dshpc-seg__thumb{background:var(--dshpc-business);}\n\n/* ── bordered 外框(2026-10-20 用户要的第二种模式):**只在最外面套一圈 1px 描边**,\n 里面一概不动 —— 选中片的填充色 / 阴影 / 文字色全部保持原样(weekday 的蓝面照旧),\n 这里不写任何针对 __item 的规则。\n 总高必须与无框版逐像素一致:border 1px×2 由 padding 各让 1px 抵消(3 → 2);\n weekday 自己声明的 3px 在文件更后面,靠双类选择器压回 2px。 */\n.dshpc-seg--bordered{border:1px solid var(--dshpc-border);padding:2px;}\n.dshpc-seg--bordered.dshpc-seg--weekday{padding:2px;}\n\n@media (prefers-reduced-motion: reduce){.dshpc-seg__item{transition:none;}.dshpc-seg__thumb{transition:none;}}\n";
|
|
112
|
+
//#endregion
|
|
113
|
+
//#region ../../node_modules/.pnpm/dsh-plugin-core@0.5.0_@babel+runtime@8.0.8_@codemirror+autocomplete@6.20.4_@codemirror+_bddbf1bc7ba0e94be71f734653121d0c/node_modules/dsh-plugin-core/dist/ui/controls/button-css.generated.js
|
|
114
|
+
const BUTTON_CSS = "\n/* ── 按钮 / 图标钮 P2 ───────────────────────────────────────────────────\n 与 Segmented 同一条高度纪律:--dshpc-control-h-sm(24) / -md(28) / -lg(32),\n 有边框的 variant 用 1px 真边框 + 内部 padding 补回,**有边 / 无边同高**。\n\n 三条受控轴(2026-10-19 重写,对齐主流 UI 框架的分类口径):\n · variant —— 外观档 = 形态 + 语义色,共 10 档:\n primary / secondary / outline / ghost / danger / success / warning / info /\n danger-outline(红字描边)/ link(行内链接)\n · size —— sm / md / lg\n · block —— 撑满父宽\n 每一档**只填 5 个局部变量**(--btn-bg / -fg / -border / -bg-hover / -bg-active),\n 结构与交互只有上面这一份;任何档位都不许再写一遍 display/height/padding。\n 自定义颜色(Button 的 color 参数)同样只覆盖这 5 个变量(token 覆盖,不是新皮肤)。\n\n ⚠️ hover 不再用 opacity 压一层(用户 2026-10-19:「黑色和红色的按钮移上去变化太小,\n 完全感觉不到颜色变了」)⇒ 走 --dshpc-*-hover / -active 的明确混色,见 tokens-css.ts。 */\n.dshpc-btn{--btn-bg:transparent;--btn-fg:var(--dshpc-fg);--btn-border:transparent;--btn-pad:12px;\n --btn-bg-hover:var(--dshpc-hover);--btn-bg-active:var(--dshpc-active);--btn-fg-hover:var(--btn-fg);\n appearance:none;display:inline-flex;align-items:center;justify-content:center;gap:6px;\n box-sizing:border-box;border:1px solid var(--btn-border);border-radius:var(--dshpc-radius-md);\n background-color:var(--btn-bg);color:var(--btn-fg);font-family:inherit;font-weight:500;white-space:nowrap;cursor:pointer;\n transition:background-color var(--dshpc-dur-fast) var(--dshpc-ease),border-color var(--dshpc-dur-fast) var(--dshpc-ease),color var(--dshpc-dur-fast) var(--dshpc-ease),box-shadow var(--dshpc-dur-fast) var(--dshpc-ease),transform var(--dshpc-dur-fast) var(--dshpc-ease);}\n.dshpc-btn--sm{--btn-pad:10px;height:var(--dshpc-control-h-sm);padding:0 var(--btn-pad);font-size:var(--dshpc-font-sm);line-height:1;}\n.dshpc-btn--md{--btn-pad:12px;height:var(--dshpc-control-h-md);padding:0 var(--btn-pad);font-size:var(--dshpc-font-md);line-height:1;}\n.dshpc-btn--lg{--btn-pad:14px;height:var(--dshpc-control-h-lg);padding:0 var(--btn-pad);font-size:var(--dshpc-font-md);line-height:1;}\n/* block:撑满父宽(表单底栏 / 抽屉底部的主操作) */\n.dshpc-btn--block{display:flex;width:100%;}\n/* block + 前置图标 ⇒ 文字视觉居中(2026-10-19 用户点名):\n 内容组 [图标 + 间距 + 文字] 整体在盒内居中时,**文字**的中心会被图标推右半格。\n 把右内边距补上「图标宽 + 间距」,可用盒随之左移同量 ⇒ 文字落回视觉中心,图标贴左侧。\n 图标宽按 1.2em 估(官方图标 14/16px vs 字号 12/13px),em 随字号档自动缩放。 */\n.dshpc-btn--block.dshpc-btn--icon-start{padding-right:calc(var(--btn-pad) + 1.2em + 6px);}\n.dshpc-btn__icon,.dshpc-btn__icon-end{display:inline-flex;align-items:center;justify-content:center;flex:none;line-height:0;}\n.dshpc-btn__icon svg,.dshpc-btn__icon-end svg{display:block;margin:0;}\n/* loading:不换 DOM 结构,只在文案前插一个同色小圈。\n ⚠️ 2026-10-20 改画法:原来是 border:1.5px 加 border-radius:999px 画的环 —— 真机实测 computed\n radius 就是 999px、宽高都是 12px(没被任何样式覆盖),看着却\"像圆角方\",原因是**次像素边框\n (1.5px)在 12px 这么小的圆上被抗锯齿插值拉毛**。改用 SVG 矢量弧:任意 DPR 下都是真圆。 */\n.dshpc-btn__spinner{display:block;flex:none;width:12px;height:12px;\n animation:dshpc-btn-spin .7s linear infinite;}\n/* shortcut: 12px 是固定值,不随按钮字号缩放;要更大就改这一处。 */\n@keyframes dshpc-btn-spin{to{transform:rotate(360deg)}}\n\n/* 交互态:颜色变化写在变量上 ⇒ 所有档位一次生效,且变化幅度由 token 决定(够明显) */\n.dshpc-btn:hover:not(:disabled){background-color:var(--btn-bg-hover);color:var(--btn-fg-hover);}\n.dshpc-btn:active:not(:disabled){background-color:var(--btn-bg-active);transform:translateY(1px);}\n.dshpc-btn:focus-visible{outline:2px solid var(--dshpc-focus);outline-offset:2px;}\n.dshpc-btn:disabled{cursor:default;opacity:.5;}\n\n.dshpc-btn--primary{--btn-bg:var(--dshpc-accent);--btn-fg:var(--dshpc-fg-inverse);\n --btn-bg-hover:var(--dshpc-accent-hover);--btn-bg-active:var(--dshpc-accent-active);}\n/* secondary:中性实心(灰面),用于「取消 / 次要」这类与主操作并排的按钮 */\n.dshpc-btn--secondary{--btn-bg:var(--dshpc-hover);--btn-fg:var(--dshpc-fg);\n --btn-bg-hover:var(--dshpc-active);--btn-bg-active:var(--dshpc-active);}\n.dshpc-btn--outline{--btn-bg:var(--dshpc-surface-1);--btn-border:var(--dshpc-border-strong);\n --btn-bg-hover:var(--dshpc-hover);--btn-bg-active:var(--dshpc-active);}\n.dshpc-btn--ghost{--btn-fg:var(--dshpc-fg-2);--btn-fg-hover:var(--dshpc-fg);\n --btn-bg-hover:var(--dshpc-hover);--btn-bg-active:var(--dshpc-active);}\n.dshpc-btn--danger{--btn-bg:var(--dshpc-danger);--btn-fg:var(--dshpc-on-signal);\n --btn-bg-hover:var(--dshpc-danger-hover);--btn-bg-active:var(--dshpc-danger-active);}\n.dshpc-btn--success{--btn-bg:var(--dshpc-success);--btn-fg:var(--dshpc-on-signal);\n --btn-bg-hover:var(--dshpc-success-hover);--btn-bg-active:var(--dshpc-success-active);}\n.dshpc-btn--warning{--btn-bg:var(--dshpc-warning);--btn-fg:var(--dshpc-on-warning);\n --btn-bg-hover:var(--dshpc-warning-hover);--btn-bg-active:var(--dshpc-warning-active);}\n.dshpc-btn--info{--btn-bg:var(--dshpc-business);--btn-fg:var(--dshpc-on-signal);\n --btn-bg-hover:var(--dshpc-business-hover);--btn-bg-active:var(--dshpc-business-active);}\n/* danger-outline:红字描边(破坏性次要操作,如卡片上的「删除」)。\n ⚠️ 旧修饰类 danger-ink 保留为别名(消费方可能还在挂),两者同一套皮肤。 */\n.dshpc-btn--danger-outline,.dshpc-btn--danger-ink{--btn-border:var(--dshpc-danger);--btn-fg:var(--dshpc-danger);\n --btn-fg-hover:var(--dshpc-danger);--btn-bg-hover:var(--dshpc-danger-soft);--btn-bg-active:var(--dshpc-danger-soft);}\n/* link:行内文字链接型(会话 / 产出文件名),无底无边、品牌蓝、hover 下划线 */\n.dshpc-btn--link{--btn-fg:var(--dshpc-link);--btn-fg-hover:var(--dshpc-link);\n --btn-bg-hover:transparent;--btn-bg-active:transparent;\n height:auto;padding:0;border:0;background:none;font-weight:400;text-align:left;}\n.dshpc-btn--link:hover:not(:disabled){text-decoration:underline;}\n\n/* 图标钮:纯图标,方形;尺寸档的宽高与同档文字按钮等高 */\n.dshpc-iconbtn{appearance:none;display:inline-flex;align-items:center;justify-content:center;box-sizing:border-box;\n border:1px solid transparent;border-radius:var(--dshpc-radius-sm);background:transparent;color:var(--dshpc-fg-2);\n font-family:inherit;cursor:pointer;flex:none;\n transition:background-color var(--dshpc-dur-fast) var(--dshpc-ease),border-color var(--dshpc-dur-fast) var(--dshpc-ease),color var(--dshpc-dur-fast) var(--dshpc-ease),opacity var(--dshpc-dur-fast) var(--dshpc-ease);}\n.dshpc-iconbtn--sm{width:var(--dshpc-control-h-sm);height:var(--dshpc-control-h-sm);font-size:var(--dshpc-font-sm);}\n.dshpc-iconbtn--md{width:var(--dshpc-control-h-md);height:var(--dshpc-control-h-md);font-size:var(--dshpc-font-md);}\n.dshpc-iconbtn--lg{width:var(--dshpc-control-h-lg);height:var(--dshpc-control-h-lg);font-size:var(--dshpc-font-md);}\n.dshpc-iconbtn--plain{color:var(--dshpc-fg-2);}\n.dshpc-iconbtn--outline{background:var(--dshpc-surface-1);border-color:var(--dshpc-border);color:var(--dshpc-fg-2);}\n.dshpc-iconbtn--danger{color:var(--dshpc-danger);}\n.dshpc-iconbtn:hover:not(:disabled){background:var(--dshpc-hover);color:var(--dshpc-fg);}\n.dshpc-iconbtn--danger:hover:not(:disabled){background:var(--dshpc-danger-soft);color:var(--dshpc-danger);}\n.dshpc-iconbtn:focus-visible{outline:2px solid var(--dshpc-focus);outline-offset:2px;}\n.dshpc-iconbtn:disabled{cursor:default;opacity:.4;}\n\n/* ── 行式文件按钮(图标 + 文件名)P2:**全站唯一实现**(2026-10-04 收编)──────────\n 用途:「产出物 / 附件」那种**一行一个文件**的清单项(基础信息右栏产出物清单、附件区、\n 执行记录页的展开区)。平时透明、**鼠标移上去才出浅底**(沿用用户 2026-10-03 定的观感)。\n 两个形态修饰类:\n --block 撑满父宽(清单里一项一行)\n --inline 内容宽(跟在文字后头,如附件行)\n 收编原因:这份皮肤此前只写在 task-list.tsx 的 TASK_LIST_CSS 里(旧名 .dshpc-info-out),\n 执行记录页展开区要用同一种观感 ⇒ 上提基础层,避免再出现「各写一份外观」(同名不同皮的坑刚踩过)。 */\n.dshpc-filechip{appearance:none;-webkit-appearance:none;border:0;border-radius:var(--dshpc-radius-xs);\n background:transparent;color:var(--dshpc-fg);font:inherit;text-align:left;cursor:pointer;min-width:0;\n transition:background-color var(--dshpc-dur) var(--dshpc-ease);}\n.dshpc-filechip:hover:not(:disabled){background:var(--dshpc-chip-bg);}\n.dshpc-filechip:focus-visible{outline:2px solid var(--dshpc-focus);outline-offset:1px;}\n.dshpc-filechip:disabled{cursor:default;background:transparent;color:var(--dshpc-fg-3);}\n.dshpc-filechip--block{display:flex;align-items:center;gap:6px;width:100%;box-sizing:border-box;\n padding:4px 6px;font-size:var(--dshpc-font-xs);}\n.dshpc-filechip--inline{display:inline-flex;align-items:center;gap:4px;padding:2px 6px;font-size:var(--dshpc-font-sm);}\n\n@media (prefers-reduced-motion: reduce){.dshpc-btn,.dshpc-iconbtn,.dshpc-filechip{transition:none;}}\n";
|
|
115
|
+
//#endregion
|
|
116
|
+
//#region ../../node_modules/.pnpm/dsh-plugin-core@0.5.0_@babel+runtime@8.0.8_@codemirror+autocomplete@6.20.4_@codemirror+_bddbf1bc7ba0e94be71f734653121d0c/node_modules/dsh-plugin-core/dist/ui/controls/field-css.generated.js
|
|
117
|
+
const FIELD_CSS = "\n/* ── 字段 + 问号提示(hint 参数内置) ──────────────────────────────────── */\n/* 控件 + FieldHint 同一行;hint 版由组件自己包,调用方只传 hint 字符串。\n 铺满型控件(input/textarea)进包后改吃 flex 弹性,让位给问号。 */\n.dshpc-fieldwrap{display:flex;align-items:center;gap:6px;min-width:0;max-width:100%;}\n.dshpc-fieldwrap--inline{display:inline-flex;}\n.dshpc-fieldwrap > .dshpc-input,.dshpc-fieldwrap > .dshpc-textarea{flex:1 1 auto;width:auto;min-width:0;}\n/* 多行输入:问号钉在**右下角**(2026-10-20 用户:不要垂直居中),文本区底部留出它的位置。\n ⚠️ 这一档必须把 textarea 的宽度还回去(上面那条 flex 让位规则会把它缩窄)。 */\n.dshpc-fieldwrap--block{position:relative;display:block;}\n.dshpc-fieldwrap--block > .dshpc-textarea{width:100%;padding-bottom:24px;}\n.dshpc-fieldwrap--block > .dshpc-hint{position:absolute;right:8px;bottom:6px;}\n\n/* ── 输入类 P3 ────────────────────────────────────────────────────────── */\n/* 默认铺满容器(width:100%,与 .dshpc-textarea 同口径):input 原生按 size 属性取内在宽,\n 不铺满 ⇒ 调用方套定宽壳时会「右边空一截、看着没贴右」(2026-10-20 用户抓的 bug)。\n 要定宽由调用方在外面套壳控制(如 192px 搜索槽)。 */\n.dshpc-input{display:block;width:100%;box-sizing:border-box;border:1px solid var(--dshpc-border);border-radius:var(--dshpc-radius-md);\n background:var(--dshpc-surface-1);color:var(--dshpc-fg);font-family:inherit;outline:none;\n transition:border-color var(--dshpc-dur-fast) var(--dshpc-ease),box-shadow var(--dshpc-dur-fast) var(--dshpc-ease);}\n.dshpc-input--sm{height:var(--dshpc-control-h-sm);padding:0 8px;font-size:var(--dshpc-font-sm);line-height:var(--dshpc-line-sm);}\n.dshpc-input--md{height:var(--dshpc-control-h-md);padding:0 10px;font-size:var(--dshpc-font-md);line-height:var(--dshpc-line-md);}\n.dshpc-input--lg{height:var(--dshpc-control-h-lg);padding:0 12px;font-size:var(--dshpc-font-md);line-height:var(--dshpc-line-md);}\n.dshpc-input::placeholder{color:var(--dshpc-fg-dim);}\n.dshpc-input:focus{border-color:var(--dshpc-focus);box-shadow:0 0 0 1px var(--dshpc-focus);}\n.dshpc-input--error{border-color:var(--dshpc-danger);}\n.dshpc-input:disabled{cursor:default;opacity:.5;}\n\n.dshpc-pfx{display:inline-flex;align-items:center;box-sizing:border-box;overflow:hidden;\n border:1px solid var(--dshpc-border);border-radius:var(--dshpc-radius-md);background:var(--dshpc-surface-1);color:var(--dshpc-fg);}\n.dshpc-pfx--sm{height:var(--dshpc-control-h-sm);}\n.dshpc-pfx--md{height:var(--dshpc-control-h-md);}\n.dshpc-pfx--lg{height:var(--dshpc-control-h-lg);}\n/* md / lg 档字号跟档走(与同档下拉同字号):此前写死 sm(12px),同排下拉是 13px ⇒ 显得「input 字小」。 */\n.dshpc-pfx--md .dshpc-pfx__label,.dshpc-pfx--lg .dshpc-pfx__label{font-size:var(--dshpc-font-md);line-height:var(--dshpc-line-md);}\n.dshpc-pfx--md .dshpc-pfx__input,.dshpc-pfx--lg .dshpc-pfx__input{font-size:var(--dshpc-font-md);line-height:var(--dshpc-line-md);}\n.dshpc-pfx--error{border-color:var(--dshpc-danger);}\n.dshpc-pfx:focus-within{border-color:var(--dshpc-focus);box-shadow:0 0 0 1px var(--dshpc-focus);}\n.dshpc-pfx__label{padding:0 8px;color:var(--dshpc-fg-2);font-size:var(--dshpc-font-sm);line-height:var(--dshpc-line-sm);white-space:nowrap;border-right:1px solid var(--dshpc-border);}\n.dshpc-pfx__input{flex:1 1 auto;min-width:0;height:100%;padding:0 8px;border:0;background:transparent;color:var(--dshpc-fg);\n font-family:inherit;font-size:var(--dshpc-font-sm);line-height:var(--dshpc-line-sm);outline:none;}\n.dshpc-pfx__input::placeholder{color:var(--dshpc-fg-dim);}\n\n.dshpc-num{display:inline-flex;align-items:center;justify-content:space-between;box-sizing:border-box;overflow:hidden;\n border:1px solid var(--dshpc-border);border-radius:var(--dshpc-radius-md);background:var(--dshpc-surface-1);color:var(--dshpc-fg);}\n/* 中段:数字 + 后缀成组居中;容器被消费端拉宽时吃掉全部余量,两端 − / + 因此钉死在左右边缘。 */\n.dshpc-num__mid{display:flex;align-items:center;justify-content:center;flex:1 1 auto;min-width:0;}\n.dshpc-num--sm{height:var(--dshpc-control-h-sm);}\n.dshpc-num--md{height:var(--dshpc-control-h-md);}\n.dshpc-num--lg{height:var(--dshpc-control-h-lg);}\n.dshpc-num--md .dshpc-num__input,.dshpc-num--lg .dshpc-num__input{font-size:var(--dshpc-font-md);line-height:var(--dshpc-line-md);}\n.dshpc-num--md .dshpc-num__suffix,.dshpc-num--lg .dshpc-num__suffix{font-size:var(--dshpc-font-md);}\n.dshpc-num--disabled{opacity:.5;}\n/* 焦点态与 Input 同款(2026-10-20 用户:数字框里点进去没有蓝框):内层 input 无边框,\n 焦点状态画在整个步进控件外框上。 */\n.dshpc-num:focus-within{border-color:var(--dshpc-focus);box-shadow:0 0 0 1px var(--dshpc-focus);}\n.dshpc-num__input{width:36px;height:100%;padding:0 2px;border:0;background:transparent;color:var(--dshpc-fg);\n font-family:inherit;font-size:var(--dshpc-font-sm);line-height:var(--dshpc-line-sm);text-align:center;outline:none;}\n.dshpc-num__suffix{padding:0 6px;color:var(--dshpc-fg-2);font-size:var(--dshpc-font-sm);white-space:nowrap;}\n.dshpc-num .dshpc-iconbtn{border-radius:0;color:var(--dshpc-fg-2);flex:none;}\n\n/* 官方 Switch 包装统一:选中 = success 绿。\n (合并原先 task-editor-css / task-list 两处就地覆盖;选择器带包装类 + role,特异性高于官方。) */\n.dshpc-switch button[role='switch'][aria-checked='true']{background:var(--dshpc-success);}\n\n/* 多行文本输入(提示词等,P3):**边框 / 圆角 / 底 / 焦点态与 Input 同一套口径**(用户 2026-10-20:\n 「多行输入应该和 input 的边儿是一个道理,包括圆角在内,都是一个东西」)。\n ⚠️ 旧意图「卡内无边框、视觉重心在整张卡上」已作废 —— 现在它就是一只带框的多行输入框。\n (从 task-editor-css 的 .dshpc-ed-prompt 上提而来;业务文件不再自写 textarea 皮肤。) */\n.dshpc-textarea{display:block;width:100%;box-sizing:border-box;min-height:132px;padding:8px 12px;\n border:1px solid var(--dshpc-border);border-radius:var(--dshpc-radius-md);outline:none;\n background:var(--dshpc-surface-1);color:var(--dshpc-fg);font-family:inherit;font-size:var(--dshpc-font-lg);line-height:1.6;resize:vertical;\n transition:border-color var(--dshpc-dur-fast) var(--dshpc-ease),box-shadow var(--dshpc-dur-fast) var(--dshpc-ease);}\n.dshpc-textarea::placeholder{color:var(--dshpc-fg-dim);}\n.dshpc-textarea:focus{border-color:var(--dshpc-focus);box-shadow:0 0 0 1px var(--dshpc-focus);}\n/* 校验不通过:与 Input 一致,走边框描红(旧版是 box-shadow 描红盒,与 Input 不同口径) */\n.dshpc-textarea--error{border-color:var(--dshpc-danger);}\n.dshpc-textarea:disabled{cursor:default;opacity:.5;}\n@media (prefers-reduced-motion: reduce){.dshpc-textarea{transition:none;}}\n\n/* 拖拽分隔条(编辑分栏 / 预览 dock 共用,U20 #3):6px 命中区,col-resize,不画线,hover/按下浮出浅带。\n 具体 z-index 由 .dshpc-ed-resizer / .dshpc-sv-resizer 各自补。 */\n.dshpc-resizer{position:absolute;top:0;bottom:0;left:0;width:6px;cursor:col-resize;background:0 0;touch-action:none;user-select:none;}\n.dshpc-resizer:hover,.dshpc-resizer:active{background:var(--dshpc-hover,rgba(38,49,72,.06));}\n\n@media (prefers-reduced-motion: reduce){.dshpc-input,.dshpc-pfx{transition:none;}}\n";
|
|
118
|
+
//#endregion
|
|
119
|
+
//#region ../../node_modules/.pnpm/dsh-plugin-core@0.5.0_@babel+runtime@8.0.8_@codemirror+autocomplete@6.20.4_@codemirror+_bddbf1bc7ba0e94be71f734653121d0c/node_modules/dsh-plugin-core/dist/ui/controls/loading-css.generated.js
|
|
120
|
+
const LOADING_CSS = "\n/* 运行中 / loading 的活动指示:三个小方块依次脉动。 */\n@keyframes dshpc-run-block { 0%, 80%, 100% { opacity: 0.25; transform: scale(0.8) } 40% { opacity: 1; transform: scale(1) } }\n.dshpc-run-blocks { display: inline-flex; align-items: center; gap: 3px; }\n.dshpc-run-blocks > i { width: 5px; height: 5px; border-radius: 1px; background: currentColor; animation: dshpc-run-block 1.2s ease-in-out infinite; }\n.dshpc-run-blocks > i:nth-child(2) { animation-delay: 0.15s; }\n.dshpc-run-blocks > i:nth-child(3) { animation-delay: 0.3s; }\n@media (prefers-reduced-motion: reduce) { .dshpc-run-blocks > i { animation: none; opacity: 1; } }\n";
|
|
121
|
+
//#endregion
|
|
122
|
+
//#region ../../node_modules/.pnpm/dsh-plugin-core@0.5.0_@babel+runtime@8.0.8_@codemirror+autocomplete@6.20.4_@codemirror+_bddbf1bc7ba0e94be71f734653121d0c/node_modules/dsh-plugin-core/dist/ui/controls/back-to-top-css.generated.js
|
|
123
|
+
const BACK_TO_TOP_CSS = "\n/* 回到顶部悬浮钮:圆钮、实面、投影;默认隐身,滚过阈值加 .is-visible 才显形。\n 横向 left 由组件按主内容列右缘实时算出(贴在其右侧外侧),不写死。 */\n.dshpc-backtotop{\n position:fixed;\n bottom:var(--dshpc-space-4);\n z-index:var(--dshpc-z-dock);\n width:44px;height:44px;\n display:inline-flex;align-items:center;justify-content:center;\n padding:0;margin:0;\n box-sizing:border-box;\n border:1px solid var(--dshpc-border);\n border-radius:50%;\n background:var(--dshpc-solid);\n color:var(--dshpc-on-solid);\n box-shadow:var(--dshpc-shadow-2);\n cursor:pointer;\n opacity:0;\n transform:translateY(8px) scale(.92);\n transition:opacity var(--dshpc-dur) var(--dshpc-ease),\n transform var(--dshpc-dur) var(--dshpc-ease),\n background-color var(--dshpc-dur-fast) var(--dshpc-ease);\n pointer-events:none;\n}\n.dshpc-backtotop.is-visible{opacity:1;transform:translateY(0) scale(1);pointer-events:auto;}\n.dshpc-backtotop:hover{background:var(--dshpc-hover);}\n.dshpc-backtotop:active{background:var(--dshpc-active);}\n.dshpc-backtotop:focus-visible{outline:2px solid var(--dshpc-focus);outline-offset:2px;}\n@media (prefers-reduced-motion: reduce){\n .dshpc-backtotop{transition:opacity var(--dshpc-dur-fast) linear;transform:none;}\n}\n";
|
|
124
|
+
//#endregion
|
|
125
|
+
//#region ../../node_modules/.pnpm/dsh-plugin-core@0.5.0_@babel+runtime@8.0.8_@codemirror+autocomplete@6.20.4_@codemirror+_bddbf1bc7ba0e94be71f734653121d0c/node_modules/dsh-plugin-core/dist/ui/controls/hint-css.generated.js
|
|
126
|
+
const HINT_CSS = "\n/* ── 问号提示 P4(用户 2026-10-18:对齐真实插件 HelpButton——**带圈的问号图标**)──\n 本体 14px 细圈 + 圈内 ?,颜色 fg-3、hover 只提亮不加底(与 dshpc-ed-help 同规矩)。\n 气泡不在本文件:2026-10-19 用户拍板「问号必须用官方 Tooltip 那一个」⇒ 气泡由注入的\n 官方组件渲染(src/ui/tooltip.ts),这里只管问号图标本身。 */\n.dshpc-hint{display:inline-flex;align-items:center;justify-content:center;flex:none;\n box-sizing:border-box;width:14px;height:14px;padding:0;border:1px solid currentColor;border-radius:50%;background:transparent;\n color:var(--dshpc-fg-3);font-family:inherit;font-size:8px;font-weight:600;line-height:12px;cursor:help;vertical-align:middle;\n transition:color var(--dshpc-dur-fast) var(--dshpc-ease);}\n.dshpc-hint:hover,.dshpc-hint:focus-visible{color:var(--dshpc-fg);background:0 0;}\n.dshpc-hint:focus-visible{outline:2px solid var(--dshpc-focus);outline-offset:1px;}\n";
|
|
127
|
+
//#endregion
|
|
128
|
+
//#region ../../node_modules/.pnpm/dsh-plugin-core@0.5.0_@babel+runtime@8.0.8_@codemirror+autocomplete@6.20.4_@codemirror+_bddbf1bc7ba0e94be71f734653121d0c/node_modules/dsh-plugin-core/dist/ui/controls/datetime-css.generated.js
|
|
129
|
+
const DATETIME_CSS = "/* 日期时间选择器(DateTimePicker)。类名 dshpc-dt-*;配色只吃 token,明暗随 token 切换。\n 结构:触发器(range = 一个整条:两个日期区 + 样式画的灰隔条;single = 单日期)→ 浮层\n (两个独立端框 + 两块独立日历 + 底部动作)。\n 浮层行为与 Picker 一致:portal 到 body、贴边翻转、点外关闭、无遮罩。 */\n.dshpc-dt{position:relative;display:inline-block;font-size:13px;line-height:20px}\n.dshpc-dt__trigger{\n display:inline-flex;align-items:center;justify-content:space-between;gap:6px;\n max-width:100%;height:var(--dshpc-control-h-md);padding:0 8px;\n color:var(--dshpc-fg);background:var(--dshpc-surface-1);\n border:1px solid var(--dshpc-border);border-radius:var(--dshpc-radius-md);cursor:pointer;\n}\n.dshpc-dt__trigger--sm{height:var(--dshpc-control-h-sm);font-size:12px}\n.dshpc-dt__trigger--lg{height:var(--dshpc-control-h-lg)}\n.dshpc-dt__trigger:disabled{color:var(--dshpc-fg-dim);cursor:not-allowed;opacity:.7}\n/* 焦点与基础 Input 完全同款(点击即蓝描边 + 1px 光环)。 */\n.dshpc-dt__trigger:focus{border-color:var(--dshpc-focus);box-shadow:0 0 0 1px var(--dshpc-focus)}\n.dshpc-dt__trigger-label{flex:1 1 auto;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;text-align:left;font-variant-numeric:tabular-nums}\n.dshpc-dt__trigger-label--empty{color:var(--dshpc-fg-dim)}\n.dshpc-dt__cal{flex:none;color:var(--dshpc-fg-3)}\n/* range 触发器:一个整条里两个日期区 + 样式画出来的灰隔条(左右两条竖边),点整条都展开。 */\n/* 组撑满触发器内容高度,隔条才能上下顶到 border。 */\n.dshpc-dt__pair-group{flex:1 1 auto;min-width:0;align-self:stretch;display:flex;align-items:center;gap:8px}\n/* 两个日期区平分(flex:1 1 0):开始 / 结束永远一样宽,不随内容偏袒。 */\n.dshpc-dt__pair-date{flex:1 1 0;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-variant-numeric:tabular-nums}\n.dshpc-dt__pair-date--empty{color:var(--dshpc-fg-dim)}\n/* 隔条:上下顶到触发器 border(与边框连起来),中间隔出一块;块里放「到」的符号(-,用户 2026-10-24 拍板)。 */\n.dshpc-dt__pair-sep{\n flex:none;align-self:stretch;width:22px;margin:0;\n display:inline-flex;align-items:center;justify-content:center;\n background:var(--dshpc-surface-sunken);\n border-left:1px solid var(--dshpc-border);border-right:1px solid var(--dshpc-border);\n color:var(--dshpc-fg-3);font-size:12px;line-height:1;\n}\n/* 默认宽:**固定**(选中前后不变),数值对照参考图实测(2x 屏,换算 CSS px)后\n 统一 -6px(用户 2026-10-24:实测值留得偏多):\n 单值 day 128 / 时·分 153.2 / 秒 174.8;区间 day 269 / 分 341.4 / 秒 377.6。\n ch = 字体里 \"0\" 的宽(日期 tabular-nums 等宽)⇒ 写成 Nch + 常数;常数同时兜住\n 默认占位「请选择日期时间」(7 汉字)不省略。调用方要另给宽:className 传 width。 */\n.dshpc-dt__trigger--w-day{width:calc(10ch + 56px)}\n.dshpc-dt__trigger--w-minute{width:calc(16ch + 38px)}\n.dshpc-dt__trigger--w-second{width:calc(19ch + 38px)}\n.dshpc-dt__trigger--wr-day{width:calc(20ch + 125px)}\n.dshpc-dt__trigger--wr-minute{width:calc(32ch + 111px)}\n.dshpc-dt__trigger--wr-second{width:calc(38ch + 104px)}\n\n.dshpc-dt__pop{\n z-index:60;padding:10px;user-select:none;\n font-size:13px;line-height:20px;\n background:var(--dshpc-surface-menu);border:1px solid var(--dshpc-border);\n border-radius:var(--dshpc-radius-md);box-shadow:0 8px 24px rgba(15,23,42,.12);\n}\n/* 两个独立端框(range):点哪个哪个成为当前编辑端,互不联动、只是排在一起。 */\n.dshpc-dt__ends{display:flex;gap:6px;margin-bottom:8px}\n.dshpc-dt__end{\n flex:1 1 0;min-width:0;display:flex;align-items:center;gap:6px;padding:4px 8px;\n text-align:left;background:var(--dshpc-surface-1);\n border:1px solid var(--dshpc-border-faint);border-radius:var(--dshpc-radius-sm);cursor:pointer;\n}\n.dshpc-dt__end--active{border-color:var(--dshpc-business);background:var(--dshpc-open-bg)}\n.dshpc-dt__end:focus-visible{outline:2px solid var(--dshpc-focus);outline-offset:1px}\n.dshpc-dt__end-label{flex:none;font-size:11px;line-height:16px;color:var(--dshpc-fg-3);white-space:nowrap}\n.dshpc-dt__end-value{font-size:12px;line-height:18px;color:var(--dshpc-fg);overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-variant-numeric:tabular-nums}\n.dshpc-dt__end-value--empty{color:var(--dshpc-fg-dim)}\n\n.dshpc-dt__nav{display:flex;align-items:center;justify-content:space-between;margin-bottom:6px}\n.dshpc-dt__nav-group{display:flex;gap:2px}\n.dshpc-dt__nav-btn{\n display:inline-flex;align-items:center;justify-content:center;width:24px;height:24px;padding:0;\n color:var(--dshpc-fg-2);background:none;border:0;border-radius:var(--dshpc-radius-sm);cursor:pointer;\n}\n.dshpc-dt__nav-btn:hover{background:var(--dshpc-surface-sunken);color:var(--dshpc-fg)}\n.dshpc-dt__nav-btn:focus-visible{outline:2px solid var(--dshpc-focus);outline-offset:-1px}\n.dshpc-dt__caption{font-size:13px;font-weight:600;color:var(--dshpc-fg);white-space:nowrap}\n\n.dshpc-dt__grid{display:grid;grid-template-columns:repeat(7,30px);gap:2px}\n.dshpc-dt__wd{height:20px;font-size:11px;line-height:20px;color:var(--dshpc-fg-3);text-align:center}\n.dshpc-dt__cell{\n height:26px;padding:0;font-size:12px;font-variant-numeric:tabular-nums;\n color:var(--dshpc-fg);background:none;border:0;border-radius:var(--dshpc-radius-sm);cursor:pointer;\n}\n.dshpc-dt__cell:hover{background:var(--dshpc-surface-sunken)}\n.dshpc-dt__cell:focus-visible{outline:2px solid var(--dshpc-focus);outline-offset:-1px}\n.dshpc-dt__cell--out{color:var(--dshpc-fg-dim)}\n.dshpc-dt__cell--today{color:var(--dshpc-business);font-weight:600}\n/* 起 / 止端:品牌蓝实面反白(与 Segmented weekday 选中同口径)。 */\n.dshpc-dt__cell--sel{background:var(--dshpc-business);color:var(--dshpc-fg-inverse);font-weight:600}\n.dshpc-dt__cell--sel:hover{background:var(--dshpc-business-hover)}\n\n/* 两块日历面板(range:左开始、右结束,各选各的)。 */\n.dshpc-dt__panels{display:flex;gap:14px;align-items:flex-start}\n.dshpc-dt__panel{display:flex;flex-direction:column;gap:6px}\n\n.dshpc-dt__time{display:flex;align-items:flex-end;justify-content:center;gap:4px;margin-top:2px;padding-top:8px;border-top:1px solid var(--dshpc-border-faint)}\n.dshpc-dt__unit{display:flex;flex-direction:column;align-items:center;gap:2px}\n.dshpc-dt__unit-label{font-size:10px;line-height:14px;color:var(--dshpc-fg-3)}\n.dshpc-dt__step-btn{\n display:inline-flex;align-items:center;justify-content:center;width:34px;height:14px;padding:0;\n color:var(--dshpc-fg-2);background:none;border:0;border-radius:var(--dshpc-radius-sm);cursor:pointer;\n}\n.dshpc-dt__step-btn:hover{background:var(--dshpc-surface-sunken);color:var(--dshpc-fg)}\n.dshpc-dt__step-btn:focus-visible{outline:2px solid var(--dshpc-focus);outline-offset:-1px}\n.dshpc-dt__step-val{\n width:34px;height:24px;padding:0;box-sizing:border-box;text-align:center;\n font-size:13px;font-variant-numeric:tabular-nums;color:var(--dshpc-fg);\n background:var(--dshpc-surface-sunken);border:1px solid var(--dshpc-border-faint);\n border-radius:var(--dshpc-radius-sm);outline:none;\n}\n.dshpc-dt__step-val:focus{border-color:var(--dshpc-focus);box-shadow:0 0 0 1px var(--dshpc-focus)}\n.dshpc-dt__step-val:disabled{color:var(--dshpc-fg-dim);cursor:not-allowed}\n.dshpc-dt__sep{padding-bottom:5px;color:var(--dshpc-fg-3);font-size:12px}\n\n.dshpc-dt__foot{display:flex;align-items:center;justify-content:space-between;gap:8px;margin-top:8px;padding-top:8px;border-top:1px solid var(--dshpc-border-faint)}\n.dshpc-dt__foot-side{display:flex;align-items:center;gap:6px}\n.dshpc-dt__warn{font-size:11px;color:var(--dshpc-warning-label);white-space:nowrap}\n";
|
|
130
|
+
//#endregion
|
|
131
|
+
//#region ../../node_modules/.pnpm/dsh-plugin-core@0.5.0_@babel+runtime@8.0.8_@codemirror+autocomplete@6.20.4_@codemirror+_bddbf1bc7ba0e94be71f734653121d0c/node_modules/dsh-plugin-core/dist/ui/marquee-css.generated.js
|
|
132
|
+
const MARQUEE_CSS = "/* 跑马灯(MarqueeText):双层——外层只裁剪,内层才 transform 滚动;非 hover 内层自带省略号。\n 2026-10-20:本文件原是杂烩「select.css」(下拉 / 日历 / 时分的皮肤都装过),随着那些控件\n 一个个删完,最后只剩跑马灯,故按本包「一个 css 服务一个对象」的格局改名归档。\n 同批清掉的还有零引用的省略号类 .dshpc-ellipsis —— 本包三个用到截断的地方都没采纳它。 */\n.dshpc-mq{display:block;overflow:hidden;white-space:nowrap;}\n.dshpc-mq .dshpc-mq-in{display:inline-block;white-space:nowrap;max-width:100%;overflow:hidden;text-overflow:ellipsis;vertical-align:top;}\n/* ⚠️ 跑法(用户 2026-10-03 拍板):**跑一遍、停在尾字**(播放 1 次 + forwards),不来回弹、不无限跑。\n 滚距 = 精确溢出量 ⇒ 停下时最后一个字正好贴右缘,**不会跑进黑块**(黑块是旧手写版把\n 内层盒子裁了、按「半截文本」平移导致的)。鼠标移开 ⇒ :hover 失效 ⇒ 自动复位回省略号态。 */\n.dshpc-mq-run:hover .dshpc-mq-in{max-width:none;overflow:visible;animation:dshpc-mq-scroll var(--dshpc-mq-dur,6s) linear .4s 1 forwards;}\n@keyframes dshpc-mq-scroll{from{transform:translateX(0)}to{transform:translateX(var(--dshpc-mq-dist,-40px))}}\n/* 溢出渐影(用户 2026-10-24 拍板「左右稍微有点渐影」;官方口径 = dsh-client-ui-primitives@0.2.1-rc.2\n PathLabel.module.css:13-15:mask-image 线性渐隐 + 28px 随官方)。⚠️ 只在 **hover 滚动态** 加:\n 静态态(三个点)不要渐影(用户 2026-10-24 二次拍板),hover 滚动时两端渐影——左缘柔化被裁的文字头。 */\n.dshpc-mq-run:hover{mask-image:linear-gradient(to right, transparent, #000 28px, #000 calc(100% - 28px), transparent);}\n";
|
|
133
|
+
//#endregion
|
|
134
|
+
//#region ../../node_modules/.pnpm/dsh-plugin-core@0.5.0_@babel+runtime@8.0.8_@codemirror+autocomplete@6.20.4_@codemirror+_bddbf1bc7ba0e94be71f734653121d0c/node_modules/dsh-plugin-core/dist/ui/picker-css.generated.js
|
|
135
|
+
const PICKER_CSS = "\n.dshpc-picker{position:relative;display:inline-block;font-size:13px;line-height:20px}\n.dshpc-picker__trigger{\n display:inline-flex;align-items:center;justify-content:space-between;gap:6px;\n min-width:120px;max-width:100%;height:28px;padding:0 8px;\n color:var(--dshpc-fg);background:var(--dshpc-surface-1);\n border:1px solid var(--dshpc-border);border-radius:var(--dshpc-radius-md);cursor:pointer;\n}\n.dshpc-picker__trigger:disabled{color:var(--dshpc-fg-dim);cursor:not-allowed;opacity:.7}\n/* 聚焦(键盘或点击选中)时与全站一致的蓝色描边;菜单打开后焦点会进去,触发器自然失去焦点。 */\n.dshpc-picker__trigger:focus-visible{outline:2px solid var(--dshpc-focus);outline-offset:1px}\n/* 文字默认靠左(吃掉剩余宽度),不给 space-between 把短文案推到中间的机会;\n 确实要居中就显式传 align=\"center\"。 */\n.dshpc-picker__label{flex:1 1 auto;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;text-align:left}\n.dshpc-picker__trigger--center .dshpc-picker__label{text-align:center}\n.dshpc-picker__caret{flex:none;color:var(--dshpc-fg-3)}\n.dshpc-picker__icon{display:inline-flex;flex:none;color:var(--dshpc-fg-2)}\n.dshpc-picker__option-icon{display:inline-flex;flex:none;color:var(--dshpc-fg-2)}\n.dshpc-picker__menu{\n z-index:60;max-height:280px;overflow:auto;padding:4px;\n /* 菜单经 FloatingPortal 挂到 body,脱离 .dshpc-picker,须显式字号,否则继承 body 的大字号 */\n font-size:13px;line-height:20px;\n background:var(--dshpc-surface-menu);border:1px solid var(--dshpc-border);\n border-radius:var(--dshpc-radius-md);box-shadow:0 8px 24px rgba(15,23,42,.12);\n}\n/* 尺寸档(与 Field 的 sm/md/lg 对应)。 */\n.dshpc-picker__trigger--sm{height:24px;font-size:12px}\n.dshpc-picker__trigger--lg{height:32px}\n/* 键盘游标所在项(无 hover 也要看得见)。 */\n.dshpc-picker__option[data-active='true']{background:var(--dshpc-surface-sunken);outline:1px solid var(--dshpc-border)}\n.dshpc-picker__option--clear{color:var(--dshpc-fg-3)}\n.dshpc-picker__search{\n width:100%;height:28px;margin-bottom:4px;padding:0 8px;box-sizing:border-box;\n color:var(--dshpc-fg);background:var(--dshpc-surface-sunken);\n border:1px solid var(--dshpc-border-faint);border-radius:var(--dshpc-radius-md);outline:none;\n}\n.dshpc-picker__group-label{\n padding:6px 8px 2px;color:var(--dshpc-fg-3);font-size:11px;\n}\n.dshpc-picker__option{\n display:flex;align-items:center;gap:6px;padding:6px 8px;border-radius:var(--dshpc-radius-sm);cursor:pointer;\n color:var(--dshpc-fg);white-space:nowrap;\n}\n.dshpc-picker__option:hover{background:var(--dshpc-surface-sunken)}\n.dshpc-picker__option--active{background:var(--dshpc-open-bg);color:var(--dshpc-business)}\n.dshpc-picker__option--disabled{color:var(--dshpc-fg-dim);cursor:not-allowed}\n.dshpc-picker__tick{width:12px;color:var(--dshpc-business)}\n.dshpc-picker__empty{padding:8px;color:var(--dshpc-fg-3);text-align:center}\n.dshpc-picker__degraded{\n padding:6px 8px;margin-bottom:4px;border-radius:var(--dshpc-radius-sm);\n color:var(--dshpc-warning-label);background:color-mix(in srgb,var(--dshpc-warning) 12%,transparent);\n font-size:11px;\n}\n.dshpc-picker__row{display:flex;align-items:center;gap:8px}\n";
|
|
136
|
+
//#endregion
|
|
137
|
+
//#region ../../node_modules/.pnpm/dsh-plugin-core@0.5.0_@babel+runtime@8.0.8_@codemirror+autocomplete@6.20.4_@codemirror+_bddbf1bc7ba0e94be71f734653121d0c/node_modules/dsh-plugin-core/dist/ui/feedback-css.generated.js
|
|
138
|
+
const FEEDBACK_CSS = "\n/* 遮罩 = 宿主遮罩变量 --dsw-alias-bg-mask-1(与官方 Modal / 兄弟项目 --tdt-mask 同一条真值,用户 2026-10-20)。 */\n/* 右边界让位页面级分栏(PanelDock 发布的 --dshpc-page-inset-right,用户 2026-10-22):\n 分栏不被压暗、照常可点;弹窗在这块**剩下**的区域里居中,就像整页被推出去一样。 */\n.dshpc-modal-mask{\n position:fixed;inset:0 var(--dshpc-page-inset-right,0px) 0 0;z-index:1070;\n display:flex;align-items:center;justify-content:center;\n background:var(--dshpc-mask);\n}\n/* 大弹窗家族(md/lg):抄兄弟项目 archive-session-css 的 .dsh-tdt-sv-panel(surface-base + border-l2 + radius 12 + shadow-2)。 */\n.dshpc-modal{\n display:flex;flex-direction:column;box-sizing:border-box;\n background:var(--dshpc-surface-base);color:var(--dshpc-fg);\n border:1px solid var(--dshpc-border);border-radius:var(--dshpc-radius-md);\n box-shadow:var(--dshpc-shadow-2);overflow:hidden;\n}\n.dshpc-modal__head{\n display:flex;align-items:center;gap:8px;padding:18px 31px 12px;\n border-bottom:1px solid var(--dshpc-border);flex-wrap:wrap;\n}\n/* 标题组:第一行 = 标题 + 右侧小块(徽标紧跟标题),第二行 = 副标题。 */\n.dshpc-modal__titlegroup{display:flex;flex-direction:column;gap:2px;min-width:0;flex:0 1 auto}\n.dshpc-modal__titlerow{display:flex;align-items:center;gap:8px;min-width:0}\n.dshpc-modal__title{font-size:var(--dshpc-font-lg);font-weight:600;line-height:1.4;min-width:0}\n/* 标题下副标题行(兄弟项目 .dsh-tdt-sv-sid:等宽字体、caption 色、可换行)。 */\n.dshpc-modal__sid{font-family:var(--ds-font-family-code,monospace);font-size:var(--dshpc-font-xs);color:var(--dshpc-fg-3);word-break:break-all}\n/* 关闭按钮:24×24 方角图标位,不借用 Picker 的触发器皮肤(那份带 min-width:120px)。 */\n.dshpc-modal__close{\n display:inline-flex;align-items:center;justify-content:center;flex:none;\n width:20px;height:20px;padding:0;border:none;border-radius:var(--dshpc-radius-sm);\n background:transparent;color:var(--dshpc-fg-3);font-family:inherit;font-size:13px;line-height:1;cursor:pointer;\n transition:background-color var(--dshpc-dur-fast) var(--dshpc-ease),color var(--dshpc-dur-fast) var(--dshpc-ease);\n}\n.dshpc-modal__close:hover{background:var(--dshpc-hover);color:var(--dshpc-fg)}\n.dshpc-modal__close:focus-visible{outline:2px solid var(--dshpc-focus);outline-offset:1px}\n/* body = 唯一滚动容器:内距与滚动都归它(滚动条贴面板右缘,不被内距挤进来);\n 内容按流排,不设 height:100%、不自己开滚动条。 */\n.dshpc-modal__body{flex:1 1 auto;min-height:0;overflow:auto;padding:17px 31px}\n.dshpc-modal__foot{display:flex;justify-content:flex-end;gap:8px;padding:12px 31px 18px}\n.dshpc-toast-host{\n position:fixed;z-index:1090;left:50%;bottom:32px;transform:translateX(-50%);\n display:flex;flex-direction:column;gap:8px;align-items:center;pointer-events:none;\n}\n.dshpc-toast{\n padding:8px 14px;border-radius:8px;font-size:13px;color:var(--dshpc-fg);\n background:var(--dshpc-surface-menu);border:1px solid var(--dshpc-border);\n box-shadow:0 8px 24px rgba(15,23,42,.16);\n}\n.dshpc-toast--success{color:var(--dshpc-success);border-color:color-mix(in srgb,var(--dshpc-success) 40%,transparent)}\n.dshpc-toast--error{color:var(--dshpc-danger);border-color:color-mix(in srgb,var(--dshpc-danger) 40%,transparent)}\n.dshpc-error__retry{\n margin-top:8px;color:var(--dshpc-link);cursor:pointer;background:none;border:none;padding:0;\n}\n/* 原生弹窗演示:经宿主 Modal 的 contentClassName 注入,证明宿主内容区尺寸可经类名自定义。 */\n.dshpc-native-demo-content{max-width:520px}\n/* Modal 头部四槽:左图标 / 标题组 / 弹性间隔 / 右侧动作区 + 关闭钮。 */\n.dshpc-modal__heading{display:flex;align-items:center;gap:8px;min-width:0;flex:0 1 auto}\n.dshpc-modal__lead{flex:none;display:inline-flex;align-items:center;justify-content:center;font-size:16px;line-height:1}\n.dshpc-modal__extra{flex:none;display:inline-flex;align-items:center}\n.dshpc-modal__spacer{flex:1 1 auto;min-width:8px}\n.dshpc-modal__actions{flex:none;display:flex;align-items:center;gap:8px}\n/* 头部信号图标(AlertModal 按 severity 注入):自含配色,不依赖宿主 token。 */\n.dshpc-alert-sev{display:inline-flex;align-items:center;justify-content:center;width:20px;height:20px;border-radius:50%;font-size:12px;color:#fff;flex:none}\n.dshpc-alert-sev--info{background:#2563eb}\n.dshpc-alert-sev--success{background:#16a34a}\n.dshpc-alert-sev--warning{background:#d97706}\n.dshpc-alert-sev--error{background:#dc2626}\n/* 小确认框家族(sm):严格抄兄弟项目 renderConfirm 的 dialogStyle(task-list.tsx:456)——\n 360px 宽 / 18px 内距 / 头部无分隔线 / 说明文字 fg-2 / 底部按钮右对齐。 */\n.dshpc-modal--sm{padding:18px}\n.dshpc-modal--sm .dshpc-modal__head{padding:0 0 8px;border-bottom:none}\n.dshpc-modal--sm .dshpc-modal__body{padding:0 0 14px;overflow:visible;font-size:var(--dshpc-font-sm);color:var(--dshpc-fg-2);line-height:var(--dshpc-line-sm)}\n.dshpc-modal--sm .dshpc-modal__foot{padding:0}\n";
|
|
139
|
+
//#endregion
|
|
140
|
+
//#region ../../node_modules/.pnpm/dsh-plugin-core@0.5.0_@babel+runtime@8.0.8_@codemirror+autocomplete@6.20.4_@codemirror+_bddbf1bc7ba0e94be71f734653121d0c/node_modules/dsh-plugin-core/dist/ui/card-css.generated.js
|
|
141
|
+
const CARD_CSS = "\n.dshpc-card{\n position:relative;box-sizing:border-box;color:var(--dshpc-fg);font:inherit;text-align:left;\n --card-accent:var(--dshpc-business);\n --card-accent-soft:var(--dshpc-business-soft);\n}\n/* 档位 → token(照 records-timeline 的 tone 模式:一个变量切档,不写 5 套规则;浅底与色条同源)。 */\n.dshpc-card--success{--card-accent:var(--dshpc-success);--card-accent-soft:var(--dshpc-success-soft)}\n.dshpc-card--warning{--card-accent:var(--dshpc-warning);--card-accent-soft:var(--dshpc-warning-soft)}\n.dshpc-card--danger{--card-accent:var(--dshpc-danger);--card-accent-soft:var(--dshpc-danger-soft)}\n/* neutral 浅底借 chip 底(兄弟项目 mute 档同款:明暗都成立)。 */\n.dshpc-card--neutral{--card-accent:var(--dshpc-fg-4);--card-accent-soft:var(--dshpc-chip-bg)}\n\n/* 头部一行 = 色条 + 主内容 + 右侧槽,**整体垂直居中**:调用方在 action 里裸放一个元素\n (按钮 / 文字 / 图标)不用自己套容器居中;一行两行、右边怎么放由调用方在框内自定。 */\n.dshpc-card__head{display:flex;align-items:center;gap:8px;min-width:0}\n.dshpc-card__main{flex:1;min-width:0}\n.dshpc-card__side{display:flex;align-items:center;gap:6px;flex:none}\n\n/* ── 外观一 · StripCard:同色系浅底 + 1px 不可见占位边框 + 方角 + 4px 通高方角色条贴左缘 ── */\n.dshpc-card--strip{\n padding:12px 12px 12px 20px;border:1px solid transparent;\n background:var(--card-accent-soft,transparent);\n}\n/* 左内边距 20px = 16 留白 + 4 条宽 ⇒ 内容从色条右缘起算;色条绝对定位通高,跟着内容高度自适应。 */\n.dshpc-card--strip .dshpc-card__bar{position:absolute;left:0;top:0;bottom:0;width:4px;background:var(--card-accent)}\n\n/* ── 外观二 · Card:surface 底 + 1px 实色边框 + 圆角 + 行内圆角短条 ── */\n.dshpc-card--bordered{\n /* 左内边距 12(比上/右/下 14 少 2):竖条贴近边框;头部内缩 2px ⇒ 主内容跟着左移 2px,\n 竖条↔内容的 12px 间距不变——比「条子 left:-2 而内容不动」更正规(不靠相对定位硬补)。 */\n padding:14px 14px 14px 12px;border:1px solid var(--dshpc-border);border-radius:var(--dshpc-radius-sm);\n background:var(--dshpc-surface-1);\n}\n.dshpc-card--bordered .dshpc-card__head{gap:12px}\n/* 短条:行内 flex 项,**高度跟着内容走**(stretch),最小一行文字(--dshpc-line-md)——\n 一行文字时条子与文字齐高,不会把卡撑高;竖条距左 12(= 左内边距),距上/右/下 14。 */\n.dshpc-card--bordered .dshpc-card__bar{width:6px;flex:none;align-self:stretch;min-height:var(--dshpc-line-md);border-radius:var(--dshpc-radius-xs);background:var(--card-accent)}\n.dshpc-card__toggle{\n display:inline-flex;align-items:center;justify-content:center;\n width:24px;height:24px;padding:0;background:none;border:none;border-radius:6px;\n color:var(--dshpc-fg-3);cursor:pointer;\n}\n.dshpc-card__toggle:hover{background:var(--dshpc-surface-sunken);color:var(--dshpc-fg)}\n.dshpc-card__caret{display:inline-block;font-size:10px;transition:transform .15s ease}\n.dshpc-card__caret.is-open{transform:rotate(180deg)}\n.dshpc-card__panel{margin-top:8px;padding-top:8px;border-top:1px solid var(--dshpc-border-faint)}\n";
|
|
142
|
+
//#endregion
|
|
143
|
+
//#region ../../node_modules/.pnpm/dsh-plugin-core@0.5.0_@babel+runtime@8.0.8_@codemirror+autocomplete@6.20.4_@codemirror+_bddbf1bc7ba0e94be71f734653121d0c/node_modules/dsh-plugin-core/dist/ui/chip-css.generated.js
|
|
144
|
+
const CHIP_CSS = "\n/* 三条局部变量承载配色:neutral 走旧灰面;语义档换底字配对(2026-10-20 用户要多色多尺寸标签)。 */\n.dshpc-chip{--chip-bg:var(--dshpc-chip-bg);--chip-fg:var(--dshpc-fg);--chip-bg-hover:var(--dshpc-chip-bg-hover);\n display:inline-flex;align-items:center;justify-content:center;gap:4px;padding:1px 8px;\n box-sizing:border-box;border-radius:var(--dshpc-radius-pill,999px);border:none;\n background:var(--chip-bg);color:var(--chip-fg);\n font-family:inherit;font-size:11px;line-height:18px;margin:0;\n /* 2026-10-18:chip 是 flex 行里的常用项,禁止被压缩换行(预览站出现过文字竖排、互相叠压的挤压)。 */\n white-space:nowrap;flex:none;\n appearance:none;-webkit-appearance:none;\n}\n/* md 档:卡片元信息行等稍大场景;sm 即旧版默认,逐像素不动。 */\n.dshpc-chip--md{padding:2px 10px;font-size:12px;line-height:20px;}\n/* xs 档:标题后缀等极紧凑场景(2026-10-20 用户要更小标签);16px 高、font 10。 */\n.dshpc-chip--xs{padding:0 6px;font-size:10px;line-height:16px;}\n/* 语义色实心档:底 / 字 / hover 配对与 Button 同源(黄底中高明度 ⇒ 字用 --dshpc-on-warning)。 */\n.dshpc-chip--business{--chip-bg:var(--dshpc-business);--chip-fg:var(--dshpc-on-signal);--chip-bg-hover:var(--dshpc-business-hover);}\n.dshpc-chip--success{--chip-bg:var(--dshpc-success);--chip-fg:var(--dshpc-on-signal);--chip-bg-hover:var(--dshpc-success-hover);}\n.dshpc-chip--warning{--chip-bg:var(--dshpc-warning);--chip-fg:var(--dshpc-on-warning);--chip-bg-hover:var(--dshpc-warning-hover);}\n.dshpc-chip--danger{--chip-bg:var(--dshpc-danger);--chip-fg:var(--dshpc-on-signal);--chip-bg-hover:var(--dshpc-danger-hover);}\n/* 可点态:button 渲染(见 Chip.ts),光标 + hover 加深。 */\n.dshpc-chip--clickable{cursor:pointer;transition:background-color var(--dshpc-dur-fast) var(--dshpc-ease);}\n.dshpc-chip--clickable:hover:not(:disabled){background:var(--chip-bg-hover)}\n.dshpc-chip:focus-visible{outline:2px solid var(--dshpc-focus);outline-offset:1px}\n.dshpc-chip:disabled{cursor:default;color:var(--dshpc-fg-3)}\n@media (prefers-reduced-motion: reduce){.dshpc-chip{transition:none}}\n";
|
|
145
|
+
//#endregion
|
|
146
|
+
//#region ../../node_modules/.pnpm/dsh-plugin-core@0.5.0_@babel+runtime@8.0.8_@codemirror+autocomplete@6.20.4_@codemirror+_bddbf1bc7ba0e94be71f734653121d0c/node_modules/dsh-plugin-core/dist/ui/code-viewer-css.generated.js
|
|
147
|
+
const CODE_VIEWER_CSS = "/* CodeViewer(只读 CodeMirror 查看器)样式。类名固定 dshpc-cv*;颜色吃 --dshpc-* token,\n 深色由 design 的 token 深色段自动生效(不写死颜色值)。 */\n.dshpc-cv{position:relative;display:flex;flex-direction:column;height:100%;min-height:0;}\n.dshpc-cv__copy{position:absolute;top:6px;right:6px;z-index:5;display:inline-flex;align-items:center;justify-content:center;width:28px;height:28px;padding:0;appearance:none;border:1px solid var(--dshpc-border,rgba(128,128,128,.35));border-radius:var(--dshpc-radius-sm,6px);background:var(--dshpc-surface-1,#fff);color:var(--dshpc-fg-2,rgba(128,128,128,.95));cursor:pointer;opacity:0;transition:opacity .12s var(--dshpc-ease,ease),background .12s,color .12s;}\n.dshpc-cv:hover .dshpc-cv__copy,.dshpc-cv__copy:focus-visible{opacity:1;}\n.dshpc-cv__copy:hover{background:var(--dshpc-hover,rgba(38,49,72,.06));color:var(--dshpc-fg,#1f2328);}\n.dshpc-cv__copy svg{width:16px;height:16px;}\n.dshpc-cv__editor{flex:1 1 auto;min-height:0;overflow:hidden;}\n.dshpc-cv__editor .cm-editor{height:100%;}\n.dshpc-cv__editor .cm-scroller{overflow:auto;}\n";
|
|
148
|
+
//#endregion
|
|
149
|
+
//#region ../../node_modules/.pnpm/dsh-plugin-core@0.5.0_@babel+runtime@8.0.8_@codemirror+autocomplete@6.20.4_@codemirror+_bddbf1bc7ba0e94be71f734653121d0c/node_modules/dsh-plugin-core/dist/ui/panel-dock-css.generated.js
|
|
150
|
+
const PANEL_DOCK_CSS = "\n/* 停靠栏 = **布局成员**,不是浮层:它占宽度、把主区真正挤窄(兄弟项目 2026-09-28:\n 「分栏压过来,不是盖上去」)。所以调用方必须把它放进自己的 flex 根里。 */\n.dshpc-dock{display:flex;flex:0 0 auto;align-self:stretch;min-width:0}\n\n/* 单栏:sticky + 100vh 让它在页面滚动时保持可见,同时仍然占宽度。\n ⚠️ **本条刻意不设 z-index**:布局成员一旦带正 z-index,就会无条件压过宿主 portal 到 body 的\n 弹窗(兄弟项目 2026-10-05 真机事故「侧边栏盖住宿主设置弹窗」)。层序交给 DOM 顺序裁决。 */\n.dshpc-dock__panel{\n box-sizing:border-box;position:sticky;top:0;align-self:stretch;\n display:flex;flex-direction:column;flex:0 0 auto;\n /* 高度默认视口高(整页场景);嵌在定高容器里时由调用方给 --dshpc-dock-h(如 420px / 100%)。 */\n height:var(--dshpc-dock-h,100vh);max-height:var(--dshpc-dock-h,100vh);min-width:0;\n background:var(--dshpc-surface-base);color:var(--dshpc-fg);\n border-left:1px solid var(--dshpc-border);\n box-shadow:var(--dshpc-shadow-2);\n}\n\n.dshpc-dock__head{\n flex:none;display:flex;align-items:center;gap:8px;\n /* 右侧 34px = 8(边距) + 20(关钮) + 6(呼吸):给绝对定位的关钮留位,标题/extra 不从它底下钻 */\n padding:10px 34px 10px 14px;\n border-bottom:1px solid var(--dshpc-border-faint);\n}\n/* 图标位 / 标题右侧的内容位:消费方传 ReactNode,可塞多个;库只负责排布,不抢宽度。 */\n.dshpc-dock__lead{display:inline-flex;align-items:center;gap:6px;flex:none;color:var(--dshpc-fg-2)}\n.dshpc-dock__extra{display:inline-flex;align-items:center;gap:6px;flex:none;margin-left:auto}\n/* 自定义头部:整行归调用方 —— 不加内边距/边框/背景,也不给关钮留内联空间(关钮是绝对定位的)。 */\n.dshpc-dock__head--custom{display:block;padding:0;border-bottom:none}\n.dshpc-dock__title{\n flex:1 1 auto;min-width:0;\n overflow:hidden;text-overflow:ellipsis;white-space:nowrap;\n font-size:var(--dshpc-font-md);font-weight:600;\n}\n/* 关闭钮:20×20 方角图标位(与 Modal 的关闭钮同规格,不借 Picker 触发器皮肤)。 */\n.dshpc-dock__close{\n display:inline-flex;align-items:center;justify-content:center;flex:none;\n width:20px;height:20px;padding:0;border:none;border-radius:var(--dshpc-radius-sm);\n background:transparent;color:var(--dshpc-fg-3);\n font-family:inherit;font-size:13px;line-height:1;cursor:pointer;\n transition:background-color var(--dshpc-dur-fast) var(--dshpc-ease),color var(--dshpc-dur-fast) var(--dshpc-ease);\n}\n.dshpc-dock__close:hover{background:var(--dshpc-hover);color:var(--dshpc-fg)}\n.dshpc-dock__close:focus-visible{outline:2px solid var(--dshpc-focus);outline-offset:1px}\n/* 头部关钮:绝对定位,位置与内置头完全一致(top 10 / right 8);自定义头也用这一个位置。\n 锚点是面板本身(position:sticky 即定位上下文),不在滚动内容里,所以正文滚动它不跟滚。 */\n.dshpc-dock__close--abs{position:absolute;top:10px;right:8px;z-index:8}\n/* 浮动关钮:无头部面板用,略收一点边距。 */\n.dshpc-dock__close--floating{\n position:absolute;top:6px;right:6px;z-index:8;\n background:var(--dshpc-surface-menu);border:1px solid var(--dshpc-border-faint);\n}\n\n/* 内容区自己滚:面板高度锁 100vh,内容不设内部滚动就会把整页撑高。 */\n.dshpc-dock__body{flex:1 1 auto;min-height:0;overflow:auto}\n\n/* 拖拽条:左缘 6px 命中区,**不画线**,hover/按住时才浮出一条浅色带。\n z-index 7 必须高于面板内容里的浮层(复制钮一类),否则命中区会被内容盖住。 */\n.dshpc-dock__resizer{\n position:absolute;left:0;top:0;bottom:0;width:6px;\n z-index:7;cursor:col-resize;background:transparent;\n transition:background-color var(--dshpc-dur-fast) var(--dshpc-ease);\n}\n/* hover/按住:不填灰带,改为官方 work 区指示条样式 —— 左缘 2px 蓝竖条、上下渐隐\n (颜色走 business 蓝的官方 alias,明暗自动跟随宿主;命中区仍是 6px 不变)。 */\n.dshpc-dock__resizer:hover,.dshpc-dock__resizer:active{\n background:linear-gradient(180deg,transparent,var(--dshpc-business) 30%,var(--dshpc-business) 70%,transparent) left center / 1px 100% no-repeat;\n}\n\n/* 拖动期:① <iframe>(PDF / HTML 预览)是独立文档,会吞掉父文档的 pointermove,\n 向右拖进 iframe 就卡死 —— 整片让出指针事件;② contain 把重排隔离在栏内,\n 否则每帧改宽度都会牵动整页重排(兄弟项目 2026-10-04 真机「挪很久才动一下」)。 */\n.dshpc-dock.dshpc-dock--resizing iframe{pointer-events:none}\n.dshpc-dock.dshpc-dock--resizing .dshpc-dock__panel{contain:layout paint;will-change:width}\n";
|
|
151
|
+
//#endregion
|
|
152
|
+
//#region ../../node_modules/.pnpm/dsh-plugin-core@0.5.0_@babel+runtime@8.0.8_@codemirror+autocomplete@6.20.4_@codemirror+_bddbf1bc7ba0e94be71f734653121d0c/node_modules/dsh-plugin-core/dist/explorer/explorer-css.generated.js
|
|
153
|
+
const EXPLORER_CSS = "/* 工作区文件浏览器(dshpc-fb-*)。\n *\n * 度量真源 = 兄弟项目 dsh-task-dispatch-table 的 src/client/archive-session-css.ts\n * (.dsh-tdt-sv-* 全族)。**逐条照抄,不许自己估**:padding / gap / 圆角 / 字号 / 行高 /\n * 边框色 / 悬停色 / 透明度动画 / 溢出策略,一一对应,改这里之前先去那边对原文。\n * 前缀与变量名换成本仓口径(--tdt-* → --dshpc-*),数值不换。\n *\n * 控件:能核心就核心(面包屑 = Button ghost、行尾 = Button outline、展开 / 图标 = IconButton、\n * 分段 = Segmented、文字 = MarqueeText)。核心控件自带的 padding / 高度 / 皮肤在本文件里\n * **按兄弟数值覆盖**(选择器带 .dshpc-fb 前缀提高特异性,确保盖得住控件默认值)。\n */\n.dshpc-fb{\n position:relative;display:flex;flex-direction:column;height:100%;min-height:0;\n background:var(--dshpc-surface-base);color:var(--dshpc-fg);\n}\n\n/* 第一排:▾ 选层 + 面包屑 + 动作(兄弟 .dsh-tdt-sv-crumbbar)\n ⚠️ 不能 overflow:hidden —— 下拉浮层挂在它下面,裁了就看不见。 */\n.dshpc-fb__bar{\n position:relative;flex:none;display:flex;align-items:center;gap:2px;\n padding:4px 10px;border-bottom:1px solid var(--dshpc-border);white-space:nowrap;\n}\n.dshpc-fb__menu-wrap{position:relative;flex:none;display:inline-flex}\n.dshpc-fb__crumbs{position:relative;flex:1;min-width:0;display:flex;align-items:center;gap:2px;overflow:hidden}\n.dshpc-fb__crumbs-measure{\n position:absolute;top:0;left:0;display:inline-flex;align-items:center;gap:2px;\n visibility:hidden;pointer-events:none;white-space:nowrap;\n}\n\n/* 面包屑:核心 ghost 钮,但皮肤与尺寸取兄弟 .dsh-tdt-sv-crumb(高由内容决定,不锁控制高)。 */\n.dshpc-fb .dshpc-fb__crumb{\n appearance:none;background:0 0;border:none;height:auto;\n padding:2px 4px;border-radius:var(--dshpc-radius-sm);\n font:inherit;font-size:var(--dshpc-font-sm);line-height:var(--dshpc-line-sm);\n color:var(--dshpc-fg-2);cursor:pointer;\n display:inline-flex;align-items:center;min-width:0;overflow:hidden;text-overflow:ellipsis;\n}\n.dshpc-fb .dshpc-fb__crumb:hover{background:var(--dshpc-hover);color:var(--dshpc-fg)}\n.dshpc-fb .dshpc-fb__crumb:disabled{color:var(--dshpc-fg-2);cursor:default}\n.dshpc-fb .dshpc-fb__crumb--current{cursor:default;color:var(--dshpc-fg);font-weight:600;min-width:0}\n.dshpc-fb .dshpc-fb__crumb--current:hover{background:0 0}\n.dshpc-fb__crumb-mq{flex:1 1 auto;min-width:0}\n.dshpc-fb__crumb-sep{flex:none;color:var(--dshpc-fg-3)}\n\n/* 越界(outside-workspace)第一排:只读完整路径(兄弟 .dsh-tdt-sv-crumbbar-plain-inner)。 */\n.dshpc-fb__bar-plain{\n font-family:var(--dshpc-font-mono,ui-monospace,SFMono-Regular,Menlo,Consolas,monospace);\n font-size:var(--dshpc-font-sm);line-height:var(--dshpc-line-sm);color:var(--dshpc-fg-2);\n white-space:nowrap;overflow:hidden;text-overflow:ellipsis;cursor:default;user-select:none;\n}\n.dshpc-fb__actions{flex:none;display:flex;align-items:center;gap:4px}\n\n/* ▾ 选层浮层(兄弟 .dsh-tdt-sv-crumbs-*)。\n 层序:兄弟是 30/31;本仓 picker 面板是 1100,遮罩必须高于它,否则菜单开着点面板不算「点外部」。 */\n.dshpc-fb__crumbs-backdrop{position:fixed;inset:0;z-index:1200;background:transparent}\n.dshpc-fb__crumbs-menu{\n position:absolute;top:calc(100% + 4px);left:0;z-index:1201;min-width:160px;max-height:240px;overflow:auto;\n background:var(--dshpc-surface-menu);border:1px solid var(--dshpc-border);border-radius:var(--dshpc-radius-sm);\n box-shadow:0 4px 16px rgba(0,0,0,.18);padding:4px;display:flex;flex-direction:column;\n}\n.dshpc-fb__menu-item{\n appearance:none;background:0 0;border:none;text-align:left;font:inherit;\n font-size:var(--dshpc-font-sm);line-height:var(--dshpc-line-md);\n padding:4px 8px;border-radius:var(--dshpc-radius-sm);color:var(--dshpc-fg);cursor:pointer;\n max-width:280px;display:flex;align-items:center;gap:2px;\n overflow:hidden;text-overflow:ellipsis;white-space:nowrap;\n}\n.dshpc-fb__menu-item:hover{background:var(--dshpc-hover)}\n.dshpc-fb__menu-empty{\n font-size:var(--dshpc-font-sm);line-height:var(--dshpc-line-md);padding:4px 8px;color:var(--dshpc-fg-3);\n}\n.dshpc-fb__menu-icon{flex:none;display:inline-flex}\n.dshpc-fb__menu-chev{flex:none;color:var(--dshpc-fg-3);margin-right:1px}\n.dshpc-fb__menu-chev-slot{flex:none;width:11px;height:11px;margin-right:1px}\n.dshpc-fb__menu-label{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}\n\n/* 第二排(仅预览态):文件名 + 工具(兄弟 .dsh-tdt-sv-titlebar / -preview-title-inner)。 */\n.dshpc-fb__title{\n flex:none;display:flex;align-items:center;gap:8px;\n padding:8px 14px;border-bottom:1px solid var(--dshpc-border);\n}\n.dshpc-fb__title-inner{\n font-family:var(--dshpc-font-mono,ui-monospace,SFMono-Regular,Menlo,Consolas,monospace);\n font-size:var(--dshpc-font-sm);line-height:var(--dshpc-line-sm);color:var(--dshpc-fg);\n white-space:nowrap;overflow:hidden;text-overflow:ellipsis;cursor:default;\n}\n\n/* 主体(兄弟 .dsh-tdt-sv-preview-body / -hint / -preview-err) */\n.dshpc-fb__body{flex:1;min-height:0;overflow-x:hidden;overflow-y:auto;padding:12px 14px}\n.dshpc-fb__note{font-size:var(--dshpc-font-sm);color:var(--dshpc-fg-2);text-align:center;padding:12px 0}\n.dshpc-fb__err{\n display:flex;flex-direction:column;align-items:flex-start;gap:10px;\n font-size:var(--dshpc-font-sm);line-height:1.6;color:var(--dshpc-fg-2);padding:8px 0;\n}\n\n/* 目录树(兄弟 .dsh-tdt-sv-tree*) */\n.dshpc-fb__tree{flex:1;min-height:0;overflow:auto;padding:6px 8px}\n.dshpc-fb__row{\n display:flex;align-items:center;gap:8px;padding:6px 8px;\n border-radius:var(--dshpc-radius-sm);cursor:pointer;user-select:none;\n}\n.dshpc-fb__row:hover{background:var(--dshpc-hover)}\n.dshpc-fb__row:focus-visible{outline:2px solid var(--dshpc-focus);outline-offset:-2px}\n.dshpc-fb__row-icon{flex:none;display:inline-flex;color:var(--dshpc-fg-2)}\n.dshpc-fb__row-name{\n flex:1;min-width:0;font-size:var(--dshpc-font-md);line-height:var(--dshpc-line-md);color:var(--dshpc-fg);\n overflow:hidden;text-overflow:ellipsis;white-space:nowrap;\n}\n\n/* 展开开关:核心 IconButton,命中位 20×20 + 展开时转 90°(兄弟 .dsh-tdt-sv-tree-toggle{,-open})。 */\n.dshpc-fb .dshpc-fb__row-toggle{\n appearance:none;background:0 0;border:none;flex:none;\n width:20px;height:20px;padding:0;margin:0;border-radius:var(--dshpc-radius-sm);\n color:var(--dshpc-fg-2);cursor:pointer;\n display:inline-flex;align-items:center;justify-content:center;\n transition:transform var(--dshpc-dur-fast) var(--dshpc-ease),background var(--dshpc-dur-fast) var(--dshpc-ease);\n}\n.dshpc-fb .dshpc-fb__row-toggle--open{transform:rotate(90deg)}\n\n/* 行尾「进入 / 选择」:核心 outline 钮,皮肤取兄弟 .dsh-tdt-sv-tree-act(高由内容决定)。\n 平时隐身但占位(opacity 而非 display)⇒ 出现时不顶动行内布局。 */\n.dshpc-fb .dshpc-fb__row-act{\n flex:none;margin-left:auto;appearance:none;background:0 0;\n border:1px solid var(--dshpc-border);border-radius:var(--dshpc-radius-sm);\n height:auto;padding:2px 8px;font-size:var(--dshpc-font-sm);line-height:1.4;\n color:var(--dshpc-fg-2);cursor:pointer;\n opacity:0;pointer-events:none;\n transition:opacity var(--dshpc-dur-fast) var(--dshpc-ease);\n}\n.dshpc-fb__row:hover .dshpc-fb__row-act,.dshpc-fb .dshpc-fb__row-act:focus-visible{opacity:1;pointer-events:auto}\n.dshpc-fb .dshpc-fb__row-act:hover{background:var(--dshpc-hover);color:var(--dshpc-fg)}\n\n.dshpc-fb__row-children{\n margin-left:9px;padding-left:7px;border-left:1px solid var(--dshpc-border);\n display:flex;flex-direction:column;\n}\n.dshpc-fb__row-note{flex:none;padding:8px 10px;font-size:var(--dshpc-font-sm);color:var(--dshpc-fg-3)}\n.dshpc-fb__row-err{padding:4px 8px 4px 36px;font-size:var(--dshpc-font-sm);color:var(--dshpc-danger)}\n\n/* 预览体内部容器(仅本仓预览组件用;兄弟对应 preview-fill / preview-body-code 一类)。\n 必须 border-box:渲染态 inline 加了 padding:12px 14px,content-box 下 width:100%+padding\n 会溢出父层 28px(父 .dshpc-fb 无 overflow 裁切)→ 恒多一条横滚条;border-box 把 padding\n 算进 100%,从根消除该溢出。 */\n.dshpc-fb__text{flex:1;min-height:0;overflow:auto;width:100%;box-sizing:border-box}\n.dshpc-fb__banner{padding:6px 10px;background:var(--dshpc-open-bg);color:var(--dshpc-fg-2);font-size:var(--dshpc-font-sm)}\n.dshpc-fb__more{display:flex;justify-content:center;padding:10px}\n.dshpc-fb__image{max-width:100%;border-radius:var(--dshpc-radius-sm);border:1px solid var(--dshpc-border)}\n/* iframe 的外壳(兄弟 .dsh-tdt-sv-preview-fill):iframe 必须包在这一层里才拿得到高度——\n 裸挂 iframe 时替换元素的自动最小尺寸会让高度算不出来(表现为预览区整片空白、像没反应)。 */\n.dshpc-fb__fill{flex:1;min-height:0;display:flex;overflow:hidden;padding:0}\n.dshpc-fb__frame{flex:1;min-height:0;width:100%;height:100%;border:none;background:var(--dshpc-surface-1)}\n";
|
|
154
|
+
//#endregion
|
|
155
|
+
//#region ../../node_modules/.pnpm/dsh-plugin-core@0.5.0_@babel+runtime@8.0.8_@codemirror+autocomplete@6.20.4_@codemirror+_bddbf1bc7ba0e94be71f734653121d0c/node_modules/dsh-plugin-core/dist/session/session-css.generated.js
|
|
156
|
+
const SESSION_CSS = "/* 会话预览(SessionViewModal)自绘样式:只装本包自己的组件(暂存输入区 / fork / 探针等)\n + 两个稳定钩子类(dshpc-sv-frame / dshpc-sv-scroll)。\n 已删:ChangedFiles 卡与 FileDiff 的全部自绘规则(2026-10-24)——官方 ChangedFiles /\n FileDiff 模块类由 officialClass() 运行时发现并挂在元素上,本包不再有一行兜底。\n ⚠️ 2026-10-23 起不再有官方类兜底:镜像官方组件的元素一律挂官方 CSS-module 类名\n (officialClass() 运行时发现,取不到 = 空类、裸结构不白屏)——本包只跑 DSH 宿主、官方样式必在场,\n 自绘一一对应是死代码。要改官方观感走 token 覆盖 / 双类名钩子(见 ChatView.ts 头注),别在这加兜底。\n 类名固定 dshpc-sv-*;颜色一律走 --dshpc-* token(明暗自适应)。\n 外壳(遮罩 / 面板 / 头部 / 关闭钮)= 核心 Modal(size lg)。 */\n/* 会话区 = 普通纵向流:不设高度、不自己滚(滚动与内距归核心 Modal body,用户 2026-10-22 口径)。 */\n.dshpc-sv{display:flex;flex-direction:column;min-width:0;gap:10px}\n\n/* 官方样式未命中时的可见探针(挂在头部副标题行,不占正文)。 */\n.dshpc-sv-probe{font-size:var(--dshpc-font-xs);color:var(--dshpc-warning,#b7791f)}\n\n/* 头部归档标识(官方归档图标 + 「已归档」)。 */\n.dshpc-sv-archived{display:inline-flex;align-items:center;gap:4px;font-size:var(--dshpc-font-xs);font-weight:400;color:var(--dshpc-fg-3)}\n\n/* 内距与滚动全部让给核心 Modal body ⇒ 这里把官方 ChatView.frame / scroll 的内距、\n overflow、高度一律归零(双类名 0,2,0 压过 CSS module,不靠注入顺序)。\n ⚠️ 必须同时把 flex 收掉:官方 scroll 是 flex:1(basis=0),在**自动高**的容器里会把\n 会话区压成 0 高 —— 这正是「内容自管高度」的老毛病,别再放回来。 */\n.dshpc-sv-frame.dshpc-sv-frame{padding-top:0;padding-bottom:0;}\n\n.dshpc-sv-scroll.dshpc-sv-scroll{padding:0;overflow:visible;height:auto;max-height:none;flex:none;}\n\n/* 会话区保底:高度由内容决定(撑开由 Modal body 滚)。 */\n.dshpc-sv-chat{flex:none;min-height:0;}\n\n\n.dshpc-sv-assistant{align-self:stretch;font-size:var(--dshpc-font-lg);line-height:1.7;word-break:break-word;}\n\n.dshpc-sv-image{align-self:flex-start;font-size:var(--dshpc-font-sm);color:var(--dshpc-fg-3,rgba(128,128,128,.8));border:1px dashed var(--dshpc-border,rgba(128,128,128,.35));border-radius:var(--dshpc-radius-sm);padding:4px 10px;}\n\n/* 工具卡根(SessionViewModal legacy 兜底渲染直接用;正常 keyed 路径一律挂官方 ToolRow 类)。 */\n.dshpc-sv-tool{flex-direction:column;display:flex;}\n\n.dshpc-sv-notice{align-self:center;font-size:var(--dshpc-font-sm);color:var(--dshpc-fg-3,rgba(128,128,128,.8));padding:2px 8px;}\n\n\n.dshpc-sv-forkerr{margin:0;font-size:var(--dshpc-font-lg);line-height:var(--dshpc-line-lg);color:var(--dshpc-danger,#e5484d);word-break:break-word;}\n\n.dshpc-sv-forktext{margin:0;font-size:var(--dshpc-font-sm);line-height:var(--dshpc-line-sm);color:var(--dshpc-fg-2);}\n\n/* ── 暂存输入区(期4:打字 → 确定 → fork 带话跳官方视图)── */\n.dshpc-sv-composer{flex:1;display:flex;align-items:flex-end;gap:8px;flex-wrap:wrap;}\n\n.dshpc-sv-composer textarea{flex:1;min-width:0;resize:none;font:inherit;font-size:var(--dshpc-font-lg);line-height:var(--dshpc-line-lg);color:var(--dshpc-fg,#1f2328);background:var(--dshpc-surface-2,rgba(128,128,128,.10));border:1px solid var(--dshpc-border,rgba(128,128,128,.28));border-radius:var(--dshpc-radius-md);padding:8px 12px;min-height:40px;max-height:120px;}\n\n.dshpc-sv-composer textarea:focus-visible{outline:2px solid var(--dshpc-focus,#3b5bdb);outline-offset:-1px;}\n\n.dshpc-sv-composer-hint{flex:none;font-size:var(--dshpc-font-xs);color:var(--dshpc-fg-3,rgba(128,128,128,.8));padding-bottom:10px;white-space:nowrap;}";
|
|
157
|
+
//#endregion
|
|
158
|
+
//#region ../../node_modules/.pnpm/dsh-plugin-core@0.5.0_@babel+runtime@8.0.8_@codemirror+autocomplete@6.20.4_@codemirror+_bddbf1bc7ba0e94be71f734653121d0c/node_modules/dsh-plugin-core/dist/ui/css.js
|
|
159
|
+
const CONTROLS_DOMAIN = "controls";
|
|
160
|
+
/**
|
|
161
|
+
* 全部控件样式(数组顺序不可调换:同特异性规则后注入者胜出)。
|
|
162
|
+
* 导出仅供 `test/css-contract.test.mjs` 做文本自检,不作为对外 API。
|
|
163
|
+
*/
|
|
164
|
+
const CONTROLS_CSS = [
|
|
165
|
+
SEGMENTED_CSS,
|
|
166
|
+
BUTTON_CSS,
|
|
167
|
+
FIELD_CSS,
|
|
168
|
+
LOADING_CSS,
|
|
169
|
+
BACK_TO_TOP_CSS,
|
|
170
|
+
HINT_CSS,
|
|
171
|
+
PICKER_CSS,
|
|
172
|
+
DATETIME_CSS,
|
|
173
|
+
FEEDBACK_CSS,
|
|
174
|
+
EXPLORER_CSS,
|
|
175
|
+
SESSION_CSS,
|
|
176
|
+
CARD_CSS,
|
|
177
|
+
CHIP_CSS,
|
|
178
|
+
MARQUEE_CSS,
|
|
179
|
+
PANEL_DOCK_CSS,
|
|
180
|
+
CODE_VIEWER_CSS
|
|
181
|
+
].join("\n");
|
|
182
|
+
/**
|
|
183
|
+
* 当前插件的样式设施。
|
|
184
|
+
*
|
|
185
|
+
* 为什么是模块级而不是 React Context:core 会被**内联进每个插件各自的 bundle**,
|
|
186
|
+
* 模块级变量天然按插件隔离(不像共享运行时那样会互相踩)。
|
|
187
|
+
* 插件启动时 `setStyleKit(createStyleKit({ id }))` 一次即可;不设就走默认 kit。
|
|
188
|
+
*/
|
|
189
|
+
let current$1 = createStyleKit({ id: "dsh-plugin-core-ui" });
|
|
190
|
+
function setStyleKit(kit) {
|
|
191
|
+
current$1 = kit;
|
|
192
|
+
}
|
|
193
|
+
/** 登记 token + 控件样式并确保挂载(幂等)。 */
|
|
194
|
+
function ensureControls(kit = current$1) {
|
|
195
|
+
kit.registerStyle("tokens", kit.tokensCss);
|
|
196
|
+
kit.applyStyle(CONTROLS_DOMAIN, CONTROLS_CSS);
|
|
197
|
+
}
|
|
198
|
+
//#endregion
|
|
199
|
+
//#region ../../node_modules/.pnpm/dsh-plugin-core@0.5.0_@babel+runtime@8.0.8_@codemirror+autocomplete@6.20.4_@codemirror+_bddbf1bc7ba0e94be71f734653121d0c/node_modules/dsh-plugin-core/dist/ui/picker-logic.js
|
|
200
|
+
/** 两种输入归一成 groups:给了 `options` 就当成一个无标题的组。 */
|
|
201
|
+
function toGroups(groups, options) {
|
|
202
|
+
if (groups !== void 0 && groups.length > 0) return groups;
|
|
203
|
+
const flat = options ?? [];
|
|
204
|
+
return flat.length === 0 ? [] : [{
|
|
205
|
+
value: "",
|
|
206
|
+
label: "",
|
|
207
|
+
options: flat
|
|
208
|
+
}];
|
|
209
|
+
}
|
|
210
|
+
function flattenOptions(groups) {
|
|
211
|
+
const out = [];
|
|
212
|
+
for (const g of groups) out.push(...g.options);
|
|
213
|
+
return out;
|
|
214
|
+
}
|
|
215
|
+
/** 按关键词过滤(大小写不敏感,匹配 label;整组无命中则整组去掉)。 */
|
|
216
|
+
function filterGroups(groups, query) {
|
|
217
|
+
const q = query.trim().toLowerCase();
|
|
218
|
+
if (q === "") return groups;
|
|
219
|
+
const out = [];
|
|
220
|
+
for (const g of groups) {
|
|
221
|
+
const hit = g.options.filter((o) => o.label.toLowerCase().includes(q));
|
|
222
|
+
if (hit.length > 0) out.push({
|
|
223
|
+
...g,
|
|
224
|
+
options: hit
|
|
225
|
+
});
|
|
226
|
+
}
|
|
227
|
+
return out;
|
|
228
|
+
}
|
|
229
|
+
/** 多选切换;`max` 达到上限时不再添加(返回原数组,不静默截断)。 */
|
|
230
|
+
function toggleValue(current, value, max) {
|
|
231
|
+
if (current.indexOf(value) >= 0) return current.filter((v) => v !== value);
|
|
232
|
+
if (max !== void 0 && current.length >= max) return [...current];
|
|
233
|
+
return [...current, value];
|
|
234
|
+
}
|
|
235
|
+
function labelsOf(groups, values) {
|
|
236
|
+
const all = flattenOptions(groups);
|
|
237
|
+
const out = [];
|
|
238
|
+
for (const v of values) {
|
|
239
|
+
const hit = all.find((o) => o.value === v);
|
|
240
|
+
if (hit !== void 0) out.push(hit.label);
|
|
241
|
+
}
|
|
242
|
+
return out;
|
|
243
|
+
}
|
|
244
|
+
//#endregion
|
|
245
|
+
//#region ../../node_modules/.pnpm/@floating-ui+utils@0.2.12/node_modules/@floating-ui/utils/dist/floating-ui.utils.dom.mjs
|
|
246
|
+
function hasWindow() {
|
|
247
|
+
return typeof window !== "undefined";
|
|
248
|
+
}
|
|
249
|
+
function getNodeName(node) {
|
|
250
|
+
if (isNode(node)) return (node.nodeName || "").toLowerCase();
|
|
251
|
+
return "#document";
|
|
252
|
+
}
|
|
253
|
+
function getWindow(node) {
|
|
254
|
+
var _node$ownerDocument;
|
|
255
|
+
return (node == null || (_node$ownerDocument = node.ownerDocument) == null ? void 0 : _node$ownerDocument.defaultView) || window;
|
|
256
|
+
}
|
|
257
|
+
function getDocumentElement(node) {
|
|
258
|
+
var _ref;
|
|
259
|
+
return (_ref = (isNode(node) ? node.ownerDocument : node.document) || window.document) == null ? void 0 : _ref.documentElement;
|
|
260
|
+
}
|
|
261
|
+
function isNode(value) {
|
|
262
|
+
if (!hasWindow()) return false;
|
|
263
|
+
return value instanceof Node || value instanceof getWindow(value).Node;
|
|
264
|
+
}
|
|
265
|
+
function isElement(value) {
|
|
266
|
+
if (!hasWindow()) return false;
|
|
267
|
+
return value instanceof Element || value instanceof getWindow(value).Element;
|
|
268
|
+
}
|
|
269
|
+
function isHTMLElement(value) {
|
|
270
|
+
if (!hasWindow()) return false;
|
|
271
|
+
return value instanceof HTMLElement || value instanceof getWindow(value).HTMLElement;
|
|
272
|
+
}
|
|
273
|
+
function isShadowRoot(value) {
|
|
274
|
+
if (!hasWindow() || typeof ShadowRoot === "undefined") return false;
|
|
275
|
+
return value instanceof ShadowRoot || value instanceof getWindow(value).ShadowRoot;
|
|
276
|
+
}
|
|
277
|
+
function isOverflowElement(element) {
|
|
278
|
+
const { overflow, overflowX, overflowY, display } = getComputedStyle$1(element);
|
|
279
|
+
return /auto|scroll|overlay|hidden|clip/.test(overflow + overflowY + overflowX) && display !== "inline" && display !== "contents";
|
|
280
|
+
}
|
|
281
|
+
function isTableElement(element) {
|
|
282
|
+
return /^(table|td|th)$/.test(getNodeName(element));
|
|
283
|
+
}
|
|
284
|
+
function isTopLayer(element) {
|
|
285
|
+
try {
|
|
286
|
+
if (element.matches(":popover-open")) return true;
|
|
287
|
+
} catch (_e) {}
|
|
288
|
+
try {
|
|
289
|
+
return element.matches(":modal");
|
|
290
|
+
} catch (_e) {
|
|
291
|
+
return false;
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
const willChangeRe = /transform|translate|scale|rotate|perspective|filter/;
|
|
295
|
+
const containRe = /paint|layout|strict|content/;
|
|
296
|
+
const isNotNone = (value) => !!value && value !== "none";
|
|
297
|
+
let isWebKitValue;
|
|
298
|
+
function isContainingBlock(elementOrCss) {
|
|
299
|
+
const css = isElement(elementOrCss) ? getComputedStyle$1(elementOrCss) : elementOrCss;
|
|
300
|
+
return isNotNone(css.transform) || isNotNone(css.translate) || isNotNone(css.scale) || isNotNone(css.rotate) || isNotNone(css.perspective) || !isWebKit() && (isNotNone(css.backdropFilter) || isNotNone(css.filter)) || willChangeRe.test(css.willChange || "") || containRe.test(css.contain || "");
|
|
301
|
+
}
|
|
302
|
+
function getContainingBlock(element) {
|
|
303
|
+
let currentNode = getParentNode(element);
|
|
304
|
+
while (isHTMLElement(currentNode) && !isLastTraversableNode(currentNode)) {
|
|
305
|
+
if (isContainingBlock(currentNode)) return currentNode;
|
|
306
|
+
else if (isTopLayer(currentNode)) return null;
|
|
307
|
+
currentNode = getParentNode(currentNode);
|
|
308
|
+
}
|
|
309
|
+
return null;
|
|
310
|
+
}
|
|
311
|
+
function isWebKit() {
|
|
312
|
+
if (isWebKitValue == null) isWebKitValue = typeof CSS !== "undefined" && CSS.supports && CSS.supports("-webkit-backdrop-filter", "none");
|
|
313
|
+
return isWebKitValue;
|
|
314
|
+
}
|
|
315
|
+
function isLastTraversableNode(node) {
|
|
316
|
+
return /^(html|body|#document)$/.test(getNodeName(node));
|
|
317
|
+
}
|
|
318
|
+
function getComputedStyle$1(element) {
|
|
319
|
+
return getWindow(element).getComputedStyle(element);
|
|
320
|
+
}
|
|
321
|
+
function getNodeScroll(element) {
|
|
322
|
+
if (isElement(element)) return {
|
|
323
|
+
scrollLeft: element.scrollLeft,
|
|
324
|
+
scrollTop: element.scrollTop
|
|
325
|
+
};
|
|
326
|
+
return {
|
|
327
|
+
scrollLeft: element.scrollX,
|
|
328
|
+
scrollTop: element.scrollY
|
|
329
|
+
};
|
|
330
|
+
}
|
|
331
|
+
function getParentNode(node) {
|
|
332
|
+
if (getNodeName(node) === "html") return node;
|
|
333
|
+
const result = node.assignedSlot || node.parentNode || isShadowRoot(node) && node.host || getDocumentElement(node);
|
|
334
|
+
return isShadowRoot(result) ? result.host : result;
|
|
335
|
+
}
|
|
336
|
+
function getNearestOverflowAncestor(node) {
|
|
337
|
+
const parentNode = getParentNode(node);
|
|
338
|
+
if (isLastTraversableNode(parentNode)) return (node.ownerDocument || node).body;
|
|
339
|
+
if (isHTMLElement(parentNode) && isOverflowElement(parentNode)) return parentNode;
|
|
340
|
+
return getNearestOverflowAncestor(parentNode);
|
|
341
|
+
}
|
|
342
|
+
function getOverflowAncestors(node, list, traverseIframes) {
|
|
343
|
+
var _node$ownerDocument2;
|
|
344
|
+
if (list === void 0) list = [];
|
|
345
|
+
if (traverseIframes === void 0) traverseIframes = true;
|
|
346
|
+
const scrollableAncestor = getNearestOverflowAncestor(node);
|
|
347
|
+
const isBody = scrollableAncestor === ((_node$ownerDocument2 = node.ownerDocument) == null ? void 0 : _node$ownerDocument2.body);
|
|
348
|
+
const win = getWindow(scrollableAncestor);
|
|
349
|
+
if (isBody) {
|
|
350
|
+
const frameElement = getFrameElement(win);
|
|
351
|
+
return list.concat(win, win.visualViewport || [], isOverflowElement(scrollableAncestor) ? scrollableAncestor : [], frameElement && traverseIframes ? getOverflowAncestors(frameElement) : []);
|
|
352
|
+
} else return list.concat(scrollableAncestor, getOverflowAncestors(scrollableAncestor, [], traverseIframes));
|
|
353
|
+
}
|
|
354
|
+
function getFrameElement(win) {
|
|
355
|
+
return win.parent && Object.getPrototypeOf(win.parent) ? win.frameElement : null;
|
|
356
|
+
}
|
|
357
|
+
//#endregion
|
|
358
|
+
//#region ../../node_modules/.pnpm/@floating-ui+utils@0.2.12/node_modules/@floating-ui/utils/dist/floating-ui.utils.mjs
|
|
359
|
+
const min = Math.min;
|
|
360
|
+
const max = Math.max;
|
|
361
|
+
const round = Math.round;
|
|
362
|
+
const floor = Math.floor;
|
|
363
|
+
const createCoords = (v) => ({
|
|
364
|
+
x: v,
|
|
365
|
+
y: v
|
|
366
|
+
});
|
|
367
|
+
const oppositeSideMap = {
|
|
368
|
+
left: "right",
|
|
369
|
+
right: "left",
|
|
370
|
+
bottom: "top",
|
|
371
|
+
top: "bottom"
|
|
372
|
+
};
|
|
373
|
+
function clamp(start, value, end) {
|
|
374
|
+
return max(start, min(value, end));
|
|
375
|
+
}
|
|
376
|
+
function evaluate(value, param) {
|
|
377
|
+
return typeof value === "function" ? value(param) : value;
|
|
378
|
+
}
|
|
379
|
+
function getSide(placement) {
|
|
380
|
+
return placement.split("-")[0];
|
|
381
|
+
}
|
|
382
|
+
function getAlignment(placement) {
|
|
383
|
+
return placement.split("-")[1];
|
|
384
|
+
}
|
|
385
|
+
function getOppositeAxis(axis) {
|
|
386
|
+
return axis === "x" ? "y" : "x";
|
|
387
|
+
}
|
|
388
|
+
function getAxisLength(axis) {
|
|
389
|
+
return axis === "y" ? "height" : "width";
|
|
390
|
+
}
|
|
391
|
+
function getSideAxis(placement) {
|
|
392
|
+
const firstChar = placement[0];
|
|
393
|
+
return firstChar === "t" || firstChar === "b" ? "y" : "x";
|
|
394
|
+
}
|
|
395
|
+
function getAlignmentAxis(placement) {
|
|
396
|
+
return getOppositeAxis(getSideAxis(placement));
|
|
397
|
+
}
|
|
398
|
+
function getAlignmentSides(placement, rects, rtl) {
|
|
399
|
+
if (rtl === void 0) rtl = false;
|
|
400
|
+
const alignment = getAlignment(placement);
|
|
401
|
+
const alignmentAxis = getAlignmentAxis(placement);
|
|
402
|
+
const length = getAxisLength(alignmentAxis);
|
|
403
|
+
let mainAlignmentSide = alignmentAxis === "x" ? alignment === (rtl ? "end" : "start") ? "right" : "left" : alignment === "start" ? "bottom" : "top";
|
|
404
|
+
if (rects.reference[length] > rects.floating[length]) mainAlignmentSide = getOppositePlacement(mainAlignmentSide);
|
|
405
|
+
return [mainAlignmentSide, getOppositePlacement(mainAlignmentSide)];
|
|
406
|
+
}
|
|
407
|
+
function getExpandedPlacements(placement) {
|
|
408
|
+
const oppositePlacement = getOppositePlacement(placement);
|
|
409
|
+
return [
|
|
410
|
+
getOppositeAlignmentPlacement(placement),
|
|
411
|
+
oppositePlacement,
|
|
412
|
+
getOppositeAlignmentPlacement(oppositePlacement)
|
|
413
|
+
];
|
|
414
|
+
}
|
|
415
|
+
function getOppositeAlignmentPlacement(placement) {
|
|
416
|
+
return placement.includes("start") ? placement.replace("start", "end") : placement.replace("end", "start");
|
|
417
|
+
}
|
|
418
|
+
const lrPlacement = ["left", "right"];
|
|
419
|
+
const rlPlacement = ["right", "left"];
|
|
420
|
+
const tbPlacement = ["top", "bottom"];
|
|
421
|
+
const btPlacement = ["bottom", "top"];
|
|
422
|
+
function getSideList(side, isStart, rtl) {
|
|
423
|
+
switch (side) {
|
|
424
|
+
case "top":
|
|
425
|
+
case "bottom":
|
|
426
|
+
if (rtl) return isStart ? rlPlacement : lrPlacement;
|
|
427
|
+
return isStart ? lrPlacement : rlPlacement;
|
|
428
|
+
case "left":
|
|
429
|
+
case "right": return isStart ? tbPlacement : btPlacement;
|
|
430
|
+
default: return [];
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
function getOppositeAxisPlacements(placement, flipAlignment, direction, rtl) {
|
|
434
|
+
const alignment = getAlignment(placement);
|
|
435
|
+
let list = getSideList(getSide(placement), direction === "start", rtl);
|
|
436
|
+
if (alignment) {
|
|
437
|
+
list = list.map((side) => side + "-" + alignment);
|
|
438
|
+
if (flipAlignment) list = list.concat(list.map(getOppositeAlignmentPlacement));
|
|
439
|
+
}
|
|
440
|
+
return list;
|
|
441
|
+
}
|
|
442
|
+
function getOppositePlacement(placement) {
|
|
443
|
+
const side = getSide(placement);
|
|
444
|
+
return oppositeSideMap[side] + placement.slice(side.length);
|
|
445
|
+
}
|
|
446
|
+
function expandPaddingObject(padding) {
|
|
447
|
+
var _padding$top, _padding$right, _padding$bottom, _padding$left;
|
|
448
|
+
return {
|
|
449
|
+
top: (_padding$top = padding.top) != null ? _padding$top : 0,
|
|
450
|
+
right: (_padding$right = padding.right) != null ? _padding$right : 0,
|
|
451
|
+
bottom: (_padding$bottom = padding.bottom) != null ? _padding$bottom : 0,
|
|
452
|
+
left: (_padding$left = padding.left) != null ? _padding$left : 0
|
|
453
|
+
};
|
|
454
|
+
}
|
|
455
|
+
function getPaddingObject(padding) {
|
|
456
|
+
return typeof padding !== "number" ? expandPaddingObject(padding) : {
|
|
457
|
+
top: padding,
|
|
458
|
+
right: padding,
|
|
459
|
+
bottom: padding,
|
|
460
|
+
left: padding
|
|
461
|
+
};
|
|
462
|
+
}
|
|
463
|
+
function rectToClientRect(rect) {
|
|
464
|
+
const { x, y, width, height } = rect;
|
|
465
|
+
return {
|
|
466
|
+
width,
|
|
467
|
+
height,
|
|
468
|
+
top: y,
|
|
469
|
+
left: x,
|
|
470
|
+
right: x + width,
|
|
471
|
+
bottom: y + height,
|
|
472
|
+
x,
|
|
473
|
+
y
|
|
474
|
+
};
|
|
475
|
+
}
|
|
476
|
+
/*!
|
|
477
|
+
* tabbable 6.5.1
|
|
478
|
+
* @license MIT, https://github.com/focus-trap/tabbable/blob/master/LICENSE
|
|
479
|
+
*/
|
|
480
|
+
//#endregion
|
|
481
|
+
//#region ../../node_modules/.pnpm/@floating-ui+react@0.27.20_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/@floating-ui/react/dist/floating-ui.react.utils.mjs
|
|
482
|
+
var import_dist = (/* @__PURE__ */ __commonJSMin(((exports) => {
|
|
483
|
+
var candidateSelector = /* #__PURE__ */ [
|
|
484
|
+
"input:not([inert]):not([inert] *)",
|
|
485
|
+
"select:not([inert]):not([inert] *)",
|
|
486
|
+
"textarea:not([inert]):not([inert] *)",
|
|
487
|
+
"a[href]:not([inert]):not([inert] *)",
|
|
488
|
+
"area[href]:not([inert]):not([inert] *)",
|
|
489
|
+
"button:not([inert]):not([inert] *)",
|
|
490
|
+
"[tabindex]:not(slot):not([inert]):not([inert] *)",
|
|
491
|
+
"audio[controls]:not([inert]):not([inert] *)",
|
|
492
|
+
"video[controls]:not([inert]):not([inert] *)",
|
|
493
|
+
"[contenteditable]:not([contenteditable=\"false\"]):not([inert]):not([inert] *)",
|
|
494
|
+
"details>summary:first-of-type:not([inert]):not([inert] *)",
|
|
495
|
+
"details:not([inert]):not([inert] *)"
|
|
496
|
+
].join(",");
|
|
497
|
+
var NoElement = typeof Element === "undefined";
|
|
498
|
+
var matches = NoElement ? function() {} : Element.prototype.matches || Element.prototype.msMatchesSelector || Element.prototype.webkitMatchesSelector;
|
|
499
|
+
var getRootNode = !NoElement && Element.prototype.getRootNode ? function(element) {
|
|
500
|
+
return element == null || element.getRootNode == null ? void 0 : element.getRootNode();
|
|
501
|
+
} : function(element) {
|
|
502
|
+
return element == null ? void 0 : element.ownerDocument;
|
|
503
|
+
};
|
|
504
|
+
/**
|
|
505
|
+
* Determines if a node is inert or in an inert ancestor.
|
|
506
|
+
* @param {Node} [node]
|
|
507
|
+
* @param {boolean} [lookUp] If true and `node` is not inert, looks up at ancestors to
|
|
508
|
+
* see if any of them are inert. If false, only `node` itself is considered.
|
|
509
|
+
* @returns {boolean} True if inert itself or by way of being in an inert ancestor.
|
|
510
|
+
* False if `node` is falsy.
|
|
511
|
+
*/
|
|
512
|
+
var _isInert = function isInert(node, lookUp) {
|
|
513
|
+
if (lookUp === void 0) lookUp = true;
|
|
514
|
+
var inertAtt = node == null || node.getAttribute == null ? void 0 : node.getAttribute("inert");
|
|
515
|
+
return inertAtt === "" || inertAtt === "true" || lookUp && node && (typeof node.closest === "function" ? node.closest("[inert]") : _isInert(node.parentNode));
|
|
516
|
+
};
|
|
517
|
+
/**
|
|
518
|
+
* Determines if a node's content is editable.
|
|
519
|
+
* @param {Element} [node]
|
|
520
|
+
* @returns True if it's content-editable; false if it's not or `node` is falsy.
|
|
521
|
+
*/
|
|
522
|
+
var isContentEditable = function isContentEditable(node) {
|
|
523
|
+
var _node$getAttribute;
|
|
524
|
+
var attValue = node == null || node.getAttribute == null || (_node$getAttribute = node.getAttribute("contenteditable")) == null ? void 0 : _node$getAttribute.toLowerCase();
|
|
525
|
+
return attValue === "" || attValue === "true" || attValue === "plaintext-only";
|
|
526
|
+
};
|
|
527
|
+
/**
|
|
528
|
+
* @param {Element} el container to check in
|
|
529
|
+
* @param {boolean} includeContainer add container to check
|
|
530
|
+
* @param {(node: Element) => boolean} filter filter candidates
|
|
531
|
+
* @returns {Element[]}
|
|
532
|
+
*/
|
|
533
|
+
var getCandidates = function getCandidates(el, includeContainer, filter) {
|
|
534
|
+
if (_isInert(el)) return [];
|
|
535
|
+
var candidates = Array.prototype.slice.apply(el.querySelectorAll(candidateSelector));
|
|
536
|
+
if (includeContainer && matches.call(el, candidateSelector)) candidates.unshift(el);
|
|
537
|
+
candidates = candidates.filter(filter);
|
|
538
|
+
return candidates;
|
|
539
|
+
};
|
|
540
|
+
/**
|
|
541
|
+
* @callback GetShadowRoot
|
|
542
|
+
* @param {Element} element to check for shadow root
|
|
543
|
+
* @returns {ShadowRoot|boolean} ShadowRoot if available or boolean indicating if a shadowRoot is attached but not available.
|
|
544
|
+
*/
|
|
545
|
+
/**
|
|
546
|
+
* @callback ShadowRootFilter
|
|
547
|
+
* @param {Element} shadowHostNode the element which contains shadow content
|
|
548
|
+
* @returns {boolean} true if a shadow root could potentially contain valid candidates.
|
|
549
|
+
*/
|
|
550
|
+
/**
|
|
551
|
+
* @typedef {Object} CandidateScope
|
|
552
|
+
* @property {Element} scopeParent contains inner candidates
|
|
553
|
+
* @property {Element[]} candidates list of candidates found in the scope parent
|
|
554
|
+
*/
|
|
555
|
+
/**
|
|
556
|
+
* @typedef {Object} IterativeOptions
|
|
557
|
+
* @property {GetShadowRoot|boolean} getShadowRoot true if shadow support is enabled; falsy if not;
|
|
558
|
+
* if a function, implies shadow support is enabled and either returns the shadow root of an element
|
|
559
|
+
* or a boolean stating if it has an undisclosed shadow root
|
|
560
|
+
* @property {(node: Element) => boolean} filter filter candidates
|
|
561
|
+
* @property {boolean} flatten if true then result will flatten any CandidateScope into the returned list
|
|
562
|
+
* @property {ShadowRootFilter} shadowRootFilter filter shadow roots;
|
|
563
|
+
*/
|
|
564
|
+
/**
|
|
565
|
+
* @param {Element[]} elements list of element containers to match candidates from
|
|
566
|
+
* @param {boolean} includeContainer add container list to check
|
|
567
|
+
* @param {IterativeOptions} options
|
|
568
|
+
* @returns {Array.<Element|CandidateScope>}
|
|
569
|
+
*/
|
|
570
|
+
var _getCandidatesIteratively = function getCandidatesIteratively(elements, includeContainer, options) {
|
|
571
|
+
var candidates = [];
|
|
572
|
+
var elementsToCheck = Array.from(elements);
|
|
573
|
+
while (elementsToCheck.length) {
|
|
574
|
+
var element = elementsToCheck.shift();
|
|
575
|
+
if (_isInert(element, false)) continue;
|
|
576
|
+
if (element.tagName === "SLOT") {
|
|
577
|
+
var assigned = element.assignedElements();
|
|
578
|
+
var nestedCandidates = _getCandidatesIteratively(assigned.length ? assigned : element.children, true, options);
|
|
579
|
+
if (options.flatten) candidates.push.apply(candidates, nestedCandidates);
|
|
580
|
+
else candidates.push({
|
|
581
|
+
scopeParent: element,
|
|
582
|
+
candidates: nestedCandidates
|
|
583
|
+
});
|
|
584
|
+
} else {
|
|
585
|
+
if (matches.call(element, candidateSelector) && options.filter(element) && (includeContainer || !elements.includes(element))) candidates.push(element);
|
|
586
|
+
var shadowRoot = element.shadowRoot || typeof options.getShadowRoot === "function" && options.getShadowRoot(element);
|
|
587
|
+
var validShadowRoot = !_isInert(shadowRoot, false) && (!options.shadowRootFilter || options.shadowRootFilter(element));
|
|
588
|
+
if (shadowRoot && validShadowRoot) {
|
|
589
|
+
var _nestedCandidates = _getCandidatesIteratively(shadowRoot === true ? element.children : shadowRoot.children, true, options);
|
|
590
|
+
if (options.flatten) candidates.push.apply(candidates, _nestedCandidates);
|
|
591
|
+
else candidates.push({
|
|
592
|
+
scopeParent: element,
|
|
593
|
+
candidates: _nestedCandidates
|
|
594
|
+
});
|
|
595
|
+
} else elementsToCheck.unshift.apply(elementsToCheck, element.children);
|
|
596
|
+
}
|
|
597
|
+
}
|
|
598
|
+
return candidates;
|
|
599
|
+
};
|
|
600
|
+
/**
|
|
601
|
+
* @private
|
|
602
|
+
* Determines if the node has an explicitly specified `tabindex` attribute.
|
|
603
|
+
* @param {HTMLElement} node
|
|
604
|
+
* @returns {boolean} True if so; false if not.
|
|
605
|
+
*/
|
|
606
|
+
var hasTabIndex = function hasTabIndex(node) {
|
|
607
|
+
return !isNaN(parseInt(node.getAttribute("tabindex"), 10));
|
|
608
|
+
};
|
|
609
|
+
/**
|
|
610
|
+
* Determine the tab index of a given node.
|
|
611
|
+
* @param {HTMLElement} node
|
|
612
|
+
* @returns {number} Tab order (negative, 0, or positive number).
|
|
613
|
+
* @throws {Error} If `node` is falsy.
|
|
614
|
+
*/
|
|
615
|
+
var getTabIndex = function getTabIndex(node) {
|
|
616
|
+
if (!node) throw new Error("No node provided");
|
|
617
|
+
if (node.tabIndex < 0) {
|
|
618
|
+
if ((/^(AUDIO|VIDEO|DETAILS)$/.test(node.tagName) || isContentEditable(node)) && !hasTabIndex(node)) return 0;
|
|
619
|
+
}
|
|
620
|
+
return node.tabIndex;
|
|
621
|
+
};
|
|
622
|
+
/**
|
|
623
|
+
* Determine the tab index of a given node __for sort order purposes__.
|
|
624
|
+
* @param {HTMLElement} node
|
|
625
|
+
* @param {boolean} [isScope] True for a custom element with shadow root or slot that, by default,
|
|
626
|
+
* has tabIndex -1, but needs to be sorted by document order in order for its content to be
|
|
627
|
+
* inserted into the correct sort position.
|
|
628
|
+
* @returns {number} Tab order (negative, 0, or positive number).
|
|
629
|
+
*/
|
|
630
|
+
var getSortOrderTabIndex = function getSortOrderTabIndex(node, isScope) {
|
|
631
|
+
var tabIndex = getTabIndex(node);
|
|
632
|
+
if (tabIndex < 0 && isScope && !hasTabIndex(node)) return 0;
|
|
633
|
+
return tabIndex;
|
|
634
|
+
};
|
|
635
|
+
var sortOrderedTabbables = function sortOrderedTabbables(a, b) {
|
|
636
|
+
return a.tabIndex === b.tabIndex ? a.documentOrder - b.documentOrder : a.tabIndex - b.tabIndex;
|
|
637
|
+
};
|
|
638
|
+
var isInput = function isInput(node) {
|
|
639
|
+
return node.tagName === "INPUT";
|
|
640
|
+
};
|
|
641
|
+
var isHiddenInput = function isHiddenInput(node) {
|
|
642
|
+
return isInput(node) && node.type === "hidden";
|
|
643
|
+
};
|
|
644
|
+
var isDetailsWithSummary = function isDetailsWithSummary(node) {
|
|
645
|
+
return node.tagName === "DETAILS" && Array.prototype.slice.apply(node.children).some(function(child) {
|
|
646
|
+
return child.tagName === "SUMMARY";
|
|
647
|
+
});
|
|
648
|
+
};
|
|
649
|
+
var getCheckedRadio = function getCheckedRadio(nodes, form) {
|
|
650
|
+
for (var i = 0; i < nodes.length; i++) if (nodes[i].checked && nodes[i].form === form) return nodes[i];
|
|
651
|
+
};
|
|
652
|
+
var isTabbableRadio = function isTabbableRadio(node) {
|
|
653
|
+
if (!node.name) return true;
|
|
654
|
+
var radioScope = node.form || getRootNode(node);
|
|
655
|
+
var queryRadios = function queryRadios(name) {
|
|
656
|
+
return radioScope.querySelectorAll("input[type=\"radio\"][name=\"" + name + "\"]");
|
|
657
|
+
};
|
|
658
|
+
var radioSet;
|
|
659
|
+
if (typeof window !== "undefined" && typeof window.CSS !== "undefined" && typeof window.CSS.escape === "function") radioSet = queryRadios(window.CSS.escape(node.name));
|
|
660
|
+
else try {
|
|
661
|
+
radioSet = queryRadios(node.name);
|
|
662
|
+
} catch (err) {
|
|
663
|
+
console.error("Looks like you have a radio button with a name attribute containing invalid CSS selector characters and need the CSS.escape polyfill: %s", err.message);
|
|
664
|
+
return false;
|
|
665
|
+
}
|
|
666
|
+
var checked = getCheckedRadio(radioSet, node.form);
|
|
667
|
+
return !checked || checked === node;
|
|
668
|
+
};
|
|
669
|
+
var isRadio = function isRadio(node) {
|
|
670
|
+
return isInput(node) && node.type === "radio";
|
|
671
|
+
};
|
|
672
|
+
var isNonTabbableRadio = function isNonTabbableRadio(node) {
|
|
673
|
+
return isRadio(node) && !isTabbableRadio(node);
|
|
674
|
+
};
|
|
675
|
+
var isNodeAttached = function isNodeAttached(node) {
|
|
676
|
+
var _nodeRoot;
|
|
677
|
+
var nodeRoot = node && getRootNode(node);
|
|
678
|
+
var nodeRootHost = (_nodeRoot = nodeRoot) == null ? void 0 : _nodeRoot.host;
|
|
679
|
+
var attached = false;
|
|
680
|
+
if (nodeRoot && nodeRoot !== node) {
|
|
681
|
+
var _nodeRootHost, _node$ownerDocument;
|
|
682
|
+
attached = !!((_nodeRootHost = nodeRootHost) != null && (_nodeRootHost = _nodeRootHost.ownerDocument) != null && _nodeRootHost.contains(nodeRootHost) || node != null && (_node$ownerDocument = node.ownerDocument) != null && _node$ownerDocument.contains(node));
|
|
683
|
+
while (!attached && nodeRootHost) {
|
|
684
|
+
var _nodeRoot2, _nodeRootHost2;
|
|
685
|
+
nodeRoot = getRootNode(nodeRootHost);
|
|
686
|
+
nodeRootHost = (_nodeRoot2 = nodeRoot) == null ? void 0 : _nodeRoot2.host;
|
|
687
|
+
attached = !!((_nodeRootHost2 = nodeRootHost) != null && (_nodeRootHost2 = _nodeRootHost2.ownerDocument) != null && _nodeRootHost2.contains(nodeRootHost));
|
|
688
|
+
}
|
|
689
|
+
}
|
|
690
|
+
return attached;
|
|
691
|
+
};
|
|
692
|
+
var isZeroArea = function isZeroArea(node) {
|
|
693
|
+
var _node$getBoundingClie = node.getBoundingClientRect(), width = _node$getBoundingClie.width, height = _node$getBoundingClie.height;
|
|
694
|
+
return width === 0 && height === 0;
|
|
695
|
+
};
|
|
696
|
+
var isHidden = function isHidden(node, _ref) {
|
|
697
|
+
var displayCheck = _ref.displayCheck, getShadowRoot = _ref.getShadowRoot;
|
|
698
|
+
if (displayCheck === "full-native") {
|
|
699
|
+
if ("checkVisibility" in node) return !node.checkVisibility({
|
|
700
|
+
checkOpacity: false,
|
|
701
|
+
opacityProperty: false,
|
|
702
|
+
contentVisibilityAuto: true,
|
|
703
|
+
visibilityProperty: true,
|
|
704
|
+
checkVisibilityCSS: true
|
|
705
|
+
});
|
|
706
|
+
}
|
|
707
|
+
var visibility = getComputedStyle(node).visibility;
|
|
708
|
+
if (visibility === "hidden" || visibility === "collapse") return true;
|
|
709
|
+
var nodeUnderDetails = matches.call(node, "details>summary:first-of-type") ? node.parentElement : node;
|
|
710
|
+
if (matches.call(nodeUnderDetails, "details:not([open]) *")) return true;
|
|
711
|
+
if (!displayCheck || displayCheck === "full" || displayCheck === "full-native" || displayCheck === "legacy-full") {
|
|
712
|
+
if (typeof getShadowRoot === "function") {
|
|
713
|
+
var originalNode = node;
|
|
714
|
+
while (node) {
|
|
715
|
+
var parentElement = node.parentElement;
|
|
716
|
+
var rootNode = getRootNode(node);
|
|
717
|
+
if (parentElement && !parentElement.shadowRoot && getShadowRoot(parentElement) === true) return isZeroArea(node);
|
|
718
|
+
else if (node.assignedSlot) node = node.assignedSlot;
|
|
719
|
+
else if (!parentElement && rootNode !== node.ownerDocument) node = rootNode.host;
|
|
720
|
+
else node = parentElement;
|
|
721
|
+
}
|
|
722
|
+
node = originalNode;
|
|
723
|
+
}
|
|
724
|
+
if (isNodeAttached(node)) return !node.getClientRects().length;
|
|
725
|
+
if (displayCheck !== "legacy-full") return true;
|
|
726
|
+
} else if (displayCheck === "non-zero-area") return isZeroArea(node);
|
|
727
|
+
return false;
|
|
728
|
+
};
|
|
729
|
+
var isDisabledFromFieldset = function isDisabledFromFieldset(node) {
|
|
730
|
+
if (/^(INPUT|BUTTON|SELECT|TEXTAREA)$/.test(node.tagName)) {
|
|
731
|
+
var parentNode = node.parentElement;
|
|
732
|
+
while (parentNode) {
|
|
733
|
+
if (parentNode.tagName === "FIELDSET" && parentNode.disabled) {
|
|
734
|
+
for (var i = 0; i < parentNode.children.length; i++) {
|
|
735
|
+
var child = parentNode.children.item(i);
|
|
736
|
+
if (child.tagName === "LEGEND") return matches.call(parentNode, "fieldset[disabled] *") ? true : !child.contains(node);
|
|
737
|
+
}
|
|
738
|
+
return true;
|
|
739
|
+
}
|
|
740
|
+
parentNode = parentNode.parentElement;
|
|
741
|
+
}
|
|
742
|
+
}
|
|
743
|
+
return false;
|
|
744
|
+
};
|
|
745
|
+
var isNodeMatchingSelectorFocusable = function isNodeMatchingSelectorFocusable(options, node) {
|
|
746
|
+
if (node.disabled || isHiddenInput(node) || isHidden(node, options) || isDetailsWithSummary(node) || isDisabledFromFieldset(node)) return false;
|
|
747
|
+
return true;
|
|
748
|
+
};
|
|
749
|
+
var isNodeMatchingSelectorTabbable = function isNodeMatchingSelectorTabbable(options, node) {
|
|
750
|
+
if (isNonTabbableRadio(node) || getTabIndex(node) < 0 || !isNodeMatchingSelectorFocusable(options, node)) return false;
|
|
751
|
+
return true;
|
|
752
|
+
};
|
|
753
|
+
var isShadowRootTabbable = function isShadowRootTabbable(shadowHostNode) {
|
|
754
|
+
var tabIndex = parseInt(shadowHostNode.getAttribute("tabindex"), 10);
|
|
755
|
+
if (isNaN(tabIndex) || tabIndex >= 0) return true;
|
|
756
|
+
return false;
|
|
757
|
+
};
|
|
758
|
+
/**
|
|
759
|
+
* @param {Array.<Element|CandidateScope>} candidates
|
|
760
|
+
* @returns Element[]
|
|
761
|
+
*/
|
|
762
|
+
var _sortByOrder = function sortByOrder(candidates) {
|
|
763
|
+
var regularTabbables = [];
|
|
764
|
+
var orderedTabbables = [];
|
|
765
|
+
candidates.forEach(function(item, i) {
|
|
766
|
+
var isScope = !!item.scopeParent;
|
|
767
|
+
var element = isScope ? item.scopeParent : item;
|
|
768
|
+
var candidateTabindex = getSortOrderTabIndex(element, isScope);
|
|
769
|
+
var elements = isScope ? _sortByOrder(item.candidates) : element;
|
|
770
|
+
if (candidateTabindex === 0) isScope ? regularTabbables.push.apply(regularTabbables, elements) : regularTabbables.push(element);
|
|
771
|
+
else orderedTabbables.push({
|
|
772
|
+
documentOrder: i,
|
|
773
|
+
tabIndex: candidateTabindex,
|
|
774
|
+
item,
|
|
775
|
+
isScope,
|
|
776
|
+
content: elements
|
|
777
|
+
});
|
|
778
|
+
});
|
|
779
|
+
return orderedTabbables.sort(sortOrderedTabbables).reduce(function(acc, sortable) {
|
|
780
|
+
sortable.isScope ? acc.push.apply(acc, sortable.content) : acc.push(sortable.content);
|
|
781
|
+
return acc;
|
|
782
|
+
}, []).concat(regularTabbables);
|
|
783
|
+
};
|
|
784
|
+
exports.tabbable = function tabbable(container, options) {
|
|
785
|
+
options = options || {};
|
|
786
|
+
var candidates;
|
|
787
|
+
if (options.getShadowRoot) candidates = _getCandidatesIteratively([container], options.includeContainer, {
|
|
788
|
+
filter: isNodeMatchingSelectorTabbable.bind(null, options),
|
|
789
|
+
flatten: false,
|
|
790
|
+
getShadowRoot: options.getShadowRoot,
|
|
791
|
+
shadowRootFilter: isShadowRootTabbable
|
|
792
|
+
});
|
|
793
|
+
else candidates = getCandidates(container, options.includeContainer, isNodeMatchingSelectorTabbable.bind(null, options));
|
|
794
|
+
return _sortByOrder(candidates);
|
|
795
|
+
};
|
|
796
|
+
})))();
|
|
797
|
+
function isSafari() {
|
|
798
|
+
return /apple/i.test(navigator.vendor);
|
|
799
|
+
}
|
|
800
|
+
function activeElement(doc) {
|
|
801
|
+
let activeElement = doc.activeElement;
|
|
802
|
+
while (((_activeElement = activeElement) == null || (_activeElement = _activeElement.shadowRoot) == null ? void 0 : _activeElement.activeElement) != null) {
|
|
803
|
+
var _activeElement;
|
|
804
|
+
activeElement = activeElement.shadowRoot.activeElement;
|
|
805
|
+
}
|
|
806
|
+
return activeElement;
|
|
807
|
+
}
|
|
808
|
+
function contains(parent, child) {
|
|
809
|
+
if (!parent || !child) return false;
|
|
810
|
+
const rootNode = child.getRootNode == null ? void 0 : child.getRootNode();
|
|
811
|
+
if (parent.contains(child)) return true;
|
|
812
|
+
if (rootNode && isShadowRoot(rootNode)) {
|
|
813
|
+
let next = child;
|
|
814
|
+
while (next) {
|
|
815
|
+
if (parent === next) return true;
|
|
816
|
+
next = next.parentNode || next.host;
|
|
817
|
+
}
|
|
818
|
+
}
|
|
819
|
+
return false;
|
|
820
|
+
}
|
|
821
|
+
function getDocument(node) {
|
|
822
|
+
return (node == null ? void 0 : node.ownerDocument) || document;
|
|
823
|
+
}
|
|
824
|
+
var index$1 = typeof document !== "undefined" ? react.useLayoutEffect : function noop() {};
|
|
825
|
+
const useSafeInsertionEffect = { ...react }.useInsertionEffect || ((fn) => fn());
|
|
826
|
+
function useEffectEvent(callback) {
|
|
827
|
+
const ref = react.useRef(() => {});
|
|
828
|
+
useSafeInsertionEffect(() => {
|
|
829
|
+
ref.current = callback;
|
|
830
|
+
});
|
|
831
|
+
return react.useCallback(function() {
|
|
832
|
+
for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) args[_key] = arguments[_key];
|
|
833
|
+
return ref.current == null ? void 0 : ref.current(...args);
|
|
834
|
+
}, []);
|
|
835
|
+
}
|
|
836
|
+
const getTabbableOptions = () => ({
|
|
837
|
+
getShadowRoot: true,
|
|
838
|
+
displayCheck: typeof ResizeObserver === "function" && ResizeObserver.toString().includes("[native code]") ? "full" : "none"
|
|
839
|
+
});
|
|
840
|
+
function getTabbableIn(container, dir) {
|
|
841
|
+
const list = (0, import_dist.tabbable)(container, getTabbableOptions());
|
|
842
|
+
const len = list.length;
|
|
843
|
+
if (len === 0) return;
|
|
844
|
+
const active = activeElement(getDocument(container));
|
|
845
|
+
const index = list.indexOf(active);
|
|
846
|
+
return list[index === -1 ? dir === 1 ? 0 : len - 1 : index + dir];
|
|
847
|
+
}
|
|
848
|
+
function getNextTabbable(referenceElement) {
|
|
849
|
+
return getTabbableIn(getDocument(referenceElement).body, 1) || referenceElement;
|
|
850
|
+
}
|
|
851
|
+
function getPreviousTabbable(referenceElement) {
|
|
852
|
+
return getTabbableIn(getDocument(referenceElement).body, -1) || referenceElement;
|
|
853
|
+
}
|
|
854
|
+
function isOutsideEvent(event, container) {
|
|
855
|
+
const containerElement = container || event.currentTarget;
|
|
856
|
+
const relatedTarget = event.relatedTarget;
|
|
857
|
+
return !relatedTarget || !contains(containerElement, relatedTarget);
|
|
858
|
+
}
|
|
859
|
+
function disableFocusInside(container) {
|
|
860
|
+
(0, import_dist.tabbable)(container, getTabbableOptions()).forEach((element) => {
|
|
861
|
+
element.dataset.tabindex = element.getAttribute("tabindex") || "";
|
|
862
|
+
element.setAttribute("tabindex", "-1");
|
|
863
|
+
});
|
|
864
|
+
}
|
|
865
|
+
function enableFocusInside(container) {
|
|
866
|
+
container.querySelectorAll("[data-tabindex]").forEach((element) => {
|
|
867
|
+
const tabindex = element.dataset.tabindex;
|
|
868
|
+
delete element.dataset.tabindex;
|
|
869
|
+
if (tabindex) element.setAttribute("tabindex", tabindex);
|
|
870
|
+
else element.removeAttribute("tabindex");
|
|
871
|
+
});
|
|
872
|
+
}
|
|
873
|
+
//#endregion
|
|
874
|
+
//#region ../../node_modules/.pnpm/@floating-ui+core@1.8.0/node_modules/@floating-ui/core/dist/floating-ui.core.mjs
|
|
875
|
+
function computeCoordsFromPlacement(_ref, placement, rtl) {
|
|
876
|
+
let { reference, floating } = _ref;
|
|
877
|
+
const sideAxis = getSideAxis(placement);
|
|
878
|
+
const alignmentAxis = getAlignmentAxis(placement);
|
|
879
|
+
const alignLength = getAxisLength(alignmentAxis);
|
|
880
|
+
const side = getSide(placement);
|
|
881
|
+
const isVertical = sideAxis === "y";
|
|
882
|
+
const commonX = reference.x + reference.width / 2 - floating.width / 2;
|
|
883
|
+
const commonY = reference.y + reference.height / 2 - floating.height / 2;
|
|
884
|
+
const commonAlign = reference[alignLength] / 2 - floating[alignLength] / 2;
|
|
885
|
+
let coords;
|
|
886
|
+
switch (side) {
|
|
887
|
+
case "top":
|
|
888
|
+
coords = {
|
|
889
|
+
x: commonX,
|
|
890
|
+
y: reference.y - floating.height
|
|
891
|
+
};
|
|
892
|
+
break;
|
|
893
|
+
case "bottom":
|
|
894
|
+
coords = {
|
|
895
|
+
x: commonX,
|
|
896
|
+
y: reference.y + reference.height
|
|
897
|
+
};
|
|
898
|
+
break;
|
|
899
|
+
case "right":
|
|
900
|
+
coords = {
|
|
901
|
+
x: reference.x + reference.width,
|
|
902
|
+
y: commonY
|
|
903
|
+
};
|
|
904
|
+
break;
|
|
905
|
+
case "left":
|
|
906
|
+
coords = {
|
|
907
|
+
x: reference.x - floating.width,
|
|
908
|
+
y: commonY
|
|
909
|
+
};
|
|
910
|
+
break;
|
|
911
|
+
default: coords = {
|
|
912
|
+
x: reference.x,
|
|
913
|
+
y: reference.y
|
|
914
|
+
};
|
|
915
|
+
}
|
|
916
|
+
const alignment = getAlignment(placement);
|
|
917
|
+
if (alignment) coords[alignmentAxis] += commonAlign * (alignment === "end" ? 1 : -1) * (rtl && isVertical ? -1 : 1);
|
|
918
|
+
return coords;
|
|
919
|
+
}
|
|
920
|
+
/**
|
|
921
|
+
* Resolves with an object of overflow side offsets that determine how much the
|
|
922
|
+
* element is overflowing a given clipping boundary on each side.
|
|
923
|
+
* - positive = overflowing the boundary by that number of pixels
|
|
924
|
+
* - negative = how many pixels left before it will overflow
|
|
925
|
+
* - 0 = lies flush with the boundary
|
|
926
|
+
* @see https://floating-ui.com/docs/detectOverflow
|
|
927
|
+
*/
|
|
928
|
+
async function detectOverflow(state, options) {
|
|
929
|
+
var _await$platform$isEle;
|
|
930
|
+
if (options === void 0) options = {};
|
|
931
|
+
const { x, y, platform, rects, elements, strategy } = state;
|
|
932
|
+
const { boundary = "clippingAncestors", rootBoundary = "viewport", elementContext = "floating", altBoundary = false, padding = 0 } = evaluate(options, state);
|
|
933
|
+
const paddingObject = getPaddingObject(padding);
|
|
934
|
+
const element = elements[altBoundary ? elementContext === "floating" ? "reference" : "floating" : elementContext];
|
|
935
|
+
const clippingClientRect = rectToClientRect(await platform.getClippingRect({
|
|
936
|
+
element: ((_await$platform$isEle = await (platform.isElement == null ? void 0 : platform.isElement(element))) != null ? _await$platform$isEle : true) ? element : element.contextElement || await (platform.getDocumentElement == null ? void 0 : platform.getDocumentElement(elements.floating)),
|
|
937
|
+
boundary,
|
|
938
|
+
rootBoundary,
|
|
939
|
+
strategy
|
|
940
|
+
}));
|
|
941
|
+
const rect = elementContext === "floating" ? {
|
|
942
|
+
x,
|
|
943
|
+
y,
|
|
944
|
+
width: rects.floating.width,
|
|
945
|
+
height: rects.floating.height
|
|
946
|
+
} : rects.reference;
|
|
947
|
+
const offsetParent = await (platform.getOffsetParent == null ? void 0 : platform.getOffsetParent(elements.floating));
|
|
948
|
+
const offsetScale = await (platform.isElement == null ? void 0 : platform.isElement(offsetParent)) && await (platform.getScale == null ? void 0 : platform.getScale(offsetParent)) || {
|
|
949
|
+
x: 1,
|
|
950
|
+
y: 1
|
|
951
|
+
};
|
|
952
|
+
const elementClientRect = rectToClientRect(platform.convertOffsetParentRelativeRectToViewportRelativeRect ? await platform.convertOffsetParentRelativeRectToViewportRelativeRect({
|
|
953
|
+
elements,
|
|
954
|
+
rect,
|
|
955
|
+
offsetParent,
|
|
956
|
+
strategy
|
|
957
|
+
}) : rect);
|
|
958
|
+
return {
|
|
959
|
+
top: (clippingClientRect.top - elementClientRect.top + paddingObject.top) / offsetScale.y,
|
|
960
|
+
bottom: (elementClientRect.bottom - clippingClientRect.bottom + paddingObject.bottom) / offsetScale.y,
|
|
961
|
+
left: (clippingClientRect.left - elementClientRect.left + paddingObject.left) / offsetScale.x,
|
|
962
|
+
right: (elementClientRect.right - clippingClientRect.right + paddingObject.right) / offsetScale.x
|
|
963
|
+
};
|
|
964
|
+
}
|
|
965
|
+
const MAX_RESET_COUNT = 50;
|
|
966
|
+
/**
|
|
967
|
+
* Computes the `x` and `y` coordinates that will place the floating element
|
|
968
|
+
* next to a given reference element.
|
|
969
|
+
*
|
|
970
|
+
* This export does not have any `platform` interface logic. You will need to
|
|
971
|
+
* write one for the platform you are using Floating UI with.
|
|
972
|
+
*/
|
|
973
|
+
const computePosition$1 = async (reference, floating, config) => {
|
|
974
|
+
const { placement = "bottom", strategy = "absolute", middleware = [], platform } = config;
|
|
975
|
+
const platformWithDetectOverflow = platform.detectOverflow ? platform : {
|
|
976
|
+
...platform,
|
|
977
|
+
detectOverflow
|
|
978
|
+
};
|
|
979
|
+
const rtl = await (platform.isRTL == null ? void 0 : platform.isRTL(floating));
|
|
980
|
+
let rects = await platform.getElementRects({
|
|
981
|
+
reference,
|
|
982
|
+
floating,
|
|
983
|
+
strategy
|
|
984
|
+
});
|
|
985
|
+
let { x, y } = computeCoordsFromPlacement(rects, placement, rtl);
|
|
986
|
+
let statefulPlacement = placement;
|
|
987
|
+
let resetCount = 0;
|
|
988
|
+
const middlewareData = {};
|
|
989
|
+
for (let i = 0; i < middleware.length; i++) {
|
|
990
|
+
const currentMiddleware = middleware[i];
|
|
991
|
+
if (!currentMiddleware) continue;
|
|
992
|
+
const { name, fn } = currentMiddleware;
|
|
993
|
+
const { x: nextX, y: nextY, data, reset } = await fn({
|
|
994
|
+
x,
|
|
995
|
+
y,
|
|
996
|
+
initialPlacement: placement,
|
|
997
|
+
placement: statefulPlacement,
|
|
998
|
+
strategy,
|
|
999
|
+
middlewareData,
|
|
1000
|
+
rects,
|
|
1001
|
+
platform: platformWithDetectOverflow,
|
|
1002
|
+
elements: {
|
|
1003
|
+
reference,
|
|
1004
|
+
floating
|
|
1005
|
+
}
|
|
1006
|
+
});
|
|
1007
|
+
x = nextX != null ? nextX : x;
|
|
1008
|
+
y = nextY != null ? nextY : y;
|
|
1009
|
+
middlewareData[name] = {
|
|
1010
|
+
...middlewareData[name],
|
|
1011
|
+
...data
|
|
1012
|
+
};
|
|
1013
|
+
if (reset && resetCount < MAX_RESET_COUNT) {
|
|
1014
|
+
resetCount++;
|
|
1015
|
+
if (typeof reset === "object") {
|
|
1016
|
+
if (reset.placement) statefulPlacement = reset.placement;
|
|
1017
|
+
if (reset.rects) rects = reset.rects === true ? await platform.getElementRects({
|
|
1018
|
+
reference,
|
|
1019
|
+
floating,
|
|
1020
|
+
strategy
|
|
1021
|
+
}) : reset.rects;
|
|
1022
|
+
({x, y} = computeCoordsFromPlacement(rects, statefulPlacement, rtl));
|
|
1023
|
+
}
|
|
1024
|
+
i = -1;
|
|
1025
|
+
}
|
|
1026
|
+
}
|
|
1027
|
+
return {
|
|
1028
|
+
x,
|
|
1029
|
+
y,
|
|
1030
|
+
placement: statefulPlacement,
|
|
1031
|
+
strategy,
|
|
1032
|
+
middlewareData
|
|
1033
|
+
};
|
|
1034
|
+
};
|
|
1035
|
+
/**
|
|
1036
|
+
* Optimizes the visibility of the floating element by flipping the `placement`
|
|
1037
|
+
* in order to keep it in view when the preferred placement(s) will overflow the
|
|
1038
|
+
* clipping boundary. Alternative to `autoPlacement`.
|
|
1039
|
+
* @see https://floating-ui.com/docs/flip
|
|
1040
|
+
*/
|
|
1041
|
+
const flip$1 = function(options) {
|
|
1042
|
+
if (options === void 0) options = {};
|
|
1043
|
+
return {
|
|
1044
|
+
name: "flip",
|
|
1045
|
+
options,
|
|
1046
|
+
async fn(state) {
|
|
1047
|
+
var _middlewareData$arrow, _middlewareData$flip;
|
|
1048
|
+
const { placement, middlewareData, rects, initialPlacement, platform, elements } = state;
|
|
1049
|
+
const { mainAxis: checkMainAxis = true, crossAxis: checkCrossAxis = true, fallbackPlacements: specifiedFallbackPlacements, fallbackStrategy = "bestFit", fallbackAxisSideDirection = "none", flipAlignment = true, ...detectOverflowOptions } = evaluate(options, state);
|
|
1050
|
+
if ((_middlewareData$arrow = middlewareData.arrow) != null && _middlewareData$arrow.alignmentOffset) return {};
|
|
1051
|
+
const side = getSide(placement);
|
|
1052
|
+
const initialSideAxis = getSideAxis(initialPlacement);
|
|
1053
|
+
const isBasePlacement = getSide(initialPlacement) === initialPlacement;
|
|
1054
|
+
const rtl = await (platform.isRTL == null ? void 0 : platform.isRTL(elements.floating));
|
|
1055
|
+
const fallbackPlacements = specifiedFallbackPlacements || (isBasePlacement || !flipAlignment ? [getOppositePlacement(initialPlacement)] : getExpandedPlacements(initialPlacement));
|
|
1056
|
+
const hasFallbackAxisSideDirection = fallbackAxisSideDirection !== "none";
|
|
1057
|
+
if (!specifiedFallbackPlacements && hasFallbackAxisSideDirection) fallbackPlacements.push(...getOppositeAxisPlacements(initialPlacement, flipAlignment, fallbackAxisSideDirection, rtl));
|
|
1058
|
+
const placements = [initialPlacement, ...fallbackPlacements];
|
|
1059
|
+
const overflow = await platform.detectOverflow(state, detectOverflowOptions);
|
|
1060
|
+
const overflows = [];
|
|
1061
|
+
let overflowsData = ((_middlewareData$flip = middlewareData.flip) == null ? void 0 : _middlewareData$flip.overflows) || [];
|
|
1062
|
+
if (checkMainAxis) overflows.push(overflow[side]);
|
|
1063
|
+
if (checkCrossAxis) {
|
|
1064
|
+
const sides = getAlignmentSides(placement, rects, rtl);
|
|
1065
|
+
overflows.push(overflow[sides[0]], overflow[sides[1]]);
|
|
1066
|
+
}
|
|
1067
|
+
overflowsData = [...overflowsData, {
|
|
1068
|
+
placement,
|
|
1069
|
+
overflows
|
|
1070
|
+
}];
|
|
1071
|
+
if (!overflows.every((side) => side <= 0)) {
|
|
1072
|
+
var _middlewareData$flip2, _overflowsData$filter;
|
|
1073
|
+
const nextIndex = (((_middlewareData$flip2 = middlewareData.flip) == null ? void 0 : _middlewareData$flip2.index) || 0) + 1;
|
|
1074
|
+
const nextPlacement = placements[nextIndex];
|
|
1075
|
+
if (nextPlacement) {
|
|
1076
|
+
if (!(checkCrossAxis === "alignment" ? initialSideAxis !== getSideAxis(nextPlacement) : false) || overflowsData.every((d) => getSideAxis(d.placement) === initialSideAxis ? d.overflows[0] > 0 : true)) return {
|
|
1077
|
+
data: {
|
|
1078
|
+
index: nextIndex,
|
|
1079
|
+
overflows: overflowsData
|
|
1080
|
+
},
|
|
1081
|
+
reset: { placement: nextPlacement }
|
|
1082
|
+
};
|
|
1083
|
+
}
|
|
1084
|
+
let resetPlacement = (_overflowsData$filter = overflowsData.filter((d) => d.overflows[0] <= 0).sort((a, b) => a.overflows[1] - b.overflows[1])[0]) == null ? void 0 : _overflowsData$filter.placement;
|
|
1085
|
+
if (!resetPlacement) switch (fallbackStrategy) {
|
|
1086
|
+
case "bestFit": {
|
|
1087
|
+
var _overflowsData$filter2;
|
|
1088
|
+
const placement = (_overflowsData$filter2 = overflowsData.filter((d) => {
|
|
1089
|
+
if (hasFallbackAxisSideDirection) {
|
|
1090
|
+
const currentSideAxis = getSideAxis(d.placement);
|
|
1091
|
+
return currentSideAxis === initialSideAxis || currentSideAxis === "y";
|
|
1092
|
+
}
|
|
1093
|
+
return true;
|
|
1094
|
+
}).map((d) => [d.placement, d.overflows.filter((overflow) => overflow > 0).reduce((acc, overflow) => acc + overflow, 0)]).sort((a, b) => a[1] - b[1])[0]) == null ? void 0 : _overflowsData$filter2[0];
|
|
1095
|
+
if (placement) resetPlacement = placement;
|
|
1096
|
+
break;
|
|
1097
|
+
}
|
|
1098
|
+
case "initialPlacement": resetPlacement = initialPlacement;
|
|
1099
|
+
}
|
|
1100
|
+
if (placement !== resetPlacement) return { reset: { placement: resetPlacement } };
|
|
1101
|
+
}
|
|
1102
|
+
return {};
|
|
1103
|
+
}
|
|
1104
|
+
};
|
|
1105
|
+
};
|
|
1106
|
+
const originSides = /*#__PURE__*/ new Set(["left", "top"]);
|
|
1107
|
+
async function convertValueToCoords(state, options) {
|
|
1108
|
+
const { placement, platform, elements } = state;
|
|
1109
|
+
const rtl = await (platform.isRTL == null ? void 0 : platform.isRTL(elements.floating));
|
|
1110
|
+
const side = getSide(placement);
|
|
1111
|
+
const alignment = getAlignment(placement);
|
|
1112
|
+
const isVertical = getSideAxis(placement) === "y";
|
|
1113
|
+
const mainAxisMulti = originSides.has(side) ? -1 : 1;
|
|
1114
|
+
const crossAxisMulti = rtl && isVertical ? -1 : 1;
|
|
1115
|
+
const rawValue = evaluate(options, state);
|
|
1116
|
+
let { mainAxis, crossAxis, alignmentAxis } = typeof rawValue === "number" ? {
|
|
1117
|
+
mainAxis: rawValue,
|
|
1118
|
+
crossAxis: 0,
|
|
1119
|
+
alignmentAxis: null
|
|
1120
|
+
} : {
|
|
1121
|
+
mainAxis: rawValue.mainAxis || 0,
|
|
1122
|
+
crossAxis: rawValue.crossAxis || 0,
|
|
1123
|
+
alignmentAxis: rawValue.alignmentAxis
|
|
1124
|
+
};
|
|
1125
|
+
if (alignment && typeof alignmentAxis === "number") crossAxis = alignment === "end" ? alignmentAxis * -1 : alignmentAxis;
|
|
1126
|
+
return isVertical ? {
|
|
1127
|
+
x: crossAxis * crossAxisMulti,
|
|
1128
|
+
y: mainAxis * mainAxisMulti
|
|
1129
|
+
} : {
|
|
1130
|
+
x: mainAxis * mainAxisMulti,
|
|
1131
|
+
y: crossAxis * crossAxisMulti
|
|
1132
|
+
};
|
|
1133
|
+
}
|
|
1134
|
+
/**
|
|
1135
|
+
* Modifies the placement by translating the floating element along the
|
|
1136
|
+
* specified axes.
|
|
1137
|
+
* A number (shorthand for `mainAxis` or distance), or an axes configuration
|
|
1138
|
+
* object may be passed.
|
|
1139
|
+
* @see https://floating-ui.com/docs/offset
|
|
1140
|
+
*/
|
|
1141
|
+
const offset$1 = function(options) {
|
|
1142
|
+
if (options === void 0) options = 0;
|
|
1143
|
+
return {
|
|
1144
|
+
name: "offset",
|
|
1145
|
+
options,
|
|
1146
|
+
async fn(state) {
|
|
1147
|
+
var _middlewareData$offse, _middlewareData$arrow;
|
|
1148
|
+
const { x, y, placement, middlewareData } = state;
|
|
1149
|
+
const diffCoords = await convertValueToCoords(state, options);
|
|
1150
|
+
if (placement === ((_middlewareData$offse = middlewareData.offset) == null ? void 0 : _middlewareData$offse.placement) && (_middlewareData$arrow = middlewareData.arrow) != null && _middlewareData$arrow.alignmentOffset) return {};
|
|
1151
|
+
return {
|
|
1152
|
+
x: x + diffCoords.x,
|
|
1153
|
+
y: y + diffCoords.y,
|
|
1154
|
+
data: {
|
|
1155
|
+
...diffCoords,
|
|
1156
|
+
placement
|
|
1157
|
+
}
|
|
1158
|
+
};
|
|
1159
|
+
}
|
|
1160
|
+
};
|
|
1161
|
+
};
|
|
1162
|
+
/**
|
|
1163
|
+
* Optimizes the visibility of the floating element by shifting it in order to
|
|
1164
|
+
* keep it in view when it will overflow the clipping boundary.
|
|
1165
|
+
* @see https://floating-ui.com/docs/shift
|
|
1166
|
+
*/
|
|
1167
|
+
const shift$1 = function(options) {
|
|
1168
|
+
if (options === void 0) options = {};
|
|
1169
|
+
return {
|
|
1170
|
+
name: "shift",
|
|
1171
|
+
options,
|
|
1172
|
+
async fn(state) {
|
|
1173
|
+
const { x, y, placement, platform } = state;
|
|
1174
|
+
const { mainAxis: checkMainAxis = true, crossAxis: checkCrossAxis = false, limiter = { fn: (_ref) => {
|
|
1175
|
+
let { x, y } = _ref;
|
|
1176
|
+
return {
|
|
1177
|
+
x,
|
|
1178
|
+
y
|
|
1179
|
+
};
|
|
1180
|
+
} }, ...detectOverflowOptions } = evaluate(options, state);
|
|
1181
|
+
const coords = {
|
|
1182
|
+
x,
|
|
1183
|
+
y
|
|
1184
|
+
};
|
|
1185
|
+
const overflow = await platform.detectOverflow(state, detectOverflowOptions);
|
|
1186
|
+
const crossAxis = getSideAxis(placement);
|
|
1187
|
+
const mainAxis = getOppositeAxis(crossAxis);
|
|
1188
|
+
let mainAxisCoord = coords[mainAxis];
|
|
1189
|
+
let crossAxisCoord = coords[crossAxis];
|
|
1190
|
+
const clampCoord = (axis, coord) => clamp(coord + overflow[axis === "y" ? "top" : "left"], coord, coord - overflow[axis === "y" ? "bottom" : "right"]);
|
|
1191
|
+
if (checkMainAxis) mainAxisCoord = clampCoord(mainAxis, mainAxisCoord);
|
|
1192
|
+
if (checkCrossAxis) crossAxisCoord = clampCoord(crossAxis, crossAxisCoord);
|
|
1193
|
+
const limitedCoords = limiter.fn({
|
|
1194
|
+
...state,
|
|
1195
|
+
[mainAxis]: mainAxisCoord,
|
|
1196
|
+
[crossAxis]: crossAxisCoord
|
|
1197
|
+
});
|
|
1198
|
+
return {
|
|
1199
|
+
...limitedCoords,
|
|
1200
|
+
data: {
|
|
1201
|
+
x: limitedCoords.x - x,
|
|
1202
|
+
y: limitedCoords.y - y,
|
|
1203
|
+
enabled: {
|
|
1204
|
+
[mainAxis]: checkMainAxis,
|
|
1205
|
+
[crossAxis]: checkCrossAxis
|
|
1206
|
+
}
|
|
1207
|
+
}
|
|
1208
|
+
};
|
|
1209
|
+
}
|
|
1210
|
+
};
|
|
1211
|
+
};
|
|
1212
|
+
/**
|
|
1213
|
+
* Provides data that allows you to change the size of the floating element —
|
|
1214
|
+
* for instance, prevent it from overflowing the clipping boundary or match the
|
|
1215
|
+
* width of the reference element.
|
|
1216
|
+
* @see https://floating-ui.com/docs/size
|
|
1217
|
+
*/
|
|
1218
|
+
const size$1 = function(options) {
|
|
1219
|
+
if (options === void 0) options = {};
|
|
1220
|
+
return {
|
|
1221
|
+
name: "size",
|
|
1222
|
+
options,
|
|
1223
|
+
async fn(state) {
|
|
1224
|
+
const { placement, rects, platform, elements } = state;
|
|
1225
|
+
const { apply = () => {}, ...detectOverflowOptions } = evaluate(options, state);
|
|
1226
|
+
const overflow = await platform.detectOverflow(state, detectOverflowOptions);
|
|
1227
|
+
const side = getSide(placement);
|
|
1228
|
+
const alignment = getAlignment(placement);
|
|
1229
|
+
const isYAxis = getSideAxis(placement) === "y";
|
|
1230
|
+
const { width, height } = rects.floating;
|
|
1231
|
+
let heightSide;
|
|
1232
|
+
let widthSide;
|
|
1233
|
+
if (side === "top" || side === "bottom") {
|
|
1234
|
+
heightSide = side;
|
|
1235
|
+
widthSide = alignment === (await (platform.isRTL == null ? void 0 : platform.isRTL(elements.floating)) ? "start" : "end") ? "left" : "right";
|
|
1236
|
+
} else {
|
|
1237
|
+
widthSide = side;
|
|
1238
|
+
heightSide = alignment === "end" ? "top" : "bottom";
|
|
1239
|
+
}
|
|
1240
|
+
const maximumClippingHeight = height - overflow.top - overflow.bottom;
|
|
1241
|
+
const maximumClippingWidth = width - overflow.left - overflow.right;
|
|
1242
|
+
const overflowAvailableHeight = min(height - overflow[heightSide], maximumClippingHeight);
|
|
1243
|
+
const overflowAvailableWidth = min(width - overflow[widthSide], maximumClippingWidth);
|
|
1244
|
+
const shiftData = state.middlewareData.shift;
|
|
1245
|
+
const noShift = !shiftData;
|
|
1246
|
+
let availableHeight = overflowAvailableHeight;
|
|
1247
|
+
let availableWidth = overflowAvailableWidth;
|
|
1248
|
+
if (shiftData != null && shiftData.enabled.x) availableWidth = maximumClippingWidth;
|
|
1249
|
+
if (shiftData != null && shiftData.enabled.y) availableHeight = maximumClippingHeight;
|
|
1250
|
+
if (noShift && !alignment) {
|
|
1251
|
+
if (isYAxis) availableWidth = width - 2 * max(overflow.left, overflow.right);
|
|
1252
|
+
else availableHeight = height - 2 * max(overflow.top, overflow.bottom);
|
|
1253
|
+
}
|
|
1254
|
+
await apply({
|
|
1255
|
+
...state,
|
|
1256
|
+
availableWidth,
|
|
1257
|
+
availableHeight
|
|
1258
|
+
});
|
|
1259
|
+
const nextDimensions = await platform.getDimensions(elements.floating);
|
|
1260
|
+
if (width !== nextDimensions.width || height !== nextDimensions.height) return { reset: { rects: true } };
|
|
1261
|
+
return {};
|
|
1262
|
+
}
|
|
1263
|
+
};
|
|
1264
|
+
};
|
|
1265
|
+
//#endregion
|
|
1266
|
+
//#region ../../node_modules/.pnpm/@floating-ui+dom@1.8.0/node_modules/@floating-ui/dom/dist/floating-ui.dom.mjs
|
|
1267
|
+
function getCssDimensions(element) {
|
|
1268
|
+
const css = getComputedStyle$1(element);
|
|
1269
|
+
let width = parseFloat(css.width) || 0;
|
|
1270
|
+
let height = parseFloat(css.height) || 0;
|
|
1271
|
+
const hasOffset = isHTMLElement(element);
|
|
1272
|
+
const offsetWidth = hasOffset ? element.offsetWidth : width;
|
|
1273
|
+
const offsetHeight = hasOffset ? element.offsetHeight : height;
|
|
1274
|
+
const shouldFallback = round(width) !== offsetWidth || round(height) !== offsetHeight;
|
|
1275
|
+
if (shouldFallback) {
|
|
1276
|
+
width = offsetWidth;
|
|
1277
|
+
height = offsetHeight;
|
|
1278
|
+
}
|
|
1279
|
+
return {
|
|
1280
|
+
width,
|
|
1281
|
+
height,
|
|
1282
|
+
$: shouldFallback
|
|
1283
|
+
};
|
|
1284
|
+
}
|
|
1285
|
+
function unwrapElement(element) {
|
|
1286
|
+
return !isElement(element) ? element.contextElement : element;
|
|
1287
|
+
}
|
|
1288
|
+
function getScale(element) {
|
|
1289
|
+
const domElement = unwrapElement(element);
|
|
1290
|
+
if (!isHTMLElement(domElement)) return createCoords(1);
|
|
1291
|
+
const rect = domElement.getBoundingClientRect();
|
|
1292
|
+
const { width, height, $ } = getCssDimensions(domElement);
|
|
1293
|
+
let x = ($ ? round(rect.width) : rect.width) / width;
|
|
1294
|
+
let y = ($ ? round(rect.height) : rect.height) / height;
|
|
1295
|
+
if (!x || !Number.isFinite(x)) x = 1;
|
|
1296
|
+
if (!y || !Number.isFinite(y)) y = 1;
|
|
1297
|
+
return {
|
|
1298
|
+
x,
|
|
1299
|
+
y
|
|
1300
|
+
};
|
|
1301
|
+
}
|
|
1302
|
+
const noOffsets = /*#__PURE__*/ createCoords(0);
|
|
1303
|
+
function getVisualOffsets(element) {
|
|
1304
|
+
const win = getWindow(element);
|
|
1305
|
+
if (!isWebKit() || !win.visualViewport) return noOffsets;
|
|
1306
|
+
return {
|
|
1307
|
+
x: win.visualViewport.offsetLeft,
|
|
1308
|
+
y: win.visualViewport.offsetTop
|
|
1309
|
+
};
|
|
1310
|
+
}
|
|
1311
|
+
function shouldAddVisualOffsets(element, isFixed, floatingOffsetParent) {
|
|
1312
|
+
if (isFixed === void 0) isFixed = false;
|
|
1313
|
+
return !!floatingOffsetParent && isFixed && floatingOffsetParent === getWindow(element);
|
|
1314
|
+
}
|
|
1315
|
+
function getBoundingClientRect(element, includeScale, isFixedStrategy, offsetParent) {
|
|
1316
|
+
if (includeScale === void 0) includeScale = false;
|
|
1317
|
+
if (isFixedStrategy === void 0) isFixedStrategy = false;
|
|
1318
|
+
const clientRect = element.getBoundingClientRect();
|
|
1319
|
+
const domElement = unwrapElement(element);
|
|
1320
|
+
let scale = createCoords(1);
|
|
1321
|
+
if (includeScale) {
|
|
1322
|
+
if (offsetParent) {
|
|
1323
|
+
if (isElement(offsetParent)) scale = getScale(offsetParent);
|
|
1324
|
+
} else scale = getScale(element);
|
|
1325
|
+
}
|
|
1326
|
+
const visualOffsets = shouldAddVisualOffsets(domElement, isFixedStrategy, offsetParent) ? getVisualOffsets(domElement) : createCoords(0);
|
|
1327
|
+
let x = (clientRect.left + visualOffsets.x) / scale.x;
|
|
1328
|
+
let y = (clientRect.top + visualOffsets.y) / scale.y;
|
|
1329
|
+
let width = clientRect.width / scale.x;
|
|
1330
|
+
let height = clientRect.height / scale.y;
|
|
1331
|
+
if (domElement && offsetParent) {
|
|
1332
|
+
const win = getWindow(domElement);
|
|
1333
|
+
const offsetWin = isElement(offsetParent) ? getWindow(offsetParent) : offsetParent;
|
|
1334
|
+
let currentWin = win;
|
|
1335
|
+
let currentIFrame = getFrameElement(currentWin);
|
|
1336
|
+
while (currentIFrame && offsetWin !== currentWin) {
|
|
1337
|
+
const iframeScale = getScale(currentIFrame);
|
|
1338
|
+
const iframeRect = currentIFrame.getBoundingClientRect();
|
|
1339
|
+
const css = getComputedStyle$1(currentIFrame);
|
|
1340
|
+
const left = iframeRect.left + (currentIFrame.clientLeft + parseFloat(css.paddingLeft)) * iframeScale.x;
|
|
1341
|
+
const top = iframeRect.top + (currentIFrame.clientTop + parseFloat(css.paddingTop)) * iframeScale.y;
|
|
1342
|
+
x *= iframeScale.x;
|
|
1343
|
+
y *= iframeScale.y;
|
|
1344
|
+
width *= iframeScale.x;
|
|
1345
|
+
height *= iframeScale.y;
|
|
1346
|
+
x += left;
|
|
1347
|
+
y += top;
|
|
1348
|
+
currentWin = getWindow(currentIFrame);
|
|
1349
|
+
currentIFrame = getFrameElement(currentWin);
|
|
1350
|
+
}
|
|
1351
|
+
}
|
|
1352
|
+
return rectToClientRect({
|
|
1353
|
+
width,
|
|
1354
|
+
height,
|
|
1355
|
+
x,
|
|
1356
|
+
y
|
|
1357
|
+
});
|
|
1358
|
+
}
|
|
1359
|
+
function getWindowScrollBarX(element, rect) {
|
|
1360
|
+
const leftScroll = getNodeScroll(element).scrollLeft;
|
|
1361
|
+
if (!rect) return getBoundingClientRect(getDocumentElement(element)).left + leftScroll;
|
|
1362
|
+
return rect.left + leftScroll;
|
|
1363
|
+
}
|
|
1364
|
+
function getHTMLOffset(documentElement, scroll) {
|
|
1365
|
+
const htmlRect = documentElement.getBoundingClientRect();
|
|
1366
|
+
return {
|
|
1367
|
+
x: htmlRect.left + scroll.scrollLeft - getWindowScrollBarX(documentElement, htmlRect),
|
|
1368
|
+
y: htmlRect.top + scroll.scrollTop
|
|
1369
|
+
};
|
|
1370
|
+
}
|
|
1371
|
+
function convertOffsetParentRelativeRectToViewportRelativeRect(_ref) {
|
|
1372
|
+
let { elements, rect, offsetParent, strategy } = _ref;
|
|
1373
|
+
const isFixed = strategy === "fixed";
|
|
1374
|
+
const documentElement = getDocumentElement(offsetParent);
|
|
1375
|
+
const topLayer = elements ? isTopLayer(elements.floating) : false;
|
|
1376
|
+
if (offsetParent === documentElement || topLayer && isFixed) return rect;
|
|
1377
|
+
let scroll = {
|
|
1378
|
+
scrollLeft: 0,
|
|
1379
|
+
scrollTop: 0
|
|
1380
|
+
};
|
|
1381
|
+
let scale = createCoords(1);
|
|
1382
|
+
const offsets = createCoords(0);
|
|
1383
|
+
const isOffsetParentAnElement = isHTMLElement(offsetParent);
|
|
1384
|
+
if (isOffsetParentAnElement || !isFixed) {
|
|
1385
|
+
if (getNodeName(offsetParent) !== "body" || isOverflowElement(documentElement)) scroll = getNodeScroll(offsetParent);
|
|
1386
|
+
if (isOffsetParentAnElement) {
|
|
1387
|
+
const offsetRect = getBoundingClientRect(offsetParent);
|
|
1388
|
+
scale = getScale(offsetParent);
|
|
1389
|
+
offsets.x = offsetRect.x + offsetParent.clientLeft;
|
|
1390
|
+
offsets.y = offsetRect.y + offsetParent.clientTop;
|
|
1391
|
+
}
|
|
1392
|
+
}
|
|
1393
|
+
const htmlOffset = documentElement && !isOffsetParentAnElement && !isFixed ? getHTMLOffset(documentElement, scroll) : createCoords(0);
|
|
1394
|
+
return {
|
|
1395
|
+
width: rect.width * scale.x,
|
|
1396
|
+
height: rect.height * scale.y,
|
|
1397
|
+
x: rect.x * scale.x - scroll.scrollLeft * scale.x + offsets.x + htmlOffset.x,
|
|
1398
|
+
y: rect.y * scale.y - scroll.scrollTop * scale.y + offsets.y + htmlOffset.y
|
|
1399
|
+
};
|
|
1400
|
+
}
|
|
1401
|
+
function getClientRects(element) {
|
|
1402
|
+
return element.getClientRects ? Array.from(element.getClientRects()) : [];
|
|
1403
|
+
}
|
|
1404
|
+
function getDocumentRect(html) {
|
|
1405
|
+
const scroll = getNodeScroll(html);
|
|
1406
|
+
const body = html.ownerDocument.body;
|
|
1407
|
+
const width = max(html.scrollWidth, html.clientWidth, body.scrollWidth, body.clientWidth);
|
|
1408
|
+
const height = max(html.scrollHeight, html.clientHeight, body.scrollHeight, body.clientHeight);
|
|
1409
|
+
let x = -scroll.scrollLeft + getWindowScrollBarX(html);
|
|
1410
|
+
const y = -scroll.scrollTop;
|
|
1411
|
+
if (getComputedStyle$1(body).direction === "rtl") x += max(html.clientWidth, body.clientWidth) - width;
|
|
1412
|
+
return {
|
|
1413
|
+
width,
|
|
1414
|
+
height,
|
|
1415
|
+
x,
|
|
1416
|
+
y
|
|
1417
|
+
};
|
|
1418
|
+
}
|
|
1419
|
+
const SCROLLBAR_MAX = 25;
|
|
1420
|
+
function getViewportRect(element, strategy, rootBoundary) {
|
|
1421
|
+
if (rootBoundary === void 0) rootBoundary = "viewport";
|
|
1422
|
+
const isLayoutViewport = rootBoundary === "layoutViewport";
|
|
1423
|
+
const win = getWindow(element);
|
|
1424
|
+
const html = getDocumentElement(element);
|
|
1425
|
+
const visualViewport = win.visualViewport;
|
|
1426
|
+
let width = html.clientWidth;
|
|
1427
|
+
let height = html.clientHeight;
|
|
1428
|
+
let x = 0;
|
|
1429
|
+
let y = 0;
|
|
1430
|
+
if (visualViewport) {
|
|
1431
|
+
const layoutRelativeClientCoords = !isWebKit() || strategy === "fixed";
|
|
1432
|
+
if (isLayoutViewport) {
|
|
1433
|
+
if (!layoutRelativeClientCoords) {
|
|
1434
|
+
x = -visualViewport.offsetLeft;
|
|
1435
|
+
y = -visualViewport.offsetTop;
|
|
1436
|
+
}
|
|
1437
|
+
} else {
|
|
1438
|
+
width = visualViewport.width;
|
|
1439
|
+
height = visualViewport.height;
|
|
1440
|
+
if (layoutRelativeClientCoords) {
|
|
1441
|
+
x = visualViewport.offsetLeft;
|
|
1442
|
+
y = visualViewport.offsetTop;
|
|
1443
|
+
}
|
|
1444
|
+
}
|
|
1445
|
+
}
|
|
1446
|
+
if (getWindowScrollBarX(html) <= 0) {
|
|
1447
|
+
const doc = html.ownerDocument;
|
|
1448
|
+
const body = doc.body;
|
|
1449
|
+
const bodyStyles = getComputedStyle(body);
|
|
1450
|
+
const bodyMarginInline = doc.compatMode === "CSS1Compat" ? parseFloat(bodyStyles.marginLeft) + parseFloat(bodyStyles.marginRight) || 0 : 0;
|
|
1451
|
+
const reservedWidth = Math.abs(html.clientWidth - body.clientWidth - bodyMarginInline);
|
|
1452
|
+
const gutter = getComputedStyle(html).scrollbarGutter === "stable both-edges" ? reservedWidth / 2 : reservedWidth;
|
|
1453
|
+
if (gutter <= SCROLLBAR_MAX) width -= gutter;
|
|
1454
|
+
}
|
|
1455
|
+
return {
|
|
1456
|
+
width,
|
|
1457
|
+
height,
|
|
1458
|
+
x,
|
|
1459
|
+
y
|
|
1460
|
+
};
|
|
1461
|
+
}
|
|
1462
|
+
function getInnerBoundingClientRect(element, strategy) {
|
|
1463
|
+
const clientRect = getBoundingClientRect(element, true, strategy === "fixed");
|
|
1464
|
+
const top = clientRect.top + element.clientTop;
|
|
1465
|
+
const left = clientRect.left + element.clientLeft;
|
|
1466
|
+
const scale = getScale(element);
|
|
1467
|
+
return {
|
|
1468
|
+
width: element.clientWidth * scale.x,
|
|
1469
|
+
height: element.clientHeight * scale.y,
|
|
1470
|
+
x: left * scale.x,
|
|
1471
|
+
y: top * scale.y
|
|
1472
|
+
};
|
|
1473
|
+
}
|
|
1474
|
+
function getClientRectFromClippingAncestor(element, clippingAncestor, strategy) {
|
|
1475
|
+
let rect;
|
|
1476
|
+
if (clippingAncestor === "viewport" || clippingAncestor === "layoutViewport") rect = getViewportRect(element, strategy, clippingAncestor);
|
|
1477
|
+
else if (clippingAncestor === "document") rect = getDocumentRect(getDocumentElement(element));
|
|
1478
|
+
else if (isElement(clippingAncestor)) rect = getInnerBoundingClientRect(clippingAncestor, strategy);
|
|
1479
|
+
else {
|
|
1480
|
+
const visualOffsets = getVisualOffsets(element);
|
|
1481
|
+
rect = {
|
|
1482
|
+
x: clippingAncestor.x - visualOffsets.x,
|
|
1483
|
+
y: clippingAncestor.y - visualOffsets.y,
|
|
1484
|
+
width: clippingAncestor.width,
|
|
1485
|
+
height: clippingAncestor.height
|
|
1486
|
+
};
|
|
1487
|
+
}
|
|
1488
|
+
return rectToClientRect(rect);
|
|
1489
|
+
}
|
|
1490
|
+
function getClippingElementAncestors(element, cache) {
|
|
1491
|
+
const cachedResult = cache.get(element);
|
|
1492
|
+
if (cachedResult) return cachedResult;
|
|
1493
|
+
let result = getOverflowAncestors(element, [], false).filter((el) => isElement(el) && getNodeName(el) !== "body");
|
|
1494
|
+
let lastKeptComputedStyle = null;
|
|
1495
|
+
const elementIsFixed = getComputedStyle$1(element).position === "fixed";
|
|
1496
|
+
let currentNode = elementIsFixed ? getParentNode(element) : element;
|
|
1497
|
+
while (isElement(currentNode) && !isLastTraversableNode(currentNode)) {
|
|
1498
|
+
const computedStyle = getComputedStyle$1(currentNode);
|
|
1499
|
+
const currentNodeIsContaining = isContainingBlock(currentNode);
|
|
1500
|
+
const lastPosition = lastKeptComputedStyle ? lastKeptComputedStyle.position : elementIsFixed ? "fixed" : "";
|
|
1501
|
+
if (!currentNodeIsContaining && (lastPosition === "fixed" || lastPosition === "absolute" && computedStyle.position === "static")) result = result.filter((ancestor) => ancestor !== currentNode);
|
|
1502
|
+
else lastKeptComputedStyle = computedStyle;
|
|
1503
|
+
currentNode = getParentNode(currentNode);
|
|
1504
|
+
}
|
|
1505
|
+
cache.set(element, result);
|
|
1506
|
+
return result;
|
|
1507
|
+
}
|
|
1508
|
+
function getClippingRect(_ref) {
|
|
1509
|
+
let { element, boundary, rootBoundary, strategy } = _ref;
|
|
1510
|
+
const clippingAncestors = [...boundary === "clippingAncestors" ? isTopLayer(element) ? [] : getClippingElementAncestors(element, this._c) : [].concat(boundary), rootBoundary];
|
|
1511
|
+
const firstRect = getClientRectFromClippingAncestor(element, clippingAncestors[0], strategy);
|
|
1512
|
+
let top = firstRect.top;
|
|
1513
|
+
let right = firstRect.right;
|
|
1514
|
+
let bottom = firstRect.bottom;
|
|
1515
|
+
let left = firstRect.left;
|
|
1516
|
+
for (let i = 1; i < clippingAncestors.length; i++) {
|
|
1517
|
+
const rect = getClientRectFromClippingAncestor(element, clippingAncestors[i], strategy);
|
|
1518
|
+
top = max(rect.top, top);
|
|
1519
|
+
right = min(rect.right, right);
|
|
1520
|
+
bottom = min(rect.bottom, bottom);
|
|
1521
|
+
left = max(rect.left, left);
|
|
1522
|
+
}
|
|
1523
|
+
return {
|
|
1524
|
+
width: right - left,
|
|
1525
|
+
height: bottom - top,
|
|
1526
|
+
x: left,
|
|
1527
|
+
y: top
|
|
1528
|
+
};
|
|
1529
|
+
}
|
|
1530
|
+
function getDimensions(element) {
|
|
1531
|
+
const { width, height } = getCssDimensions(element);
|
|
1532
|
+
return {
|
|
1533
|
+
width,
|
|
1534
|
+
height
|
|
1535
|
+
};
|
|
1536
|
+
}
|
|
1537
|
+
function getRectRelativeToOffsetParent(element, offsetParent, strategy) {
|
|
1538
|
+
const isOffsetParentAnElement = isHTMLElement(offsetParent);
|
|
1539
|
+
const documentElement = getDocumentElement(offsetParent);
|
|
1540
|
+
const isFixed = strategy === "fixed";
|
|
1541
|
+
const rect = getBoundingClientRect(element, true, isFixed, offsetParent);
|
|
1542
|
+
let scroll = {
|
|
1543
|
+
scrollLeft: 0,
|
|
1544
|
+
scrollTop: 0
|
|
1545
|
+
};
|
|
1546
|
+
const offsets = createCoords(0);
|
|
1547
|
+
if (isOffsetParentAnElement || !isFixed) {
|
|
1548
|
+
if (getNodeName(offsetParent) !== "body" || isOverflowElement(documentElement)) scroll = getNodeScroll(offsetParent);
|
|
1549
|
+
if (isOffsetParentAnElement) {
|
|
1550
|
+
const offsetRect = getBoundingClientRect(offsetParent, true, isFixed, offsetParent);
|
|
1551
|
+
offsets.x = offsetRect.x + offsetParent.clientLeft;
|
|
1552
|
+
offsets.y = offsetRect.y + offsetParent.clientTop;
|
|
1553
|
+
}
|
|
1554
|
+
}
|
|
1555
|
+
if (!isOffsetParentAnElement && documentElement) offsets.x = getWindowScrollBarX(documentElement);
|
|
1556
|
+
const htmlOffset = documentElement && !isOffsetParentAnElement && !isFixed ? getHTMLOffset(documentElement, scroll) : createCoords(0);
|
|
1557
|
+
return {
|
|
1558
|
+
x: rect.left + scroll.scrollLeft - offsets.x - htmlOffset.x,
|
|
1559
|
+
y: rect.top + scroll.scrollTop - offsets.y - htmlOffset.y,
|
|
1560
|
+
width: rect.width,
|
|
1561
|
+
height: rect.height
|
|
1562
|
+
};
|
|
1563
|
+
}
|
|
1564
|
+
function isStaticPositioned(element) {
|
|
1565
|
+
return getComputedStyle$1(element).position === "static";
|
|
1566
|
+
}
|
|
1567
|
+
function getTrueOffsetParent(element, polyfill) {
|
|
1568
|
+
if (!isHTMLElement(element) || getComputedStyle$1(element).position === "fixed") return null;
|
|
1569
|
+
if (polyfill) return polyfill(element);
|
|
1570
|
+
let rawOffsetParent = element.offsetParent;
|
|
1571
|
+
if (getDocumentElement(element) === rawOffsetParent) rawOffsetParent = rawOffsetParent.ownerDocument.body;
|
|
1572
|
+
return rawOffsetParent;
|
|
1573
|
+
}
|
|
1574
|
+
function getOffsetParent(element, polyfill) {
|
|
1575
|
+
const win = getWindow(element);
|
|
1576
|
+
if (isTopLayer(element)) return win;
|
|
1577
|
+
if (!isHTMLElement(element)) {
|
|
1578
|
+
let svgOffsetParent = getParentNode(element);
|
|
1579
|
+
while (svgOffsetParent && !isLastTraversableNode(svgOffsetParent)) {
|
|
1580
|
+
if (isElement(svgOffsetParent) && !isStaticPositioned(svgOffsetParent)) return svgOffsetParent;
|
|
1581
|
+
svgOffsetParent = getParentNode(svgOffsetParent);
|
|
1582
|
+
}
|
|
1583
|
+
return win;
|
|
1584
|
+
}
|
|
1585
|
+
let offsetParent = getTrueOffsetParent(element, polyfill);
|
|
1586
|
+
while (offsetParent && isTableElement(offsetParent) && isStaticPositioned(offsetParent)) offsetParent = getTrueOffsetParent(offsetParent, polyfill);
|
|
1587
|
+
if (offsetParent && isLastTraversableNode(offsetParent) && isStaticPositioned(offsetParent) && !isContainingBlock(offsetParent)) return win;
|
|
1588
|
+
return offsetParent || getContainingBlock(element) || win;
|
|
1589
|
+
}
|
|
1590
|
+
const getElementRects = async function(data) {
|
|
1591
|
+
const getOffsetParentFn = this.getOffsetParent || getOffsetParent;
|
|
1592
|
+
const getDimensionsFn = this.getDimensions;
|
|
1593
|
+
const floatingDimensions = await getDimensionsFn(data.floating);
|
|
1594
|
+
return {
|
|
1595
|
+
reference: getRectRelativeToOffsetParent(data.reference, await getOffsetParentFn(data.floating), data.strategy),
|
|
1596
|
+
floating: {
|
|
1597
|
+
x: 0,
|
|
1598
|
+
y: 0,
|
|
1599
|
+
width: floatingDimensions.width,
|
|
1600
|
+
height: floatingDimensions.height
|
|
1601
|
+
}
|
|
1602
|
+
};
|
|
1603
|
+
};
|
|
1604
|
+
function isRTL(element) {
|
|
1605
|
+
return getComputedStyle$1(element).direction === "rtl";
|
|
1606
|
+
}
|
|
1607
|
+
const platform = {
|
|
1608
|
+
convertOffsetParentRelativeRectToViewportRelativeRect,
|
|
1609
|
+
getDocumentElement,
|
|
1610
|
+
getClippingRect,
|
|
1611
|
+
getOffsetParent,
|
|
1612
|
+
getElementRects,
|
|
1613
|
+
getClientRects,
|
|
1614
|
+
getDimensions,
|
|
1615
|
+
getScale,
|
|
1616
|
+
isElement,
|
|
1617
|
+
isRTL
|
|
1618
|
+
};
|
|
1619
|
+
function rectsAreEqual(a, b) {
|
|
1620
|
+
return a.x === b.x && a.y === b.y && a.width === b.width && a.height === b.height;
|
|
1621
|
+
}
|
|
1622
|
+
function observeMove(element, onMove, ancestorResize) {
|
|
1623
|
+
let io = null;
|
|
1624
|
+
let timeoutId;
|
|
1625
|
+
const root = getDocumentElement(element);
|
|
1626
|
+
function cleanup() {
|
|
1627
|
+
var _io;
|
|
1628
|
+
clearTimeout(timeoutId);
|
|
1629
|
+
(_io = io) == null || _io.disconnect();
|
|
1630
|
+
io = null;
|
|
1631
|
+
}
|
|
1632
|
+
function refresh(skip, threshold) {
|
|
1633
|
+
if (skip === void 0) skip = false;
|
|
1634
|
+
if (threshold === void 0) threshold = 1;
|
|
1635
|
+
cleanup();
|
|
1636
|
+
const elementRectForRootMargin = element.getBoundingClientRect();
|
|
1637
|
+
const { left, top, width, height } = elementRectForRootMargin;
|
|
1638
|
+
if (!skip) onMove();
|
|
1639
|
+
if (!width || !height) return;
|
|
1640
|
+
const insetTop = floor(top);
|
|
1641
|
+
const insetRight = floor(root.clientWidth - (left + width));
|
|
1642
|
+
const insetBottom = floor(root.clientHeight - (top + height));
|
|
1643
|
+
const insetLeft = floor(left);
|
|
1644
|
+
const options = {
|
|
1645
|
+
rootMargin: -insetTop + "px " + -insetRight + "px " + -insetBottom + "px " + -insetLeft + "px",
|
|
1646
|
+
threshold: max(0, min(1, threshold)) || 1
|
|
1647
|
+
};
|
|
1648
|
+
let isFirstUpdate = true;
|
|
1649
|
+
function handleObserve(entries) {
|
|
1650
|
+
const ratio = entries[0].intersectionRatio;
|
|
1651
|
+
if (!rectsAreEqual(elementRectForRootMargin, element.getBoundingClientRect())) return refresh();
|
|
1652
|
+
if (ratio !== threshold) {
|
|
1653
|
+
if (!isFirstUpdate) return refresh();
|
|
1654
|
+
if (!ratio) timeoutId = setTimeout(() => {
|
|
1655
|
+
refresh(false, 1e-7);
|
|
1656
|
+
}, 1e3);
|
|
1657
|
+
else refresh(false, ratio);
|
|
1658
|
+
}
|
|
1659
|
+
isFirstUpdate = false;
|
|
1660
|
+
}
|
|
1661
|
+
try {
|
|
1662
|
+
io = new IntersectionObserver(handleObserve, {
|
|
1663
|
+
...options,
|
|
1664
|
+
root: root.ownerDocument
|
|
1665
|
+
});
|
|
1666
|
+
} catch (_e) {
|
|
1667
|
+
io = new IntersectionObserver(handleObserve, options);
|
|
1668
|
+
}
|
|
1669
|
+
io.observe(element);
|
|
1670
|
+
}
|
|
1671
|
+
const win = getWindow(element);
|
|
1672
|
+
const handleResize = () => refresh(ancestorResize);
|
|
1673
|
+
win.addEventListener("resize", handleResize);
|
|
1674
|
+
refresh(true);
|
|
1675
|
+
return () => {
|
|
1676
|
+
win.removeEventListener("resize", handleResize);
|
|
1677
|
+
cleanup();
|
|
1678
|
+
};
|
|
1679
|
+
}
|
|
1680
|
+
/**
|
|
1681
|
+
* Automatically updates the position of the floating element when necessary.
|
|
1682
|
+
* Should only be called when the floating element is mounted on the DOM or
|
|
1683
|
+
* visible on the screen.
|
|
1684
|
+
* @returns cleanup function that should be invoked when the floating element is
|
|
1685
|
+
* removed from the DOM or hidden from the screen.
|
|
1686
|
+
* @see https://floating-ui.com/docs/autoUpdate
|
|
1687
|
+
*/
|
|
1688
|
+
function autoUpdate(reference, floating, update, options) {
|
|
1689
|
+
if (options === void 0) options = {};
|
|
1690
|
+
const { ancestorScroll = true, ancestorResize = true, elementResize = typeof ResizeObserver === "function", layoutShift = typeof IntersectionObserver === "function", animationFrame = false } = options;
|
|
1691
|
+
const referenceEl = unwrapElement(reference);
|
|
1692
|
+
const ancestors = ancestorScroll || ancestorResize ? [...referenceEl ? getOverflowAncestors(referenceEl) : [], ...floating ? getOverflowAncestors(floating) : []] : [];
|
|
1693
|
+
ancestors.forEach((ancestor) => {
|
|
1694
|
+
ancestorScroll && ancestor.addEventListener("scroll", update);
|
|
1695
|
+
ancestorResize && ancestor.addEventListener("resize", update);
|
|
1696
|
+
});
|
|
1697
|
+
const cleanupIo = referenceEl && layoutShift ? observeMove(referenceEl, update, ancestorResize) : null;
|
|
1698
|
+
let reobserveFrame = -1;
|
|
1699
|
+
let resizeObserver = null;
|
|
1700
|
+
if (elementResize) {
|
|
1701
|
+
resizeObserver = new ResizeObserver((_ref) => {
|
|
1702
|
+
let [firstEntry] = _ref;
|
|
1703
|
+
if (firstEntry && firstEntry.target === referenceEl && resizeObserver && floating) {
|
|
1704
|
+
resizeObserver.unobserve(floating);
|
|
1705
|
+
cancelAnimationFrame(reobserveFrame);
|
|
1706
|
+
reobserveFrame = requestAnimationFrame(() => {
|
|
1707
|
+
var _resizeObserver;
|
|
1708
|
+
(_resizeObserver = resizeObserver) == null || _resizeObserver.observe(floating);
|
|
1709
|
+
});
|
|
1710
|
+
}
|
|
1711
|
+
update();
|
|
1712
|
+
});
|
|
1713
|
+
if (referenceEl && !animationFrame) resizeObserver.observe(referenceEl);
|
|
1714
|
+
if (floating) resizeObserver.observe(floating);
|
|
1715
|
+
}
|
|
1716
|
+
let frameId;
|
|
1717
|
+
let prevRefRect = animationFrame ? getBoundingClientRect(reference) : null;
|
|
1718
|
+
if (animationFrame) frameLoop();
|
|
1719
|
+
function frameLoop() {
|
|
1720
|
+
const nextRefRect = getBoundingClientRect(reference);
|
|
1721
|
+
if (prevRefRect && !rectsAreEqual(prevRefRect, nextRefRect)) update();
|
|
1722
|
+
prevRefRect = nextRefRect;
|
|
1723
|
+
frameId = requestAnimationFrame(frameLoop);
|
|
1724
|
+
}
|
|
1725
|
+
update();
|
|
1726
|
+
return () => {
|
|
1727
|
+
var _resizeObserver2;
|
|
1728
|
+
ancestors.forEach((ancestor) => {
|
|
1729
|
+
ancestorScroll && ancestor.removeEventListener("scroll", update);
|
|
1730
|
+
ancestorResize && ancestor.removeEventListener("resize", update);
|
|
1731
|
+
});
|
|
1732
|
+
cleanupIo?.();
|
|
1733
|
+
(_resizeObserver2 = resizeObserver) == null || _resizeObserver2.disconnect();
|
|
1734
|
+
resizeObserver = null;
|
|
1735
|
+
if (animationFrame) cancelAnimationFrame(frameId);
|
|
1736
|
+
};
|
|
1737
|
+
}
|
|
1738
|
+
/**
|
|
1739
|
+
* Modifies the placement by translating the floating element along the
|
|
1740
|
+
* specified axes.
|
|
1741
|
+
* A number (shorthand for `mainAxis` or distance), or an axes configuration
|
|
1742
|
+
* object may be passed.
|
|
1743
|
+
* @see https://floating-ui.com/docs/offset
|
|
1744
|
+
*/
|
|
1745
|
+
const offset$2 = offset$1;
|
|
1746
|
+
/**
|
|
1747
|
+
* Optimizes the visibility of the floating element by shifting it in order to
|
|
1748
|
+
* keep it in view when it will overflow the clipping boundary.
|
|
1749
|
+
* @see https://floating-ui.com/docs/shift
|
|
1750
|
+
*/
|
|
1751
|
+
const shift$2 = shift$1;
|
|
1752
|
+
/**
|
|
1753
|
+
* Optimizes the visibility of the floating element by flipping the `placement`
|
|
1754
|
+
* in order to keep it in view when the preferred placement(s) will overflow the
|
|
1755
|
+
* clipping boundary. Alternative to `autoPlacement`.
|
|
1756
|
+
* @see https://floating-ui.com/docs/flip
|
|
1757
|
+
*/
|
|
1758
|
+
const flip$2 = flip$1;
|
|
1759
|
+
/**
|
|
1760
|
+
* Provides data that allows you to change the size of the floating element —
|
|
1761
|
+
* for instance, prevent it from overflowing the clipping boundary or match the
|
|
1762
|
+
* width of the reference element.
|
|
1763
|
+
* @see https://floating-ui.com/docs/size
|
|
1764
|
+
*/
|
|
1765
|
+
const size$2 = size$1;
|
|
1766
|
+
/**
|
|
1767
|
+
* Computes the `x` and `y` coordinates that will place the floating element
|
|
1768
|
+
* next to a given reference element.
|
|
1769
|
+
*/
|
|
1770
|
+
const computePosition = (reference, floating, options) => {
|
|
1771
|
+
const cache = /* @__PURE__ */ new Map();
|
|
1772
|
+
const mergedOptions = options != null ? options : {};
|
|
1773
|
+
const platformWithCache = {
|
|
1774
|
+
...platform,
|
|
1775
|
+
...mergedOptions.platform,
|
|
1776
|
+
_c: cache
|
|
1777
|
+
};
|
|
1778
|
+
return computePosition$1(reference, floating, {
|
|
1779
|
+
...mergedOptions,
|
|
1780
|
+
platform: platformWithCache
|
|
1781
|
+
});
|
|
1782
|
+
};
|
|
1783
|
+
//#endregion
|
|
1784
|
+
//#region ../../node_modules/.pnpm/@floating-ui+react-dom@2.1.9_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/@floating-ui/react-dom/dist/floating-ui.react-dom.mjs
|
|
1785
|
+
var index = typeof document !== "undefined" ? react.useLayoutEffect : function noop() {};
|
|
1786
|
+
function deepEqual(a, b) {
|
|
1787
|
+
if (a === b) return true;
|
|
1788
|
+
if (typeof a !== typeof b) return false;
|
|
1789
|
+
if (typeof a === "function" && a.toString() === b.toString()) return true;
|
|
1790
|
+
let length;
|
|
1791
|
+
let i;
|
|
1792
|
+
let keys;
|
|
1793
|
+
if (a && b && typeof a === "object") {
|
|
1794
|
+
if (Array.isArray(a)) {
|
|
1795
|
+
length = a.length;
|
|
1796
|
+
if (length !== b.length) return false;
|
|
1797
|
+
for (i = length; i-- !== 0;) if (!deepEqual(a[i], b[i])) return false;
|
|
1798
|
+
return true;
|
|
1799
|
+
}
|
|
1800
|
+
keys = Object.keys(a);
|
|
1801
|
+
length = keys.length;
|
|
1802
|
+
if (length !== Object.keys(b).length) return false;
|
|
1803
|
+
for (i = length; i-- !== 0;) if (!{}.hasOwnProperty.call(b, keys[i])) return false;
|
|
1804
|
+
for (i = length; i-- !== 0;) {
|
|
1805
|
+
const key = keys[i];
|
|
1806
|
+
if (key === "_owner" && a.$$typeof) continue;
|
|
1807
|
+
if (!deepEqual(a[key], b[key])) return false;
|
|
1808
|
+
}
|
|
1809
|
+
return true;
|
|
1810
|
+
}
|
|
1811
|
+
return a !== a && b !== b;
|
|
1812
|
+
}
|
|
1813
|
+
function getDPR(element) {
|
|
1814
|
+
if (typeof window === "undefined") return 1;
|
|
1815
|
+
return (element.ownerDocument.defaultView || window).devicePixelRatio || 1;
|
|
1816
|
+
}
|
|
1817
|
+
function roundByDPR(element, value) {
|
|
1818
|
+
const dpr = getDPR(element);
|
|
1819
|
+
return Math.round(value * dpr) / dpr;
|
|
1820
|
+
}
|
|
1821
|
+
function useLatestRef(value) {
|
|
1822
|
+
const ref = react.useRef(value);
|
|
1823
|
+
index(() => {
|
|
1824
|
+
ref.current = value;
|
|
1825
|
+
});
|
|
1826
|
+
return ref;
|
|
1827
|
+
}
|
|
1828
|
+
/**
|
|
1829
|
+
* Provides data to position a floating element.
|
|
1830
|
+
* @see https://floating-ui.com/docs/useFloating
|
|
1831
|
+
*/
|
|
1832
|
+
function useFloating$1(options) {
|
|
1833
|
+
if (options === void 0) options = {};
|
|
1834
|
+
const { placement = "bottom", strategy = "absolute", middleware = [], platform, elements: { reference: externalReference, floating: externalFloating } = {}, transform = true, whileElementsMounted, open } = options;
|
|
1835
|
+
const [data, setData] = react.useState({
|
|
1836
|
+
x: 0,
|
|
1837
|
+
y: 0,
|
|
1838
|
+
strategy,
|
|
1839
|
+
placement,
|
|
1840
|
+
middlewareData: {},
|
|
1841
|
+
isPositioned: false
|
|
1842
|
+
});
|
|
1843
|
+
const [latestMiddleware, setLatestMiddleware] = react.useState(middleware);
|
|
1844
|
+
if (!deepEqual(latestMiddleware, middleware)) setLatestMiddleware(middleware);
|
|
1845
|
+
const [_reference, _setReference] = react.useState(null);
|
|
1846
|
+
const [_floating, _setFloating] = react.useState(null);
|
|
1847
|
+
const setReference = react.useCallback((node) => {
|
|
1848
|
+
if (node !== referenceRef.current) {
|
|
1849
|
+
referenceRef.current = node;
|
|
1850
|
+
_setReference(node);
|
|
1851
|
+
}
|
|
1852
|
+
}, []);
|
|
1853
|
+
const setFloating = react.useCallback((node) => {
|
|
1854
|
+
if (node !== floatingRef.current) {
|
|
1855
|
+
floatingRef.current = node;
|
|
1856
|
+
_setFloating(node);
|
|
1857
|
+
}
|
|
1858
|
+
}, []);
|
|
1859
|
+
const referenceEl = externalReference || _reference;
|
|
1860
|
+
const floatingEl = externalFloating || _floating;
|
|
1861
|
+
const referenceRef = react.useRef(null);
|
|
1862
|
+
const floatingRef = react.useRef(null);
|
|
1863
|
+
const dataRef = react.useRef(data);
|
|
1864
|
+
const hasWhileElementsMounted = whileElementsMounted != null;
|
|
1865
|
+
const whileElementsMountedRef = useLatestRef(whileElementsMounted);
|
|
1866
|
+
const platformRef = useLatestRef(platform);
|
|
1867
|
+
const openRef = useLatestRef(open);
|
|
1868
|
+
const update = react.useCallback(() => {
|
|
1869
|
+
if (!referenceRef.current || !floatingRef.current) return;
|
|
1870
|
+
const config = {
|
|
1871
|
+
placement,
|
|
1872
|
+
strategy,
|
|
1873
|
+
middleware: latestMiddleware
|
|
1874
|
+
};
|
|
1875
|
+
if (platformRef.current) config.platform = platformRef.current;
|
|
1876
|
+
computePosition(referenceRef.current, floatingRef.current, config).then((data) => {
|
|
1877
|
+
const fullData = {
|
|
1878
|
+
...data,
|
|
1879
|
+
isPositioned: openRef.current !== false
|
|
1880
|
+
};
|
|
1881
|
+
if (isMountedRef.current && !deepEqual(dataRef.current, fullData)) {
|
|
1882
|
+
dataRef.current = fullData;
|
|
1883
|
+
react_dom.flushSync(() => {
|
|
1884
|
+
setData(fullData);
|
|
1885
|
+
});
|
|
1886
|
+
}
|
|
1887
|
+
});
|
|
1888
|
+
}, [
|
|
1889
|
+
latestMiddleware,
|
|
1890
|
+
placement,
|
|
1891
|
+
strategy,
|
|
1892
|
+
platformRef,
|
|
1893
|
+
openRef
|
|
1894
|
+
]);
|
|
1895
|
+
index(() => {
|
|
1896
|
+
if (open === false && dataRef.current.isPositioned) {
|
|
1897
|
+
dataRef.current.isPositioned = false;
|
|
1898
|
+
setData((data) => ({
|
|
1899
|
+
...data,
|
|
1900
|
+
isPositioned: false
|
|
1901
|
+
}));
|
|
1902
|
+
}
|
|
1903
|
+
}, [open]);
|
|
1904
|
+
const isMountedRef = react.useRef(false);
|
|
1905
|
+
index(() => {
|
|
1906
|
+
isMountedRef.current = true;
|
|
1907
|
+
return () => {
|
|
1908
|
+
isMountedRef.current = false;
|
|
1909
|
+
};
|
|
1910
|
+
}, []);
|
|
1911
|
+
index(() => {
|
|
1912
|
+
if (referenceEl) referenceRef.current = referenceEl;
|
|
1913
|
+
if (floatingEl) floatingRef.current = floatingEl;
|
|
1914
|
+
if (referenceEl && floatingEl) {
|
|
1915
|
+
if (whileElementsMountedRef.current) return whileElementsMountedRef.current(referenceEl, floatingEl, update);
|
|
1916
|
+
update();
|
|
1917
|
+
}
|
|
1918
|
+
}, [
|
|
1919
|
+
referenceEl,
|
|
1920
|
+
floatingEl,
|
|
1921
|
+
update,
|
|
1922
|
+
whileElementsMountedRef,
|
|
1923
|
+
hasWhileElementsMounted
|
|
1924
|
+
]);
|
|
1925
|
+
const refs = react.useMemo(() => ({
|
|
1926
|
+
reference: referenceRef,
|
|
1927
|
+
floating: floatingRef,
|
|
1928
|
+
setReference,
|
|
1929
|
+
setFloating
|
|
1930
|
+
}), [setReference, setFloating]);
|
|
1931
|
+
const elements = react.useMemo(() => ({
|
|
1932
|
+
reference: referenceEl,
|
|
1933
|
+
floating: floatingEl
|
|
1934
|
+
}), [referenceEl, floatingEl]);
|
|
1935
|
+
const floatingStyles = react.useMemo(() => {
|
|
1936
|
+
const initialStyles = {
|
|
1937
|
+
position: strategy,
|
|
1938
|
+
left: 0,
|
|
1939
|
+
top: 0
|
|
1940
|
+
};
|
|
1941
|
+
if (!elements.floating) return initialStyles;
|
|
1942
|
+
const x = roundByDPR(elements.floating, data.x);
|
|
1943
|
+
const y = roundByDPR(elements.floating, data.y);
|
|
1944
|
+
if (transform) return {
|
|
1945
|
+
...initialStyles,
|
|
1946
|
+
transform: "translate(" + x + "px, " + y + "px)",
|
|
1947
|
+
...getDPR(elements.floating) >= 1.5 && { willChange: "transform" }
|
|
1948
|
+
};
|
|
1949
|
+
return {
|
|
1950
|
+
position: strategy,
|
|
1951
|
+
left: x,
|
|
1952
|
+
top: y
|
|
1953
|
+
};
|
|
1954
|
+
}, [
|
|
1955
|
+
strategy,
|
|
1956
|
+
transform,
|
|
1957
|
+
elements.floating,
|
|
1958
|
+
data.x,
|
|
1959
|
+
data.y
|
|
1960
|
+
]);
|
|
1961
|
+
return react.useMemo(() => ({
|
|
1962
|
+
...data,
|
|
1963
|
+
update,
|
|
1964
|
+
refs,
|
|
1965
|
+
elements,
|
|
1966
|
+
floatingStyles
|
|
1967
|
+
}), [
|
|
1968
|
+
data,
|
|
1969
|
+
update,
|
|
1970
|
+
refs,
|
|
1971
|
+
elements,
|
|
1972
|
+
floatingStyles
|
|
1973
|
+
]);
|
|
1974
|
+
}
|
|
1975
|
+
/**
|
|
1976
|
+
* Modifies the placement by translating the floating element along the
|
|
1977
|
+
* specified axes.
|
|
1978
|
+
* A number (shorthand for `mainAxis` or distance), or an axes configuration
|
|
1979
|
+
* object may be passed.
|
|
1980
|
+
* @see https://floating-ui.com/docs/offset
|
|
1981
|
+
*/
|
|
1982
|
+
const offset = (options, deps) => {
|
|
1983
|
+
const result = offset$2(options);
|
|
1984
|
+
return {
|
|
1985
|
+
name: result.name,
|
|
1986
|
+
fn: result.fn,
|
|
1987
|
+
options: [options, deps]
|
|
1988
|
+
};
|
|
1989
|
+
};
|
|
1990
|
+
/**
|
|
1991
|
+
* Optimizes the visibility of the floating element by shifting it in order to
|
|
1992
|
+
* keep it in view when it will overflow the clipping boundary.
|
|
1993
|
+
* @see https://floating-ui.com/docs/shift
|
|
1994
|
+
*/
|
|
1995
|
+
const shift = (options, deps) => {
|
|
1996
|
+
const result = shift$2(options);
|
|
1997
|
+
return {
|
|
1998
|
+
name: result.name,
|
|
1999
|
+
fn: result.fn,
|
|
2000
|
+
options: [options, deps]
|
|
2001
|
+
};
|
|
2002
|
+
};
|
|
2003
|
+
/**
|
|
2004
|
+
* Optimizes the visibility of the floating element by flipping the `placement`
|
|
2005
|
+
* in order to keep it in view when the preferred placement(s) will overflow the
|
|
2006
|
+
* clipping boundary. Alternative to `autoPlacement`.
|
|
2007
|
+
* @see https://floating-ui.com/docs/flip
|
|
2008
|
+
*/
|
|
2009
|
+
const flip = (options, deps) => {
|
|
2010
|
+
const result = flip$2(options);
|
|
2011
|
+
return {
|
|
2012
|
+
name: result.name,
|
|
2013
|
+
fn: result.fn,
|
|
2014
|
+
options: [options, deps]
|
|
2015
|
+
};
|
|
2016
|
+
};
|
|
2017
|
+
/**
|
|
2018
|
+
* Provides data that allows you to change the size of the floating element —
|
|
2019
|
+
* for instance, prevent it from overflowing the clipping boundary or match the
|
|
2020
|
+
* width of the reference element.
|
|
2021
|
+
* @see https://floating-ui.com/docs/size
|
|
2022
|
+
*/
|
|
2023
|
+
const size = (options, deps) => {
|
|
2024
|
+
const result = size$2(options);
|
|
2025
|
+
return {
|
|
2026
|
+
name: result.name,
|
|
2027
|
+
fn: result.fn,
|
|
2028
|
+
options: [options, deps]
|
|
2029
|
+
};
|
|
2030
|
+
};
|
|
2031
|
+
//#endregion
|
|
2032
|
+
//#region ../../node_modules/.pnpm/@floating-ui+react@0.27.20_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/@floating-ui/react/dist/floating-ui.react.mjs
|
|
2033
|
+
const ARROW_LEFT = "ArrowLeft";
|
|
2034
|
+
const ARROW_RIGHT = "ArrowRight";
|
|
2035
|
+
const ARROW_UP = "ArrowUp";
|
|
2036
|
+
const ARROW_DOWN = "ArrowDown";
|
|
2037
|
+
const horizontalKeys = [ARROW_LEFT, ARROW_RIGHT];
|
|
2038
|
+
const verticalKeys = [ARROW_UP, ARROW_DOWN];
|
|
2039
|
+
[...horizontalKeys, ...verticalKeys];
|
|
2040
|
+
const SafeReact = { ...react };
|
|
2041
|
+
let serverHandoffComplete = false;
|
|
2042
|
+
let count = 0;
|
|
2043
|
+
const genId = () => "floating-ui-" + Math.random().toString(36).slice(2, 6) + count++;
|
|
2044
|
+
function useFloatingId() {
|
|
2045
|
+
const [id, setId] = react.useState(() => serverHandoffComplete ? genId() : void 0);
|
|
2046
|
+
index$1(() => {
|
|
2047
|
+
if (id == null) setId(genId());
|
|
2048
|
+
}, []);
|
|
2049
|
+
react.useEffect(() => {
|
|
2050
|
+
serverHandoffComplete = true;
|
|
2051
|
+
}, []);
|
|
2052
|
+
return id;
|
|
2053
|
+
}
|
|
2054
|
+
/**
|
|
2055
|
+
* Uses React 18's built-in `useId()` when available, or falls back to a
|
|
2056
|
+
* slightly less performant (requiring a double render) implementation for
|
|
2057
|
+
* earlier React versions.
|
|
2058
|
+
* @see https://floating-ui.com/docs/react-utils#useid
|
|
2059
|
+
*/
|
|
2060
|
+
const useId = SafeReact.useId || useFloatingId;
|
|
2061
|
+
function createEventEmitter() {
|
|
2062
|
+
const map = /* @__PURE__ */ new Map();
|
|
2063
|
+
return {
|
|
2064
|
+
emit(event, data) {
|
|
2065
|
+
var _map$get;
|
|
2066
|
+
(_map$get = map.get(event)) == null || _map$get.forEach((listener) => listener(data));
|
|
2067
|
+
},
|
|
2068
|
+
on(event, listener) {
|
|
2069
|
+
if (!map.has(event)) map.set(event, /* @__PURE__ */ new Set());
|
|
2070
|
+
map.get(event).add(listener);
|
|
2071
|
+
},
|
|
2072
|
+
off(event, listener) {
|
|
2073
|
+
var _map$get2;
|
|
2074
|
+
(_map$get2 = map.get(event)) == null || _map$get2.delete(listener);
|
|
2075
|
+
}
|
|
2076
|
+
};
|
|
2077
|
+
}
|
|
2078
|
+
const FloatingNodeContext = /*#__PURE__*/ react.createContext(null);
|
|
2079
|
+
const FloatingTreeContext = /*#__PURE__*/ react.createContext(null);
|
|
2080
|
+
/**
|
|
2081
|
+
* Returns the parent node id for nested floating elements, if available.
|
|
2082
|
+
* Returns `null` for top-level floating elements.
|
|
2083
|
+
*/
|
|
2084
|
+
const useFloatingParentNodeId = () => {
|
|
2085
|
+
var _React$useContext;
|
|
2086
|
+
return ((_React$useContext = react.useContext(FloatingNodeContext)) == null ? void 0 : _React$useContext.id) || null;
|
|
2087
|
+
};
|
|
2088
|
+
/**
|
|
2089
|
+
* Returns the nearest floating tree context, if available.
|
|
2090
|
+
*/
|
|
2091
|
+
const useFloatingTree = () => react.useContext(FloatingTreeContext);
|
|
2092
|
+
function createAttribute(name) {
|
|
2093
|
+
return "data-floating-ui-" + name;
|
|
2094
|
+
}
|
|
2095
|
+
const HIDDEN_STYLES = {
|
|
2096
|
+
border: 0,
|
|
2097
|
+
clip: "rect(0 0 0 0)",
|
|
2098
|
+
height: "1px",
|
|
2099
|
+
margin: "-1px",
|
|
2100
|
+
overflow: "hidden",
|
|
2101
|
+
padding: 0,
|
|
2102
|
+
position: "fixed",
|
|
2103
|
+
whiteSpace: "nowrap",
|
|
2104
|
+
width: "1px",
|
|
2105
|
+
top: 0,
|
|
2106
|
+
left: 0
|
|
2107
|
+
};
|
|
2108
|
+
const FocusGuard = /*#__PURE__*/ react.forwardRef(function FocusGuard(props, ref) {
|
|
2109
|
+
const [role, setRole] = react.useState();
|
|
2110
|
+
index$1(() => {
|
|
2111
|
+
if (isSafari()) setRole("button");
|
|
2112
|
+
}, []);
|
|
2113
|
+
const restProps = {
|
|
2114
|
+
ref,
|
|
2115
|
+
tabIndex: 0,
|
|
2116
|
+
role,
|
|
2117
|
+
"aria-hidden": role ? void 0 : true,
|
|
2118
|
+
[createAttribute("focus-guard")]: "",
|
|
2119
|
+
style: HIDDEN_STYLES
|
|
2120
|
+
};
|
|
2121
|
+
return /*#__PURE__*/ (0, react_jsx_runtime.jsx)("span", {
|
|
2122
|
+
...props,
|
|
2123
|
+
...restProps
|
|
2124
|
+
});
|
|
2125
|
+
});
|
|
2126
|
+
const HIDDEN_OWNER_STYLES = {
|
|
2127
|
+
clipPath: "inset(50%)",
|
|
2128
|
+
position: "fixed",
|
|
2129
|
+
top: 0,
|
|
2130
|
+
left: 0
|
|
2131
|
+
};
|
|
2132
|
+
const PortalContext = /*#__PURE__*/ react.createContext(null);
|
|
2133
|
+
const attr = /*#__PURE__*/ createAttribute("portal");
|
|
2134
|
+
/**
|
|
2135
|
+
* @see https://floating-ui.com/docs/FloatingPortal#usefloatingportalnode
|
|
2136
|
+
*/
|
|
2137
|
+
function useFloatingPortalNode(props) {
|
|
2138
|
+
if (props === void 0) props = {};
|
|
2139
|
+
const { id, root } = props;
|
|
2140
|
+
const uniqueId = useId();
|
|
2141
|
+
const portalContext = usePortalContext();
|
|
2142
|
+
const [portalNode, setPortalNode] = react.useState(null);
|
|
2143
|
+
const portalNodeRef = react.useRef(null);
|
|
2144
|
+
index$1(() => {
|
|
2145
|
+
return () => {
|
|
2146
|
+
portalNode?.remove();
|
|
2147
|
+
queueMicrotask(() => {
|
|
2148
|
+
portalNodeRef.current = null;
|
|
2149
|
+
});
|
|
2150
|
+
};
|
|
2151
|
+
}, [portalNode]);
|
|
2152
|
+
index$1(() => {
|
|
2153
|
+
if (!uniqueId) return;
|
|
2154
|
+
if (portalNodeRef.current) return;
|
|
2155
|
+
const existingIdRoot = id ? document.getElementById(id) : null;
|
|
2156
|
+
if (!existingIdRoot) return;
|
|
2157
|
+
const subRoot = document.createElement("div");
|
|
2158
|
+
subRoot.id = uniqueId;
|
|
2159
|
+
subRoot.setAttribute(attr, "");
|
|
2160
|
+
existingIdRoot.appendChild(subRoot);
|
|
2161
|
+
portalNodeRef.current = subRoot;
|
|
2162
|
+
setPortalNode(subRoot);
|
|
2163
|
+
}, [id, uniqueId]);
|
|
2164
|
+
index$1(() => {
|
|
2165
|
+
if (root === null) return;
|
|
2166
|
+
if (!uniqueId) return;
|
|
2167
|
+
if (portalNodeRef.current) return;
|
|
2168
|
+
let container = root || (portalContext == null ? void 0 : portalContext.portalNode);
|
|
2169
|
+
if (container && !isNode(container)) container = container.current;
|
|
2170
|
+
container = container || document.body;
|
|
2171
|
+
let idWrapper = null;
|
|
2172
|
+
if (id) {
|
|
2173
|
+
idWrapper = document.createElement("div");
|
|
2174
|
+
idWrapper.id = id;
|
|
2175
|
+
container.appendChild(idWrapper);
|
|
2176
|
+
}
|
|
2177
|
+
const subRoot = document.createElement("div");
|
|
2178
|
+
subRoot.id = uniqueId;
|
|
2179
|
+
subRoot.setAttribute(attr, "");
|
|
2180
|
+
container = idWrapper || container;
|
|
2181
|
+
container.appendChild(subRoot);
|
|
2182
|
+
portalNodeRef.current = subRoot;
|
|
2183
|
+
setPortalNode(subRoot);
|
|
2184
|
+
}, [
|
|
2185
|
+
id,
|
|
2186
|
+
root,
|
|
2187
|
+
uniqueId,
|
|
2188
|
+
portalContext
|
|
2189
|
+
]);
|
|
2190
|
+
return portalNode;
|
|
2191
|
+
}
|
|
2192
|
+
/**
|
|
2193
|
+
* Portals the floating element into a given container element — by default,
|
|
2194
|
+
* outside of the app root and into the body.
|
|
2195
|
+
* This is necessary to ensure the floating element can appear outside any
|
|
2196
|
+
* potential parent containers that cause clipping (such as `overflow: hidden`),
|
|
2197
|
+
* while retaining its location in the React tree.
|
|
2198
|
+
* @see https://floating-ui.com/docs/FloatingPortal
|
|
2199
|
+
*/
|
|
2200
|
+
function FloatingPortal(props) {
|
|
2201
|
+
const { children, id, root, preserveTabOrder = true } = props;
|
|
2202
|
+
const portalNode = useFloatingPortalNode({
|
|
2203
|
+
id,
|
|
2204
|
+
root
|
|
2205
|
+
});
|
|
2206
|
+
const [focusManagerState, setFocusManagerState] = react.useState(null);
|
|
2207
|
+
const beforeOutsideRef = react.useRef(null);
|
|
2208
|
+
const afterOutsideRef = react.useRef(null);
|
|
2209
|
+
const beforeInsideRef = react.useRef(null);
|
|
2210
|
+
const afterInsideRef = react.useRef(null);
|
|
2211
|
+
const modal = focusManagerState == null ? void 0 : focusManagerState.modal;
|
|
2212
|
+
const open = focusManagerState == null ? void 0 : focusManagerState.open;
|
|
2213
|
+
const shouldRenderGuards = !!focusManagerState && !focusManagerState.modal && focusManagerState.open && preserveTabOrder && !!(root || portalNode);
|
|
2214
|
+
react.useEffect(() => {
|
|
2215
|
+
if (!portalNode || !preserveTabOrder || modal) return;
|
|
2216
|
+
function onFocus(event) {
|
|
2217
|
+
if (portalNode && isOutsideEvent(event)) (event.type === "focusin" ? enableFocusInside : disableFocusInside)(portalNode);
|
|
2218
|
+
}
|
|
2219
|
+
portalNode.addEventListener("focusin", onFocus, true);
|
|
2220
|
+
portalNode.addEventListener("focusout", onFocus, true);
|
|
2221
|
+
return () => {
|
|
2222
|
+
portalNode.removeEventListener("focusin", onFocus, true);
|
|
2223
|
+
portalNode.removeEventListener("focusout", onFocus, true);
|
|
2224
|
+
};
|
|
2225
|
+
}, [
|
|
2226
|
+
portalNode,
|
|
2227
|
+
preserveTabOrder,
|
|
2228
|
+
modal
|
|
2229
|
+
]);
|
|
2230
|
+
react.useEffect(() => {
|
|
2231
|
+
if (!portalNode) return;
|
|
2232
|
+
if (open) return;
|
|
2233
|
+
enableFocusInside(portalNode);
|
|
2234
|
+
}, [open, portalNode]);
|
|
2235
|
+
return /*#__PURE__*/ (0, react_jsx_runtime.jsxs)(PortalContext.Provider, {
|
|
2236
|
+
value: react.useMemo(() => ({
|
|
2237
|
+
preserveTabOrder,
|
|
2238
|
+
beforeOutsideRef,
|
|
2239
|
+
afterOutsideRef,
|
|
2240
|
+
beforeInsideRef,
|
|
2241
|
+
afterInsideRef,
|
|
2242
|
+
portalNode,
|
|
2243
|
+
setFocusManagerState
|
|
2244
|
+
}), [preserveTabOrder, portalNode]),
|
|
2245
|
+
children: [
|
|
2246
|
+
shouldRenderGuards && portalNode && /*#__PURE__*/ (0, react_jsx_runtime.jsx)(FocusGuard, {
|
|
2247
|
+
"data-type": "outside",
|
|
2248
|
+
ref: beforeOutsideRef,
|
|
2249
|
+
onFocus: (event) => {
|
|
2250
|
+
if (isOutsideEvent(event, portalNode)) {
|
|
2251
|
+
var _beforeInsideRef$curr;
|
|
2252
|
+
(_beforeInsideRef$curr = beforeInsideRef.current) == null || _beforeInsideRef$curr.focus();
|
|
2253
|
+
} else getPreviousTabbable(focusManagerState ? focusManagerState.domReference : null)?.focus();
|
|
2254
|
+
}
|
|
2255
|
+
}),
|
|
2256
|
+
shouldRenderGuards && portalNode && /*#__PURE__*/ (0, react_jsx_runtime.jsx)("span", {
|
|
2257
|
+
"aria-owns": portalNode.id,
|
|
2258
|
+
style: HIDDEN_OWNER_STYLES
|
|
2259
|
+
}),
|
|
2260
|
+
portalNode && /*#__PURE__*/ react_dom.createPortal(children, portalNode),
|
|
2261
|
+
shouldRenderGuards && portalNode && /*#__PURE__*/ (0, react_jsx_runtime.jsx)(FocusGuard, {
|
|
2262
|
+
"data-type": "outside",
|
|
2263
|
+
ref: afterOutsideRef,
|
|
2264
|
+
onFocus: (event) => {
|
|
2265
|
+
if (isOutsideEvent(event, portalNode)) {
|
|
2266
|
+
var _afterInsideRef$curre;
|
|
2267
|
+
(_afterInsideRef$curre = afterInsideRef.current) == null || _afterInsideRef$curre.focus();
|
|
2268
|
+
} else {
|
|
2269
|
+
getNextTabbable(focusManagerState ? focusManagerState.domReference : null)?.focus();
|
|
2270
|
+
focusManagerState != null && focusManagerState.closeOnFocusOut && focusManagerState?.onOpenChange(false, event.nativeEvent, "focus-out");
|
|
2271
|
+
}
|
|
2272
|
+
}
|
|
2273
|
+
})
|
|
2274
|
+
]
|
|
2275
|
+
});
|
|
2276
|
+
}
|
|
2277
|
+
const usePortalContext = () => react.useContext(PortalContext);
|
|
2278
|
+
function useFloatingRootContext(options) {
|
|
2279
|
+
const { open = false, onOpenChange: onOpenChangeProp, elements: elementsProp } = options;
|
|
2280
|
+
const floatingId = useId();
|
|
2281
|
+
const dataRef = react.useRef({});
|
|
2282
|
+
const [events] = react.useState(() => createEventEmitter());
|
|
2283
|
+
const nested = useFloatingParentNodeId() != null;
|
|
2284
|
+
const [positionReference, setPositionReference] = react.useState(elementsProp.reference);
|
|
2285
|
+
const onOpenChange = useEffectEvent((open, event, reason) => {
|
|
2286
|
+
dataRef.current.openEvent = open ? event : void 0;
|
|
2287
|
+
events.emit("openchange", {
|
|
2288
|
+
open,
|
|
2289
|
+
event,
|
|
2290
|
+
reason,
|
|
2291
|
+
nested
|
|
2292
|
+
});
|
|
2293
|
+
onOpenChangeProp?.(open, event, reason);
|
|
2294
|
+
});
|
|
2295
|
+
const refs = react.useMemo(() => ({ setPositionReference }), []);
|
|
2296
|
+
const elements = react.useMemo(() => ({
|
|
2297
|
+
reference: positionReference || elementsProp.reference || null,
|
|
2298
|
+
floating: elementsProp.floating || null,
|
|
2299
|
+
domReference: elementsProp.reference
|
|
2300
|
+
}), [
|
|
2301
|
+
positionReference,
|
|
2302
|
+
elementsProp.reference,
|
|
2303
|
+
elementsProp.floating
|
|
2304
|
+
]);
|
|
2305
|
+
return react.useMemo(() => ({
|
|
2306
|
+
dataRef,
|
|
2307
|
+
open,
|
|
2308
|
+
onOpenChange,
|
|
2309
|
+
elements,
|
|
2310
|
+
events,
|
|
2311
|
+
floatingId,
|
|
2312
|
+
refs
|
|
2313
|
+
}), [
|
|
2314
|
+
open,
|
|
2315
|
+
onOpenChange,
|
|
2316
|
+
elements,
|
|
2317
|
+
events,
|
|
2318
|
+
floatingId,
|
|
2319
|
+
refs
|
|
2320
|
+
]);
|
|
2321
|
+
}
|
|
2322
|
+
/**
|
|
2323
|
+
* Provides data to position a floating element and context to add interactions.
|
|
2324
|
+
* @see https://floating-ui.com/docs/useFloating
|
|
2325
|
+
*/
|
|
2326
|
+
function useFloating(_temp) {
|
|
2327
|
+
var _elementsOption$refer, _elementsOption$float;
|
|
2328
|
+
let { elements: elementsOption, ...options } = _temp === void 0 ? {} : _temp;
|
|
2329
|
+
const { nodeId } = options;
|
|
2330
|
+
const internalRootContext = useFloatingRootContext({
|
|
2331
|
+
...options,
|
|
2332
|
+
elements: {
|
|
2333
|
+
reference: (_elementsOption$refer = elementsOption == null ? void 0 : elementsOption.reference) != null ? _elementsOption$refer : null,
|
|
2334
|
+
floating: (_elementsOption$float = elementsOption == null ? void 0 : elementsOption.floating) != null ? _elementsOption$float : null
|
|
2335
|
+
}
|
|
2336
|
+
});
|
|
2337
|
+
const rootContext = options.rootContext || internalRootContext;
|
|
2338
|
+
const computedElements = rootContext.elements;
|
|
2339
|
+
const [_domReference, setDomReference] = react.useState(null);
|
|
2340
|
+
const [positionReference, _setPositionReference] = react.useState(null);
|
|
2341
|
+
const domReference = (computedElements == null ? void 0 : computedElements.domReference) || _domReference;
|
|
2342
|
+
const domReferenceRef = react.useRef(null);
|
|
2343
|
+
const tree = useFloatingTree();
|
|
2344
|
+
index$1(() => {
|
|
2345
|
+
if (domReference) domReferenceRef.current = domReference;
|
|
2346
|
+
}, [domReference]);
|
|
2347
|
+
const position = useFloating$1({
|
|
2348
|
+
...options,
|
|
2349
|
+
elements: {
|
|
2350
|
+
...computedElements,
|
|
2351
|
+
...positionReference && { reference: positionReference }
|
|
2352
|
+
}
|
|
2353
|
+
});
|
|
2354
|
+
const setPositionReference = react.useCallback((node) => {
|
|
2355
|
+
const computedPositionReference = isElement(node) ? {
|
|
2356
|
+
getBoundingClientRect: () => node.getBoundingClientRect(),
|
|
2357
|
+
getClientRects: () => node.getClientRects(),
|
|
2358
|
+
contextElement: node
|
|
2359
|
+
} : node;
|
|
2360
|
+
_setPositionReference(computedPositionReference);
|
|
2361
|
+
position.refs.setReference(computedPositionReference);
|
|
2362
|
+
}, [position.refs]);
|
|
2363
|
+
const setReference = react.useCallback((node) => {
|
|
2364
|
+
if (isElement(node) || node === null) {
|
|
2365
|
+
domReferenceRef.current = node;
|
|
2366
|
+
setDomReference(node);
|
|
2367
|
+
}
|
|
2368
|
+
if (isElement(position.refs.reference.current) || position.refs.reference.current === null || node !== null && !isElement(node)) position.refs.setReference(node);
|
|
2369
|
+
}, [position.refs]);
|
|
2370
|
+
const refs = react.useMemo(() => ({
|
|
2371
|
+
...position.refs,
|
|
2372
|
+
setReference,
|
|
2373
|
+
setPositionReference,
|
|
2374
|
+
domReference: domReferenceRef
|
|
2375
|
+
}), [
|
|
2376
|
+
position.refs,
|
|
2377
|
+
setReference,
|
|
2378
|
+
setPositionReference
|
|
2379
|
+
]);
|
|
2380
|
+
const elements = react.useMemo(() => ({
|
|
2381
|
+
...position.elements,
|
|
2382
|
+
domReference
|
|
2383
|
+
}), [position.elements, domReference]);
|
|
2384
|
+
const context = react.useMemo(() => ({
|
|
2385
|
+
...position,
|
|
2386
|
+
...rootContext,
|
|
2387
|
+
refs,
|
|
2388
|
+
elements,
|
|
2389
|
+
nodeId
|
|
2390
|
+
}), [
|
|
2391
|
+
position,
|
|
2392
|
+
refs,
|
|
2393
|
+
elements,
|
|
2394
|
+
nodeId,
|
|
2395
|
+
rootContext
|
|
2396
|
+
]);
|
|
2397
|
+
index$1(() => {
|
|
2398
|
+
rootContext.dataRef.current.floatingContext = context;
|
|
2399
|
+
const node = tree == null ? void 0 : tree.nodesRef.current.find((node) => node.id === nodeId);
|
|
2400
|
+
if (node) node.context = context;
|
|
2401
|
+
});
|
|
2402
|
+
return react.useMemo(() => ({
|
|
2403
|
+
...position,
|
|
2404
|
+
context,
|
|
2405
|
+
refs,
|
|
2406
|
+
elements
|
|
2407
|
+
}), [
|
|
2408
|
+
position,
|
|
2409
|
+
refs,
|
|
2410
|
+
elements,
|
|
2411
|
+
context
|
|
2412
|
+
]);
|
|
2413
|
+
}
|
|
2414
|
+
//#endregion
|
|
2415
|
+
//#region ../../node_modules/.pnpm/dsh-plugin-core@0.5.0_@babel+runtime@8.0.8_@codemirror+autocomplete@6.20.4_@codemirror+_bddbf1bc7ba0e94be71f734653121d0c/node_modules/dsh-plugin-core/dist/utils/i18n.js
|
|
2416
|
+
/**
|
|
2417
|
+
* utils 自带的最小多语言。
|
|
2418
|
+
*
|
|
2419
|
+
* 原则(需求文档 §5.4):**核心提供什么,核心就负责它的多语言** —— utils 里要吐文案的函数
|
|
2420
|
+
* (如相对时间)自带中英字典;插件**自己界面**的文案仍由插件自己管,这里不提供插件级 i18n 框架。
|
|
2421
|
+
* 需要覆盖时传自己的 `t` 进来即可。
|
|
2422
|
+
*/
|
|
2423
|
+
const DICT = {
|
|
2424
|
+
zh: {
|
|
2425
|
+
sessionLoading: "加载会话…",
|
|
2426
|
+
sessionFailed: "会话加载失败",
|
|
2427
|
+
sessionEmpty: "该会话暂无内容",
|
|
2428
|
+
explorerLoading: "加载中…",
|
|
2429
|
+
explorerFailed: "加载失败",
|
|
2430
|
+
explorerRoot: "工作区",
|
|
2431
|
+
explorerTruncated: "条目过多,已截断",
|
|
2432
|
+
explorerEmptyDir: "空目录",
|
|
2433
|
+
explorerLevels: "选择层级",
|
|
2434
|
+
explorerExpand: "展开",
|
|
2435
|
+
explorerCollapse: "收起",
|
|
2436
|
+
explorerEnter: "进入",
|
|
2437
|
+
explorerRootName: "(工作区根目录)",
|
|
2438
|
+
explorerCrumbsAria: "目录路径",
|
|
2439
|
+
explorerPickFile: "选择此文件",
|
|
2440
|
+
explorerPickDir: "选择",
|
|
2441
|
+
explorerPickDirAria: "选择此目录(连带其下所有文件)",
|
|
2442
|
+
previewClose: "关闭",
|
|
2443
|
+
previewCopyPath: "复制路径",
|
|
2444
|
+
previewRefresh: "刷新",
|
|
2445
|
+
previewRender: "预览",
|
|
2446
|
+
previewSource: "源码",
|
|
2447
|
+
previewMdSwitchAria: "切换渲染或源码",
|
|
2448
|
+
previewHtmlSwitchAria: "切换渲染或源码",
|
|
2449
|
+
previewLoadMore: "加载更多",
|
|
2450
|
+
previewTruncated: "内容过大,仅显示前 {n}",
|
|
2451
|
+
previewOfficeUnavailable: "Office 预览不可用",
|
|
2452
|
+
previewRenderFailed: "预览渲染失败",
|
|
2453
|
+
previewBadPayload: "返回数据不符合预期",
|
|
2454
|
+
previewOutside: "路径在工作区之外",
|
|
2455
|
+
previewNotFound: "文件不存在",
|
|
2456
|
+
previewNotDirectory: "不是文件夹",
|
|
2457
|
+
previewTooLarge: "文件过大,无法预览",
|
|
2458
|
+
previewNotText: "不是文本文件",
|
|
2459
|
+
previewFailedCode: "加载失败({code})",
|
|
2460
|
+
mdCopy: "复制",
|
|
2461
|
+
mdCopied: "已复制",
|
|
2462
|
+
mdCode: "代码",
|
|
2463
|
+
mdWrap: "换行",
|
|
2464
|
+
mdUnwrap: "取消换行",
|
|
2465
|
+
mdFootnotes: "脚注",
|
|
2466
|
+
cardToggle: "展开/收起",
|
|
2467
|
+
modalClose: "关闭",
|
|
2468
|
+
dockClose: "关闭面板",
|
|
2469
|
+
dockResize: "拖动调整宽度",
|
|
2470
|
+
errorRetry: "重试",
|
|
2471
|
+
confirm: "确定",
|
|
2472
|
+
cancel: "取消",
|
|
2473
|
+
dialogOk: "知道了",
|
|
2474
|
+
pickerPlaceholder: "请选择",
|
|
2475
|
+
pickerClear: "不选",
|
|
2476
|
+
pickerEmpty: "暂无可选",
|
|
2477
|
+
pickerNoMatch: "无匹配项",
|
|
2478
|
+
pickerSearch: "搜索…",
|
|
2479
|
+
pickerSelected: "已选 {n} 项",
|
|
2480
|
+
pickerMaxReached: "最多选 {n} 项",
|
|
2481
|
+
pickerDegraded: "候选可能不完整",
|
|
2482
|
+
modelProvider: "供应商",
|
|
2483
|
+
modelModel: "模型",
|
|
2484
|
+
modelDefault: "默认模型",
|
|
2485
|
+
workspaceAll: "所有工作区",
|
|
2486
|
+
relNow: "刚刚",
|
|
2487
|
+
relInJustNow: "即将",
|
|
2488
|
+
relInMinutes: "{n} 分钟后",
|
|
2489
|
+
relInHours: "{n} 小时后",
|
|
2490
|
+
relInDays: "{n} 天后",
|
|
2491
|
+
relInMonths: "{n} 个月后",
|
|
2492
|
+
relInYears: "{n} 年后",
|
|
2493
|
+
relJustNow: "刚刚",
|
|
2494
|
+
relMinutesAgo: "{n} 分钟前",
|
|
2495
|
+
relHoursAgo: "{n} 小时前",
|
|
2496
|
+
relDaysAgo: "{n} 天前",
|
|
2497
|
+
relWeeksAgo: "{n} 周前",
|
|
2498
|
+
relMonthsAgo: "{n} 个月前",
|
|
2499
|
+
relYearsAgo: "{n} 年前",
|
|
2500
|
+
codeCopy: "复制",
|
|
2501
|
+
codeCopied: "已复制",
|
|
2502
|
+
sessionUnknownKind: "未支持的节点类型:",
|
|
2503
|
+
sessionLoadOlder: "加载更早记录",
|
|
2504
|
+
sessionProcess: "过程",
|
|
2505
|
+
triggerRequest: "收到执行请求",
|
|
2506
|
+
triggerGoal: "继续执行目标",
|
|
2507
|
+
triggerAgent: "收到任务消息",
|
|
2508
|
+
triggerTeam: "收到团队消息",
|
|
2509
|
+
triggerSubagent: "子任务状态更新",
|
|
2510
|
+
triggerGithub: "收到 GitHub 事件",
|
|
2511
|
+
triggerWebhook: "收到外部事件",
|
|
2512
|
+
triggerSchedule: "定时任务",
|
|
2513
|
+
triggerJob: "后台任务状态更新",
|
|
2514
|
+
triggerPlugin: "插件状态更新",
|
|
2515
|
+
triggerExplanation: "这条通知触发了本轮回复。",
|
|
2516
|
+
turnProcessTook: "用时 {duration}",
|
|
2517
|
+
turnProcessDeepDiving: "深度求索中,用时{duration}",
|
|
2518
|
+
turnProcessWorked: "已完成工作",
|
|
2519
|
+
turnProcessFailed: "处理失败",
|
|
2520
|
+
turnStopped: "已停止",
|
|
2521
|
+
chatDeepDiving: "深度求索中",
|
|
2522
|
+
thinkLabel: "思考",
|
|
2523
|
+
durationSeconds: "{seconds}秒",
|
|
2524
|
+
durationMinutes: "{minutes}分{seconds}秒",
|
|
2525
|
+
durationHours: "{hours}小时{minutes}分{seconds}秒",
|
|
2526
|
+
durationMilliseconds: "{milliseconds}毫秒",
|
|
2527
|
+
retryActive: "正在重试模型请求",
|
|
2528
|
+
retryCancelled: "模型请求重试已取消",
|
|
2529
|
+
retryStarted: "已重试模型请求",
|
|
2530
|
+
retryScheduled: "等待重试模型请求",
|
|
2531
|
+
retryStatus: "{label}({retry}/{maximum}) · {seconds}s",
|
|
2532
|
+
retryDelay: "重试延迟:",
|
|
2533
|
+
retryFailure: "失败原因:",
|
|
2534
|
+
turnErrorTitle: "本轮运行失败",
|
|
2535
|
+
accountStopped: "任务已停止",
|
|
2536
|
+
maxTokensTitle: "已达到输出 token 上限",
|
|
2537
|
+
maxTokensHint: "回答被截断,已有输出保留在对话中。发送“继续”可让模型接着输出。",
|
|
2538
|
+
failureAuth: "API 密钥无效",
|
|
2539
|
+
failureQuota: "当前请求的额度已用尽",
|
|
2540
|
+
failureAccountSignedOut: "任务已因退出 DeepSeek 登录而停止。",
|
|
2541
|
+
failureAccountSignInRequired: "请先登录 DeepSeek,并确认请求地址支持账号认证。",
|
|
2542
|
+
clockDate: "{m}月{d}日",
|
|
2543
|
+
clockDateYear: "{y}年{m}月{d}日",
|
|
2544
|
+
copyLabel: "复制",
|
|
2545
|
+
copiedLabel: "已复制",
|
|
2546
|
+
branchLabel: "在新对话中分支",
|
|
2547
|
+
branchUnavailableLabel: "只读会话记录不可分支",
|
|
2548
|
+
turnUsageTitle: "本轮用量",
|
|
2549
|
+
turnUsageModel: "提供方 / 模型",
|
|
2550
|
+
turnUsageCacheHit: "缓存命中",
|
|
2551
|
+
turnUsageInput: "未缓存输入",
|
|
2552
|
+
turnUsageCacheRead: "缓存读取",
|
|
2553
|
+
turnUsageCacheWrite: "缓存写入",
|
|
2554
|
+
turnUsageOutput: "输出",
|
|
2555
|
+
turnUsageReasoning: "(其中推理 {tokens})",
|
|
2556
|
+
turnUsageConsumed: "用量 {total}",
|
|
2557
|
+
turnUsageCount: "{count} tok",
|
|
2558
|
+
numberThousand: "{value}K",
|
|
2559
|
+
numberMillion: "{value}M",
|
|
2560
|
+
numberGroupSeparator: ",",
|
|
2561
|
+
stepProcessDoneThinking: "已完成分析",
|
|
2562
|
+
stepProcessDoneRead: "已读取文件",
|
|
2563
|
+
stepProcessDoneReadImage: "已读取图片",
|
|
2564
|
+
stepProcessDoneWrite: "已写入文件",
|
|
2565
|
+
stepProcessDoneSearch: "已搜索代码",
|
|
2566
|
+
stepProcessDoneEdit: "修改了文件",
|
|
2567
|
+
stepProcessDoneCommands: "执行了命令",
|
|
2568
|
+
stepProcessDoneCode: "运行了代码",
|
|
2569
|
+
stepProcessDoneWebSearch: "已搜索网页",
|
|
2570
|
+
stepProcessDoneWebFetch: "已访问网页",
|
|
2571
|
+
stepProcessDoneSubagents: "已协调子智能体",
|
|
2572
|
+
stepProcessDonePlan: "更新了计划",
|
|
2573
|
+
stepProcessDoneQuestions: "向用户提出了问题",
|
|
2574
|
+
stepProcessDoneTools: "已调用工具",
|
|
2575
|
+
stepProcessJoinTwo: "{first}并{second}",
|
|
2576
|
+
stepProcessComma: ",",
|
|
2577
|
+
stepProcessSharedPrefix: "已",
|
|
2578
|
+
stepProcessMore: "{title}等",
|
|
2579
|
+
toolTitleRead: "读取",
|
|
2580
|
+
toolTitleReadImage: "读取图片",
|
|
2581
|
+
toolTitleGrep: "搜索文件内容",
|
|
2582
|
+
toolTitleGlob: "查找文件",
|
|
2583
|
+
toolTitleBash: "运行命令",
|
|
2584
|
+
toolTitleWrite: "写入",
|
|
2585
|
+
toolTitleEdit: "编辑",
|
|
2586
|
+
toolTitleCode: "代码",
|
|
2587
|
+
toolTitleWebSearch: "网页搜索",
|
|
2588
|
+
toolTitleWebFetch: "网页获取",
|
|
2589
|
+
toolTitleGeneric: "工具调用",
|
|
2590
|
+
toolTitleSearch: "搜索",
|
|
2591
|
+
toolInputLabel: "输入",
|
|
2592
|
+
toolOutputLabel: "输出",
|
|
2593
|
+
rowPreparing: "正在准备调用",
|
|
2594
|
+
rowRunning: "运行中",
|
|
2595
|
+
rowFailed: "失败",
|
|
2596
|
+
rowStopped: "已停止",
|
|
2597
|
+
commandRunning: "执行中…",
|
|
2598
|
+
commandFailed: "指令失败",
|
|
2599
|
+
commandDone: "已完成",
|
|
2600
|
+
commandTitle: "指令",
|
|
2601
|
+
collapseLabel: "收起",
|
|
2602
|
+
readWindow: "显示 {shown} / {total} 行",
|
|
2603
|
+
readCollapseAria: "收起内容",
|
|
2604
|
+
readExpandAria: "展开其余 {count} 行",
|
|
2605
|
+
readExpandRest: "… 其余 {count} 行",
|
|
2606
|
+
terminalSignal: "信号 {signal}",
|
|
2607
|
+
terminalExitCode: "退出码 {code}",
|
|
2608
|
+
terminalNoExitCode: "未正常退出",
|
|
2609
|
+
terminalRunning: "运行中",
|
|
2610
|
+
terminalFailed: "失败",
|
|
2611
|
+
terminalDone: "已完成",
|
|
2612
|
+
terminalNoOutput: "无输出",
|
|
2613
|
+
terminalCollapseAria: "收起输出",
|
|
2614
|
+
terminalExpandAria: "展开其余 {n} 行输出",
|
|
2615
|
+
terminalExpandRest: "… 其余 {n} 行",
|
|
2616
|
+
terminalCommandLine: "第 {n} 行",
|
|
2617
|
+
terminalSendInput: "(发送输入)",
|
|
2618
|
+
terminalSession: "终端 {sessionId}",
|
|
2619
|
+
codeBlockLabel: "代码块",
|
|
2620
|
+
diffWrapLabel: "自动换行",
|
|
2621
|
+
diffUnwrapLabel: "取消换行",
|
|
2622
|
+
diffCollapseAria: "收起差异",
|
|
2623
|
+
diffExpandAria: "展开其余 {count} 行差异",
|
|
2624
|
+
diffExpandRest: "… 其余 {count} 行",
|
|
2625
|
+
sessionArchived: "已归档",
|
|
2626
|
+
sessionHeading: "会话预览",
|
|
2627
|
+
changesSingle: "已编辑 {name}",
|
|
2628
|
+
changesMulti: "已编辑 {count} 个文件",
|
|
2629
|
+
changesBinary: "二进制文件",
|
|
2630
|
+
changesAll: "全部 {count} 个文件",
|
|
2631
|
+
changesCollapse: "收起",
|
|
2632
|
+
changesOversized: "文件过大",
|
|
2633
|
+
diffLoading: "正在读取改动…",
|
|
2634
|
+
diffMissing: "这轮改动的内容已不可用",
|
|
2635
|
+
diffError: "无法读取改动",
|
|
2636
|
+
diffBinary: "二进制文件,无法显示改动",
|
|
2637
|
+
diffOversized: "文件过大,无法显示改动",
|
|
2638
|
+
diffCreated: "本轮新建的文件",
|
|
2639
|
+
diffDeleted: "本轮删除的文件",
|
|
2640
|
+
diffUnchanged: "两侧内容相同",
|
|
2641
|
+
diffCoarse: "逐行对比超时,按整个文件替换显示",
|
|
2642
|
+
diffTruncated: "只显示前 {count} 行",
|
|
2643
|
+
continueBranch: "继续对话",
|
|
2644
|
+
forkConfirmTitle: "开分支继续对话",
|
|
2645
|
+
forkConfirmText: "是否需要基于此会话开一个新分支继续对话?原会话保持只读留档,新分支复制本会话内容并可继续对话。",
|
|
2646
|
+
forkConfirmAccept: "开分支并跳转",
|
|
2647
|
+
forkWorking: "正在开分支…",
|
|
2648
|
+
forkFailed: "开分支失败:{error}",
|
|
2649
|
+
deliverRowTitle: "交付文件",
|
|
2650
|
+
deliverRowPreparing: "准备交付",
|
|
2651
|
+
deliverRowRunning: "正在交付",
|
|
2652
|
+
deliverRowOk: "已交付",
|
|
2653
|
+
deliverRowError: "交付失败",
|
|
2654
|
+
deliverRowStopped: "已中断",
|
|
2655
|
+
deliverFileLabel: "文件",
|
|
2656
|
+
deliverPreviewHint: "预览",
|
|
2657
|
+
deliverPreviewCard: "预览 {name}",
|
|
2658
|
+
deliverAll: "全部 {count} 个文件",
|
|
2659
|
+
deliverCollapse: "收起",
|
|
2660
|
+
deliverExpandAria: "展开全部 {count} 个交付文件",
|
|
2661
|
+
deliverCollapseAria: "收起交付文件列表",
|
|
2662
|
+
composerPlaceholder: "继续说点什么…",
|
|
2663
|
+
composerHint: "点「确定」后基于本会话开分支,并在官方会话中开始这轮对话",
|
|
2664
|
+
dtPlaceholder: "请选择日期时间",
|
|
2665
|
+
dtStart: "开始",
|
|
2666
|
+
dtEnd: "结束",
|
|
2667
|
+
dtToday: "今天",
|
|
2668
|
+
dtNow: "现在",
|
|
2669
|
+
dtClear: "清除",
|
|
2670
|
+
dtHour: "时",
|
|
2671
|
+
dtMinute: "分",
|
|
2672
|
+
dtSecond: "秒",
|
|
2673
|
+
dtPrevYear: "上一年",
|
|
2674
|
+
dtPrevMonth: "上一月",
|
|
2675
|
+
dtNextMonth: "下一月",
|
|
2676
|
+
dtNextYear: "下一年",
|
|
2677
|
+
dtInvalidRange: "结束时间早于开始时间"
|
|
2678
|
+
},
|
|
2679
|
+
en: {
|
|
2680
|
+
sessionLoading: "Loading session…",
|
|
2681
|
+
sessionFailed: "Failed to load session",
|
|
2682
|
+
sessionEmpty: "No content in this session",
|
|
2683
|
+
explorerLoading: "Loading…",
|
|
2684
|
+
explorerFailed: "Failed to load",
|
|
2685
|
+
explorerRoot: "Workspace",
|
|
2686
|
+
explorerTruncated: "Too many entries, truncated",
|
|
2687
|
+
explorerEmptyDir: "Empty folder",
|
|
2688
|
+
explorerLevels: "Jump to level",
|
|
2689
|
+
explorerExpand: "Expand",
|
|
2690
|
+
explorerCollapse: "Collapse",
|
|
2691
|
+
explorerEnter: "Open",
|
|
2692
|
+
explorerRootName: "(workspace root)",
|
|
2693
|
+
explorerCrumbsAria: "Breadcrumb",
|
|
2694
|
+
explorerPickFile: "Pick this file",
|
|
2695
|
+
explorerPickDir: "Select",
|
|
2696
|
+
explorerPickDirAria: "Pick this folder (with everything under it)",
|
|
2697
|
+
previewClose: "Close",
|
|
2698
|
+
previewCopyPath: "Copy path",
|
|
2699
|
+
previewRefresh: "Refresh",
|
|
2700
|
+
previewRender: "Preview",
|
|
2701
|
+
previewSource: "Source",
|
|
2702
|
+
previewMdSwitchAria: "Toggle render or source",
|
|
2703
|
+
previewHtmlSwitchAria: "Toggle render or source",
|
|
2704
|
+
previewLoadMore: "Load more",
|
|
2705
|
+
previewTruncated: "Content too large, showing first {n}",
|
|
2706
|
+
previewOfficeUnavailable: "Office preview unavailable",
|
|
2707
|
+
previewRenderFailed: "Failed to render preview",
|
|
2708
|
+
previewBadPayload: "Unexpected response payload",
|
|
2709
|
+
previewOutside: "Path is outside the workspace",
|
|
2710
|
+
previewNotFound: "File not found",
|
|
2711
|
+
previewNotDirectory: "Not a folder",
|
|
2712
|
+
previewTooLarge: "File too large to preview",
|
|
2713
|
+
previewNotText: "Not a text file",
|
|
2714
|
+
previewFailedCode: "Failed to load ({code})",
|
|
2715
|
+
mdCopy: "Copy",
|
|
2716
|
+
mdCopied: "Copied",
|
|
2717
|
+
mdCode: "Code",
|
|
2718
|
+
mdWrap: "Wrap",
|
|
2719
|
+
mdUnwrap: "Unwrap",
|
|
2720
|
+
mdFootnotes: "Footnotes",
|
|
2721
|
+
cardToggle: "Expand/Collapse",
|
|
2722
|
+
modalClose: "Close",
|
|
2723
|
+
dockClose: "Close panel",
|
|
2724
|
+
dockResize: "Drag to resize",
|
|
2725
|
+
errorRetry: "Retry",
|
|
2726
|
+
confirm: "Confirm",
|
|
2727
|
+
cancel: "Cancel",
|
|
2728
|
+
dialogOk: "OK",
|
|
2729
|
+
pickerPlaceholder: "Select…",
|
|
2730
|
+
pickerClear: "None",
|
|
2731
|
+
pickerEmpty: "No options",
|
|
2732
|
+
pickerNoMatch: "No match",
|
|
2733
|
+
pickerSearch: "Search…",
|
|
2734
|
+
pickerSelected: "{n} selected",
|
|
2735
|
+
pickerMaxReached: "Up to {n}",
|
|
2736
|
+
pickerDegraded: "List may be incomplete",
|
|
2737
|
+
modelProvider: "Provider",
|
|
2738
|
+
modelModel: "Model",
|
|
2739
|
+
modelDefault: "Default model",
|
|
2740
|
+
workspaceAll: "All workspaces",
|
|
2741
|
+
relNow: "just now",
|
|
2742
|
+
relInJustNow: "soon",
|
|
2743
|
+
relInMinutes: "in {n}m",
|
|
2744
|
+
relInHours: "in {n}h",
|
|
2745
|
+
relInDays: "in {n}d",
|
|
2746
|
+
relInMonths: "in {n}mo",
|
|
2747
|
+
relInYears: "in {n}y",
|
|
2748
|
+
relJustNow: "just now",
|
|
2749
|
+
relMinutesAgo: "{n}m ago",
|
|
2750
|
+
relHoursAgo: "{n}h ago",
|
|
2751
|
+
relDaysAgo: "{n}d ago",
|
|
2752
|
+
relWeeksAgo: "{n}w ago",
|
|
2753
|
+
relMonthsAgo: "{n}mo ago",
|
|
2754
|
+
relYearsAgo: "{n}y ago",
|
|
2755
|
+
codeCopy: "Copy",
|
|
2756
|
+
codeCopied: "Copied",
|
|
2757
|
+
sessionUnknownKind: "Unsupported node kind: ",
|
|
2758
|
+
sessionLoadOlder: "Load earlier messages",
|
|
2759
|
+
sessionProcess: "Process",
|
|
2760
|
+
triggerRequest: "Execution request received",
|
|
2761
|
+
triggerGoal: "Continuing the goal",
|
|
2762
|
+
triggerAgent: "Task message received",
|
|
2763
|
+
triggerTeam: "Team message received",
|
|
2764
|
+
triggerSubagent: "Subagent status update",
|
|
2765
|
+
triggerGithub: "GitHub event received",
|
|
2766
|
+
triggerWebhook: "External event received",
|
|
2767
|
+
triggerSchedule: "Scheduled task",
|
|
2768
|
+
triggerJob: "Background task status update",
|
|
2769
|
+
triggerPlugin: "Plugin status update",
|
|
2770
|
+
triggerExplanation: "This notification triggered the reply below.",
|
|
2771
|
+
turnProcessTook: "Took {duration}",
|
|
2772
|
+
turnProcessDeepDiving: "Thinking, {duration}",
|
|
2773
|
+
turnProcessWorked: "Work completed",
|
|
2774
|
+
turnProcessFailed: "Failed",
|
|
2775
|
+
turnStopped: "Stopped",
|
|
2776
|
+
chatDeepDiving: "Thinking",
|
|
2777
|
+
thinkLabel: "Think",
|
|
2778
|
+
durationSeconds: "{seconds}s",
|
|
2779
|
+
durationMinutes: "{minutes}m {seconds}s",
|
|
2780
|
+
durationHours: "{hours}h {minutes}m {seconds}s",
|
|
2781
|
+
durationMilliseconds: "{milliseconds}ms",
|
|
2782
|
+
retryActive: "Retrying model request",
|
|
2783
|
+
retryCancelled: "Model request retry cancelled",
|
|
2784
|
+
retryStarted: "Retried model request",
|
|
2785
|
+
retryScheduled: "Waiting to retry model request",
|
|
2786
|
+
retryStatus: "{label} ({retry}/{maximum}) · {seconds}s",
|
|
2787
|
+
retryDelay: "Retry delay: ",
|
|
2788
|
+
retryFailure: "Failure reason: ",
|
|
2789
|
+
turnErrorTitle: "This turn failed",
|
|
2790
|
+
accountStopped: "Task stopped",
|
|
2791
|
+
maxTokensTitle: "Output token limit reached",
|
|
2792
|
+
maxTokensHint: "The reply was cut off; earlier output is preserved in the conversation. Send \"continue\" to let the model resume.",
|
|
2793
|
+
failureAuth: "API key is invalid",
|
|
2794
|
+
failureQuota: "Request quota exhausted.",
|
|
2795
|
+
failureAccountSignedOut: "Stopped because you signed out of DeepSeek.",
|
|
2796
|
+
failureAccountSignInRequired: "Sign in to DeepSeek and ensure the request destination supports account authentication.",
|
|
2797
|
+
clockDate: "{m}/{d}",
|
|
2798
|
+
clockDateYear: "{y}/{m}/{d}",
|
|
2799
|
+
copyLabel: "Copy",
|
|
2800
|
+
copiedLabel: "Copied",
|
|
2801
|
+
branchLabel: "Branch into a new conversation",
|
|
2802
|
+
branchUnavailableLabel: "A read-only transcript cannot be branched",
|
|
2803
|
+
turnUsageTitle: "Turn usage",
|
|
2804
|
+
turnUsageModel: "Provider / model",
|
|
2805
|
+
turnUsageCacheHit: "Cache hit",
|
|
2806
|
+
turnUsageInput: "Uncached input",
|
|
2807
|
+
turnUsageCacheRead: "Cached input",
|
|
2808
|
+
turnUsageCacheWrite: "Cache write",
|
|
2809
|
+
turnUsageOutput: "Output",
|
|
2810
|
+
turnUsageReasoning: " ({tokens} reasoning)",
|
|
2811
|
+
turnUsageConsumed: "Usage {total}",
|
|
2812
|
+
turnUsageCount: "{count} tok",
|
|
2813
|
+
numberThousand: "{value}K",
|
|
2814
|
+
numberMillion: "{value}M",
|
|
2815
|
+
numberGroupSeparator: ",",
|
|
2816
|
+
stepProcessDoneThinking: "Analysis completed",
|
|
2817
|
+
stepProcessDoneRead: "Read files",
|
|
2818
|
+
stepProcessDoneReadImage: "Read images",
|
|
2819
|
+
stepProcessDoneWrite: "Wrote files",
|
|
2820
|
+
stepProcessDoneSearch: "Searched code",
|
|
2821
|
+
stepProcessDoneEdit: "Edited files",
|
|
2822
|
+
stepProcessDoneCommands: "Ran commands",
|
|
2823
|
+
stepProcessDoneCode: "Ran code",
|
|
2824
|
+
stepProcessDoneWebSearch: "Searched the web",
|
|
2825
|
+
stepProcessDoneWebFetch: "Fetched web pages",
|
|
2826
|
+
stepProcessDoneSubagents: "Coordinated subagents",
|
|
2827
|
+
stepProcessDonePlan: "Updated the plan",
|
|
2828
|
+
stepProcessDoneQuestions: "Asked you questions",
|
|
2829
|
+
stepProcessDoneTools: "Called tools",
|
|
2830
|
+
stepProcessJoinTwo: "{first} and {second}",
|
|
2831
|
+
stepProcessComma: ", ",
|
|
2832
|
+
stepProcessSharedPrefix: "",
|
|
2833
|
+
stepProcessMore: "{title}, etc.",
|
|
2834
|
+
toolTitleRead: "Read",
|
|
2835
|
+
toolTitleReadImage: "Read image",
|
|
2836
|
+
toolTitleGrep: "Grep",
|
|
2837
|
+
toolTitleGlob: "Glob",
|
|
2838
|
+
toolTitleBash: "Bash",
|
|
2839
|
+
toolTitleWrite: "Write",
|
|
2840
|
+
toolTitleEdit: "Edit",
|
|
2841
|
+
toolTitleCode: "Code",
|
|
2842
|
+
toolTitleWebSearch: "Search",
|
|
2843
|
+
toolTitleWebFetch: "Fetch",
|
|
2844
|
+
toolTitleGeneric: "Tool call",
|
|
2845
|
+
toolTitleSearch: "Search",
|
|
2846
|
+
toolInputLabel: "IN",
|
|
2847
|
+
toolOutputLabel: "OUT",
|
|
2848
|
+
rowPreparing: "Preparing tool call",
|
|
2849
|
+
rowRunning: "Running",
|
|
2850
|
+
rowFailed: "Failed",
|
|
2851
|
+
rowStopped: "Stopped",
|
|
2852
|
+
commandRunning: "Running…",
|
|
2853
|
+
commandFailed: "Command failed",
|
|
2854
|
+
commandDone: "Completed",
|
|
2855
|
+
commandTitle: "Command",
|
|
2856
|
+
collapseLabel: "Collapse",
|
|
2857
|
+
readWindow: "Showing {shown} of {total} lines",
|
|
2858
|
+
readCollapseAria: "Collapse content",
|
|
2859
|
+
readExpandAria: "Expand {count} more lines",
|
|
2860
|
+
readExpandRest: "… {count} more lines",
|
|
2861
|
+
terminalSignal: "signal {signal}",
|
|
2862
|
+
terminalExitCode: "exit code {code}",
|
|
2863
|
+
terminalNoExitCode: "no exit code",
|
|
2864
|
+
terminalRunning: "Running",
|
|
2865
|
+
terminalFailed: "Failed",
|
|
2866
|
+
terminalDone: "Done",
|
|
2867
|
+
terminalNoOutput: "No output",
|
|
2868
|
+
terminalCollapseAria: "Collapse output",
|
|
2869
|
+
terminalExpandAria: "Expand the remaining {n} output lines",
|
|
2870
|
+
terminalExpandRest: "… {n} more lines",
|
|
2871
|
+
terminalCommandLine: "line {n}",
|
|
2872
|
+
terminalSendInput: "(send input)",
|
|
2873
|
+
terminalSession: "Terminal {sessionId}",
|
|
2874
|
+
codeBlockLabel: "Code",
|
|
2875
|
+
diffWrapLabel: "Wrap lines",
|
|
2876
|
+
diffUnwrapLabel: "Unwrap lines",
|
|
2877
|
+
diffCollapseAria: "Collapse diff",
|
|
2878
|
+
diffExpandAria: "Expand {count} more diff lines",
|
|
2879
|
+
diffExpandRest: "… {count} more lines",
|
|
2880
|
+
sessionArchived: "Archived",
|
|
2881
|
+
sessionHeading: "Session preview",
|
|
2882
|
+
changesSingle: "Edited {name}",
|
|
2883
|
+
changesMulti: "Edited {count} files",
|
|
2884
|
+
changesBinary: "Binary file",
|
|
2885
|
+
changesAll: "All {count} files",
|
|
2886
|
+
changesCollapse: "Collapse",
|
|
2887
|
+
changesOversized: "File too large",
|
|
2888
|
+
diffLoading: "Reading changes…",
|
|
2889
|
+
diffMissing: "The contents of this turn’s changes are no longer available",
|
|
2890
|
+
diffError: "Could not read the changes",
|
|
2891
|
+
diffBinary: "Binary file; changes cannot be shown",
|
|
2892
|
+
diffOversized: "File too large; changes cannot be shown",
|
|
2893
|
+
diffCreated: "Created in this turn",
|
|
2894
|
+
diffDeleted: "Deleted in this turn",
|
|
2895
|
+
diffUnchanged: "Both sides hold the same lines",
|
|
2896
|
+
diffCoarse: "Line comparison timed out; shown as a whole-file replacement",
|
|
2897
|
+
diffTruncated: "Showing the first {count} lines",
|
|
2898
|
+
continueBranch: "Continue conversation",
|
|
2899
|
+
forkConfirmTitle: "Fork to continue",
|
|
2900
|
+
forkConfirmText: "Start a new branch from this session to continue the conversation? The original stays read-only; the branch copies this conversation and can continue.",
|
|
2901
|
+
forkConfirmAccept: "Fork & open",
|
|
2902
|
+
forkWorking: "Forking…",
|
|
2903
|
+
forkFailed: "Fork failed: {error}",
|
|
2904
|
+
deliverRowTitle: "Deliver files",
|
|
2905
|
+
deliverRowPreparing: "Preparing delivery",
|
|
2906
|
+
deliverRowRunning: "Delivering",
|
|
2907
|
+
deliverRowOk: "Delivered",
|
|
2908
|
+
deliverRowError: "Delivery failed",
|
|
2909
|
+
deliverRowStopped: "Interrupted",
|
|
2910
|
+
deliverFileLabel: "File",
|
|
2911
|
+
deliverPreviewHint: "Preview",
|
|
2912
|
+
deliverPreviewCard: "Preview {name}",
|
|
2913
|
+
deliverAll: "All {count} files",
|
|
2914
|
+
deliverCollapse: "Collapse",
|
|
2915
|
+
deliverExpandAria: "Expand all {count} delivered files",
|
|
2916
|
+
deliverCollapseAria: "Collapse the delivered-files list",
|
|
2917
|
+
composerPlaceholder: "Say something to continue…",
|
|
2918
|
+
composerHint: "Confirm forks a branch from this session and starts this turn in the official chat",
|
|
2919
|
+
dtPlaceholder: "Select date & time",
|
|
2920
|
+
dtStart: "Start",
|
|
2921
|
+
dtEnd: "End",
|
|
2922
|
+
dtToday: "Today",
|
|
2923
|
+
dtNow: "Now",
|
|
2924
|
+
dtClear: "Clear",
|
|
2925
|
+
dtHour: "h",
|
|
2926
|
+
dtMinute: "m",
|
|
2927
|
+
dtSecond: "s",
|
|
2928
|
+
dtPrevYear: "Previous year",
|
|
2929
|
+
dtPrevMonth: "Previous month",
|
|
2930
|
+
dtNextMonth: "Next month",
|
|
2931
|
+
dtNextYear: "Next year",
|
|
2932
|
+
dtInvalidRange: "End is before start"
|
|
2933
|
+
}
|
|
2934
|
+
};
|
|
2935
|
+
let current = "zh";
|
|
2936
|
+
/** 用内置字典翻译一个 key;未知 key 直接回退 key 本身(不抛、不空白)。 */
|
|
2937
|
+
function t$1(key, vars) {
|
|
2938
|
+
const template = DICT[current][key] ?? DICT.zh[key] ?? key;
|
|
2939
|
+
if (vars === void 0) return template;
|
|
2940
|
+
return template.replace(/\{(\w+)\}/g, (whole, name) => {
|
|
2941
|
+
const value = vars[name];
|
|
2942
|
+
return value === void 0 ? whole : String(value);
|
|
2943
|
+
});
|
|
2944
|
+
}
|
|
2945
|
+
//#endregion
|
|
2946
|
+
//#region ../../node_modules/.pnpm/dsh-plugin-core@0.5.0_@babel+runtime@8.0.8_@codemirror+autocomplete@6.20.4_@codemirror+_bddbf1bc7ba0e94be71f734653121d0c/node_modules/dsh-plugin-core/dist/ui/FieldHint.js
|
|
2947
|
+
/**
|
|
2948
|
+
* 问号提示 —— **全站唯一实现、独立组件**(L2,P4)
|
|
2949
|
+
*
|
|
2950
|
+
* ⚠️ 它**不属于 Input 家族**:任何地方都能挂——表单行尾、标题后面、卡片角落……
|
|
2951
|
+
* 调用点自己把它排进自己的 flex / label 里即可(组件只是 14px 的内联图标 + 气泡)。
|
|
2952
|
+
*
|
|
2953
|
+
* 气泡渲染 = **官方 Tooltip 本体**(2026-10-19 用户拍板「必须和悬停提示用同一个」):
|
|
2954
|
+
* 插件启动时 `setTooltipRenderer` 把官方 Tooltip 交给 core,本组件直接走它。
|
|
2955
|
+
* ⚠️ **不做降级兜底**(用户同日明确:宿主内官方包恒在;官方改版 = 我们重新适配,不另造一套)。
|
|
2956
|
+
* 未注入 renderer 的环境(node 自检)只出问号图标、没有气泡——那是非宿主环境,不是产品形态。
|
|
2957
|
+
*/
|
|
2958
|
+
/** 问号提示图标:hover / focus 浮出说明气泡(官方 Tooltip 渲染)。 */
|
|
2959
|
+
function FieldHint(props) {
|
|
2960
|
+
ensureControls();
|
|
2961
|
+
const { text, side, align, maxWidth, className, style } = props;
|
|
2962
|
+
return (0, react.createElement)("span", {
|
|
2963
|
+
className: `dshpc-hint${className !== void 0 && className !== "" ? ` ${className}` : ""}`,
|
|
2964
|
+
style,
|
|
2965
|
+
tabIndex: 0,
|
|
2966
|
+
role: "note",
|
|
2967
|
+
"aria-label": text
|
|
2968
|
+
}, "?");
|
|
2969
|
+
}
|
|
2970
|
+
//#endregion
|
|
2971
|
+
//#region ../../node_modules/.pnpm/dsh-plugin-core@0.5.0_@babel+runtime@8.0.8_@codemirror+autocomplete@6.20.4_@codemirror+_bddbf1bc7ba0e94be71f734653121d0c/node_modules/dsh-plugin-core/dist/ui/Picker.js
|
|
2972
|
+
/**
|
|
2973
|
+
* 通用选择器:单选 / 多选 / 上限 / 搜索 / 分组 / 空态 / 降级。
|
|
2974
|
+
*
|
|
2975
|
+
* **纯零件,不自己取数** —— 选项由调用方传入(工作区列表、模型列表这类数据要跨 host↔client
|
|
2976
|
+
* 边界,通道是插件私有的,组件取不到,见需求文档 §6)。
|
|
2977
|
+
*/
|
|
2978
|
+
function Picker(props) {
|
|
2979
|
+
ensureControls();
|
|
2980
|
+
const tt = props.translate ?? t$1;
|
|
2981
|
+
const mode = props.mode ?? "single";
|
|
2982
|
+
const size$3 = props.size ?? "md";
|
|
2983
|
+
const placement = props.placement ?? "down";
|
|
2984
|
+
const clearable = props.clearable === true;
|
|
2985
|
+
const showLabels = props.showLabels !== false;
|
|
2986
|
+
const groups = (0, react.useMemo)(() => toGroups(props.groups, props.options), [props.groups, props.options]);
|
|
2987
|
+
const controlled = props.value !== void 0;
|
|
2988
|
+
const [inner, setInner] = (0, react.useState)(() => toArray(props.defaultValue));
|
|
2989
|
+
const selected = controlled ? toArray(props.value) : inner;
|
|
2990
|
+
const emit = (next) => {
|
|
2991
|
+
if (!controlled) setInner(next);
|
|
2992
|
+
props.onChange?.(mode === "single" ? next[0] ?? "" : next);
|
|
2993
|
+
};
|
|
2994
|
+
const [open, setOpen] = (0, react.useState)(false);
|
|
2995
|
+
const [query, setQuery] = (0, react.useState)("");
|
|
2996
|
+
const [active, setActive] = (0, react.useState)(-1);
|
|
2997
|
+
const rootRef = (0, react.useRef)(null);
|
|
2998
|
+
const searchRef = (0, react.useRef)(null);
|
|
2999
|
+
const { refs, floatingStyles } = useFloating({
|
|
3000
|
+
open,
|
|
3001
|
+
onOpenChange: setOpen,
|
|
3002
|
+
placement: placement === "up" ? "top-start" : "bottom-start",
|
|
3003
|
+
middleware: [
|
|
3004
|
+
offset(4),
|
|
3005
|
+
flip(),
|
|
3006
|
+
shift({ padding: 8 }),
|
|
3007
|
+
size({ apply({ elements, rects, availableWidth, availableHeight }) {
|
|
3008
|
+
Object.assign(elements.floating.style, {
|
|
3009
|
+
minWidth: `${rects.reference.width}px`,
|
|
3010
|
+
maxWidth: `${Math.min(480, availableWidth ?? 480)}px`,
|
|
3011
|
+
maxHeight: `${Math.max(80, Math.min(280, (availableHeight ?? 320) - 8))}px`
|
|
3012
|
+
});
|
|
3013
|
+
} })
|
|
3014
|
+
],
|
|
3015
|
+
whileElementsMounted: autoUpdate,
|
|
3016
|
+
strategy: "fixed"
|
|
3017
|
+
});
|
|
3018
|
+
const setSearchRef = (0, react.useCallback)((el) => {
|
|
3019
|
+
searchRef.current = el;
|
|
3020
|
+
if (el !== null && open) el.focus();
|
|
3021
|
+
}, [open]);
|
|
3022
|
+
(0, react.useEffect)(() => {
|
|
3023
|
+
if (!open) return;
|
|
3024
|
+
const onDown = (e) => {
|
|
3025
|
+
const root = rootRef.current;
|
|
3026
|
+
const floatingEl = refs.floating.current;
|
|
3027
|
+
if (root !== null && root.contains(e.target)) return;
|
|
3028
|
+
if (floatingEl !== null && floatingEl.contains(e.target)) return;
|
|
3029
|
+
setOpen(false);
|
|
3030
|
+
};
|
|
3031
|
+
document.addEventListener("mousedown", onDown);
|
|
3032
|
+
return () => document.removeEventListener("mousedown", onDown);
|
|
3033
|
+
}, [open]);
|
|
3034
|
+
(0, react.useEffect)(() => {
|
|
3035
|
+
if (open) return;
|
|
3036
|
+
setQuery("");
|
|
3037
|
+
setActive(-1);
|
|
3038
|
+
}, [open]);
|
|
3039
|
+
const shown = filterGroups(groups, query);
|
|
3040
|
+
const flat = flattenOptions(shown);
|
|
3041
|
+
const atMax = mode === "multiple" && props.max !== void 0 && selected.length >= props.max;
|
|
3042
|
+
const summary = selected.length === 0 ? props.placeholder ?? tt("pickerPlaceholder") : mode === "multiple" && !showLabels ? tt("pickerSelected", { n: selected.length }) : labelsOf(groups, selected).join("、") || (props.placeholder ?? tt("pickerPlaceholder"));
|
|
3043
|
+
const pick = (value) => {
|
|
3044
|
+
if (mode === "single") {
|
|
3045
|
+
emit([value]);
|
|
3046
|
+
setOpen(false);
|
|
3047
|
+
return;
|
|
3048
|
+
}
|
|
3049
|
+
emit(toggleValue(selected, value, props.max));
|
|
3050
|
+
if (props.closeOnSelect === true) setOpen(false);
|
|
3051
|
+
};
|
|
3052
|
+
const clear = () => {
|
|
3053
|
+
emit([]);
|
|
3054
|
+
setOpen(false);
|
|
3055
|
+
};
|
|
3056
|
+
const onKeyDown = (e) => {
|
|
3057
|
+
if (!open) return;
|
|
3058
|
+
if (e.key === "Escape") {
|
|
3059
|
+
setOpen(false);
|
|
3060
|
+
return;
|
|
3061
|
+
}
|
|
3062
|
+
if (flat.length === 0) return;
|
|
3063
|
+
if (e.key === "ArrowDown" || e.key === "ArrowUp") {
|
|
3064
|
+
e.preventDefault();
|
|
3065
|
+
const dir = e.key === "ArrowDown" ? 1 : -1;
|
|
3066
|
+
setActive((cur) => (cur + dir + flat.length) % flat.length);
|
|
3067
|
+
return;
|
|
3068
|
+
}
|
|
3069
|
+
if (e.key === "Enter" && active >= 0) {
|
|
3070
|
+
e.preventDefault();
|
|
3071
|
+
const hit = flat[active];
|
|
3072
|
+
if (hit !== void 0) pick(hit.value);
|
|
3073
|
+
}
|
|
3074
|
+
};
|
|
3075
|
+
const trigger = (0, react.createElement)("button", {
|
|
3076
|
+
type: "button",
|
|
3077
|
+
"aria-label": props.ariaLabel,
|
|
3078
|
+
"aria-expanded": open,
|
|
3079
|
+
ref: refs.setReference,
|
|
3080
|
+
className: `dshpc-picker__trigger dshpc-picker__trigger--${size$3}${props.align === "center" ? " dshpc-picker__trigger--center" : ""}`,
|
|
3081
|
+
disabled: props.disabled === true,
|
|
3082
|
+
onClick: () => {
|
|
3083
|
+
if (props.disabled !== true) setOpen(!open);
|
|
3084
|
+
}
|
|
3085
|
+
}, props.icon !== void 0 && props.icon !== null ? (0, react.createElement)("span", { className: "dshpc-picker__icon" }, props.icon) : null, (0, react.createElement)("span", { className: "dshpc-picker__label" }, summary), (0, react.createElement)("svg", {
|
|
3086
|
+
className: "dshpc-picker__caret",
|
|
3087
|
+
width: 12,
|
|
3088
|
+
height: 12,
|
|
3089
|
+
viewBox: "0 0 16 16",
|
|
3090
|
+
fill: "none",
|
|
3091
|
+
"aria-hidden": true
|
|
3092
|
+
}, (0, react.createElement)("path", {
|
|
3093
|
+
d: "M4 6l4 4 4-4",
|
|
3094
|
+
stroke: "currentColor",
|
|
3095
|
+
"stroke-width": 1.5,
|
|
3096
|
+
"stroke-linecap": "round",
|
|
3097
|
+
"stroke-linejoin": "round"
|
|
3098
|
+
})));
|
|
3099
|
+
const triggerRow = props.hint === void 0 ? trigger : (0, react.createElement)("span", { className: "dshpc-fieldwrap dshpc-fieldwrap--inline" }, trigger, (0, react.createElement)(FieldHint, { text: props.hint }));
|
|
3100
|
+
return (0, react.createElement)("div", {
|
|
3101
|
+
className: `dshpc-picker${props.className === void 0 ? "" : ` ${props.className}`}`,
|
|
3102
|
+
ref: rootRef,
|
|
3103
|
+
onKeyDown
|
|
3104
|
+
}, triggerRow, open ? (0, react.createElement)(FloatingPortal, null, (0, react.createElement)("div", {
|
|
3105
|
+
className: "dshpc-picker__menu",
|
|
3106
|
+
ref: refs.setFloating,
|
|
3107
|
+
style: floatingStyles
|
|
3108
|
+
}, props.degraded === true ? (0, react.createElement)("div", { className: "dshpc-picker__degraded" }, tt("pickerDegraded")) : null, atMax ? (0, react.createElement)("div", { className: "dshpc-picker__degraded" }, tt("pickerMaxReached", { n: props.max ?? 0 })) : null, props.searchable === true ? (0, react.createElement)("input", {
|
|
3109
|
+
ref: setSearchRef,
|
|
3110
|
+
className: "dshpc-picker__search",
|
|
3111
|
+
placeholder: tt("pickerSearch"),
|
|
3112
|
+
value: query,
|
|
3113
|
+
onChange: (e) => setQuery(e.target.value)
|
|
3114
|
+
}) : null, flat.length === 0 && groups.length === 0 ? (0, react.createElement)("div", { className: "dshpc-picker__empty" }, tt("pickerEmpty")) : flat.length === 0 ? (0, react.createElement)("div", { className: "dshpc-picker__empty" }, tt("pickerNoMatch")) : [clearable && mode === "single" && selected.length > 0 ? (0, react.createElement)("div", {
|
|
3115
|
+
key: "__clear__",
|
|
3116
|
+
className: "dshpc-picker__option dshpc-picker__option--clear",
|
|
3117
|
+
onClick: clear
|
|
3118
|
+
}, tt("pickerClear")) : null, ...shown.map((g) => (0, react.createElement)("div", { key: g.value || "_" }, g.label === "" ? null : (0, react.createElement)("div", { className: "dshpc-picker__group-label" }, g.label), g.options.map((o) => {
|
|
3119
|
+
const blocked = o.disabled === true || atMax && !selected.includes(o.value);
|
|
3120
|
+
const activeCls = [
|
|
3121
|
+
"dshpc-picker__option",
|
|
3122
|
+
selected.includes(o.value) ? "dshpc-picker__option--active" : "",
|
|
3123
|
+
blocked ? "dshpc-picker__option--disabled" : ""
|
|
3124
|
+
].filter((s) => s !== "").join(" ");
|
|
3125
|
+
const idx = flat.indexOf(o);
|
|
3126
|
+
return (0, react.createElement)("div", {
|
|
3127
|
+
key: o.value,
|
|
3128
|
+
className: activeCls,
|
|
3129
|
+
"data-active": idx === active ? "true" : void 0,
|
|
3130
|
+
onClick: () => {
|
|
3131
|
+
if (!blocked) pick(o.value);
|
|
3132
|
+
}
|
|
3133
|
+
}, mode === "multiple" ? (0, react.createElement)("span", { className: "dshpc-picker__tick" }, selected.includes(o.value) ? "✓" : "") : null, o.icon !== void 0 && o.icon !== null ? (0, react.createElement)("span", { className: "dshpc-picker__option-icon" }, o.icon) : null, (0, react.createElement)("span", null, o.label));
|
|
3134
|
+
})))])) : null);
|
|
3135
|
+
}
|
|
3136
|
+
function toArray(v) {
|
|
3137
|
+
if (v === void 0) return [];
|
|
3138
|
+
return Array.isArray(v) ? [...v] : [v];
|
|
3139
|
+
}
|
|
3140
|
+
//#endregion
|
|
3141
|
+
//#region ../../node_modules/.pnpm/dsh-plugin-core@0.5.0_@babel+runtime@8.0.8_@codemirror+autocomplete@6.20.4_@codemirror+_bddbf1bc7ba0e94be71f734653121d0c/node_modules/dsh-plugin-core/dist/ui/Button.js
|
|
3142
|
+
/**
|
|
3143
|
+
* 按钮 / 图标钮 —— **全站唯一实现**(L2 组件皮肤,P2)
|
|
3144
|
+
*
|
|
3145
|
+
* 三轴模型:
|
|
3146
|
+
* - `variant`:外观档(形态 + 语义色),共 10 档
|
|
3147
|
+
* primary(黑实心)/ secondary(灰实心)/ outline(描边)/ ghost(无底无边)
|
|
3148
|
+
* danger(红实心)/ success(绿实心)/ warning(黄实心)/ info(蓝实心)
|
|
3149
|
+
* danger-outline(红字描边)/ link(行内链接)
|
|
3150
|
+
* - `size`:`sm`(24) / `md`(28) / `lg`(32) —— 高度一律吃 `--dshpc-control-h-*`,
|
|
3151
|
+
* **有边 / 无边同高**(边框在内部补回)
|
|
3152
|
+
* - `block`:撑满父宽
|
|
3153
|
+
*
|
|
3154
|
+
* 内容轴:`icon`(前置)/ `iconRight`(后置)/ `loading`(前置小圈并自动禁用)。
|
|
3155
|
+
* 颜色轴:任一档都可以再用 `color` 传任意 CSS 色值 —— 只覆盖 `--btn-*` 几个变量,
|
|
3156
|
+
* 不新增皮肤(皮肤仍只在 `controls-css.ts` 里)。
|
|
3157
|
+
*
|
|
3158
|
+
* `IconButton` 是纯图标钮:`plain`(默认无底无边,hover 起灰底)/ `outline`(描边)/ `danger`(红)。
|
|
3159
|
+
* 兼容别名:`danger-ink` 仍是 `danger-outline` 的旧类名,可直接挂 className。
|
|
3160
|
+
*
|
|
3161
|
+
* ⚠️ 不许在任何使用点就地写按钮样式;要多一档外观 ⇒ 改基础层(一处改全站生效)。
|
|
3162
|
+
*/
|
|
3163
|
+
/** 实心档(color 参数按「底色」处理;其余档按「字色 + 描边色」处理)。 */
|
|
3164
|
+
const SOLID_VARIANTS = [
|
|
3165
|
+
"primary",
|
|
3166
|
+
"secondary",
|
|
3167
|
+
"danger",
|
|
3168
|
+
"success",
|
|
3169
|
+
"warning",
|
|
3170
|
+
"info"
|
|
3171
|
+
];
|
|
3172
|
+
/** 把自定义颜色翻译成 5 个局部变量(只覆盖 token,不新增皮肤)。 */
|
|
3173
|
+
function colorVars(variant, color) {
|
|
3174
|
+
if (color === void 0 || color === "") return void 0;
|
|
3175
|
+
if (SOLID_VARIANTS.includes(variant)) return {
|
|
3176
|
+
"--btn-bg": color,
|
|
3177
|
+
"--btn-bg-hover": `color-mix(in srgb, ${color} 82%, var(--dshpc-fg))`,
|
|
3178
|
+
"--btn-bg-active": `color-mix(in srgb, ${color} 70%, var(--dshpc-fg))`
|
|
3179
|
+
};
|
|
3180
|
+
return {
|
|
3181
|
+
"--btn-fg": color,
|
|
3182
|
+
"--btn-fg-hover": color,
|
|
3183
|
+
"--btn-border": color,
|
|
3184
|
+
"--btn-bg-hover": `color-mix(in srgb, ${color} 12%, transparent)`,
|
|
3185
|
+
"--btn-bg-active": `color-mix(in srgb, ${color} 18%, transparent)`
|
|
3186
|
+
};
|
|
3187
|
+
}
|
|
3188
|
+
/** 组装按钮 class(结构一套 + 轴类)。 */
|
|
3189
|
+
function buttonClass(variant, size, block, hasIcon, extra) {
|
|
3190
|
+
return `dshpc-btn dshpc-btn--${variant} dshpc-btn--${size}${block ? " dshpc-btn--block" : ""}${hasIcon ? " dshpc-btn--icon-start" : ""}${extra !== void 0 && extra !== "" ? ` ${extra}` : ""}`;
|
|
3191
|
+
}
|
|
3192
|
+
/**
|
|
3193
|
+
* 渲染一个「图标 + 文案」按钮。
|
|
3194
|
+
*
|
|
3195
|
+
* @param props 见 {@link ButtonProps}。
|
|
3196
|
+
* @returns 按钮元素。
|
|
3197
|
+
*/
|
|
3198
|
+
function Button$1(props) {
|
|
3199
|
+
ensureControls();
|
|
3200
|
+
const { variant = "outline", size = "lg", icon, iconRight, color, loading = false, block = false, className, style, children, ...rest } = props;
|
|
3201
|
+
const attrs = {
|
|
3202
|
+
...rest,
|
|
3203
|
+
type: rest.type ?? "button",
|
|
3204
|
+
disabled: rest.disabled === true || loading,
|
|
3205
|
+
className: buttonClass(variant, size, block, icon !== void 0 && icon !== null && !loading, className),
|
|
3206
|
+
style: {
|
|
3207
|
+
...colorVars(variant, color),
|
|
3208
|
+
...style
|
|
3209
|
+
}
|
|
3210
|
+
};
|
|
3211
|
+
return (0, react.createElement)("button", attrs, loading ? (0, react.createElement)("svg", {
|
|
3212
|
+
className: "dshpc-btn__spinner",
|
|
3213
|
+
viewBox: "0 0 12 12",
|
|
3214
|
+
width: 12,
|
|
3215
|
+
height: 12,
|
|
3216
|
+
"aria-hidden": true
|
|
3217
|
+
}, (0, react.createElement)("circle", {
|
|
3218
|
+
cx: 6,
|
|
3219
|
+
cy: 6,
|
|
3220
|
+
r: 4.75,
|
|
3221
|
+
fill: "none",
|
|
3222
|
+
stroke: "currentColor",
|
|
3223
|
+
strokeWidth: 1.5,
|
|
3224
|
+
strokeLinecap: "round",
|
|
3225
|
+
strokeDasharray: "22 30"
|
|
3226
|
+
})) : icon !== void 0 && icon !== null ? (0, react.createElement)("span", { className: "dshpc-btn__icon" }, icon) : null, children, iconRight !== void 0 && iconRight !== null ? (0, react.createElement)("span", { className: "dshpc-btn__icon-end" }, iconRight) : null);
|
|
3227
|
+
}
|
|
3228
|
+
/**
|
|
3229
|
+
* 渲染一个纯图标按钮。
|
|
3230
|
+
*
|
|
3231
|
+
* @param props 见 {@link IconButtonProps}。
|
|
3232
|
+
* @returns 图标按钮元素。
|
|
3233
|
+
*/
|
|
3234
|
+
function IconButton$1(props) {
|
|
3235
|
+
ensureControls();
|
|
3236
|
+
const { variant = "plain", size = "lg", icon, label, className, style, ...rest } = props;
|
|
3237
|
+
const attrs = {
|
|
3238
|
+
...rest,
|
|
3239
|
+
type: rest.type ?? "button",
|
|
3240
|
+
title: rest.title ?? label,
|
|
3241
|
+
"aria-label": rest["aria-label"] ?? label,
|
|
3242
|
+
className: `dshpc-iconbtn dshpc-iconbtn--${variant} dshpc-iconbtn--${size}${className !== void 0 && className !== "" ? ` ${className}` : ""}`,
|
|
3243
|
+
style
|
|
3244
|
+
};
|
|
3245
|
+
return (0, react.createElement)("button", attrs, icon);
|
|
3246
|
+
}
|
|
3247
|
+
//#endregion
|
|
3248
|
+
//#region ../../node_modules/.pnpm/dsh-plugin-core@0.5.0_@babel+runtime@8.0.8_@codemirror+autocomplete@6.20.4_@codemirror+_bddbf1bc7ba0e94be71f734653121d0c/node_modules/dsh-plugin-core/dist/ui/Card.js
|
|
3249
|
+
/** 色条档位(映射到 design 的 token,不新增 token;也接受任意 CSS 颜色值)。 */
|
|
3250
|
+
const CARD_ACCENTS = [
|
|
3251
|
+
"business",
|
|
3252
|
+
"success",
|
|
3253
|
+
"warning",
|
|
3254
|
+
"danger",
|
|
3255
|
+
"neutral"
|
|
3256
|
+
];
|
|
3257
|
+
/**
|
|
3258
|
+
* 内部共享壳:两个公开组件(`Card` / `StripCard`)只是 `kind` 不同——
|
|
3259
|
+
* 一个组件一种外观,import 即表明用的是哪种。
|
|
3260
|
+
*
|
|
3261
|
+
* 两种外观的头部都是**整体垂直居中**(`align-items:center`):调用方在 `action` 里
|
|
3262
|
+
* 裸放一个元素(按钮 / 文字 / 图标)即垂直居中,不用自己套容器;框内一行两行、
|
|
3263
|
+
* 右侧放什么、悬停浮出的按钮,都由调用方在框内自定——外壳只提供框与居中。
|
|
3264
|
+
*/
|
|
3265
|
+
function CardShell(kind, props) {
|
|
3266
|
+
ensureControls();
|
|
3267
|
+
const tt = props.translate ?? t$1;
|
|
3268
|
+
const accent = props.accent ?? "business";
|
|
3269
|
+
const isPreset = CARD_ACCENTS.includes(accent);
|
|
3270
|
+
const classes = [
|
|
3271
|
+
"dshpc-card",
|
|
3272
|
+
kind === "strip" ? "dshpc-card--strip" : "dshpc-card--bordered",
|
|
3273
|
+
isPreset ? `dshpc-card--${accent}` : "",
|
|
3274
|
+
props.className ?? ""
|
|
3275
|
+
].filter((s) => s !== "").join(" ");
|
|
3276
|
+
const style = isPreset ? props.style : {
|
|
3277
|
+
...props.style,
|
|
3278
|
+
["--card-accent"]: accent
|
|
3279
|
+
};
|
|
3280
|
+
return (0, react.createElement)("div", {
|
|
3281
|
+
className: classes,
|
|
3282
|
+
style
|
|
3283
|
+
}, (0, react.createElement)("div", { className: "dshpc-card__head" }, (0, react.createElement)("span", {
|
|
3284
|
+
className: "dshpc-card__bar",
|
|
3285
|
+
"aria-hidden": true
|
|
3286
|
+
}), (0, react.createElement)("div", { className: "dshpc-card__main" }, props.children ?? null), props.action === void 0 && props.onToggle === void 0 ? null : (0, react.createElement)("div", { className: "dshpc-card__side" }, props.action ?? null, props.onToggle === void 0 ? null : (0, react.createElement)("button", {
|
|
3287
|
+
type: "button",
|
|
3288
|
+
className: "dshpc-card__toggle",
|
|
3289
|
+
"aria-label": tt("cardToggle"),
|
|
3290
|
+
"aria-expanded": props.expanded === true,
|
|
3291
|
+
onClick: props.onToggle
|
|
3292
|
+
}, (0, react.createElement)("span", { className: props.expanded === true ? "dshpc-card__caret is-open" : "dshpc-card__caret" }, "▾")))), props.panel === void 0 || props.expanded !== true ? null : (0, react.createElement)("div", { className: "dshpc-card__panel" }, props.panel));
|
|
3293
|
+
}
|
|
3294
|
+
/**
|
|
3295
|
+
* 条带卡片(浅底式):同色系浅底 + 1px 不可见占位边框 + 方角 + 左缘 4px 通高方角色条(贴左缘)。
|
|
3296
|
+
* 与 `Card` 同一份 props,头部同样整体垂直居中。
|
|
3297
|
+
*
|
|
3298
|
+
* ```tsx
|
|
3299
|
+
* h(StripCard, {
|
|
3300
|
+
* accent: 'success',
|
|
3301
|
+
* expanded: open, onToggle: () => setOpen(!open),
|
|
3302
|
+
* panel: h('div', null, '展开详情'),
|
|
3303
|
+
* }, h('div', null, '标题 + 元信息'))
|
|
3304
|
+
* ```
|
|
3305
|
+
*/
|
|
3306
|
+
function StripCard(props) {
|
|
3307
|
+
return CardShell("strip", props);
|
|
3308
|
+
}
|
|
3309
|
+
//#endregion
|
|
3310
|
+
//#region ../../node_modules/.pnpm/dsh-plugin-core@0.5.0_@babel+runtime@8.0.8_@codemirror+autocomplete@6.20.4_@codemirror+_bddbf1bc7ba0e94be71f734653121d0c/node_modules/dsh-plugin-core/dist/ui/Chip.js
|
|
3311
|
+
/** 小标签(neutral 用现成的 `--dshpc-chip-bg`;传 `onClick` 才是可点的)。 */
|
|
3312
|
+
function Chip(props) {
|
|
3313
|
+
ensureControls();
|
|
3314
|
+
const clickable = props.onClick !== void 0;
|
|
3315
|
+
const tone = props.tone ?? "neutral";
|
|
3316
|
+
const size = props.size ?? "sm";
|
|
3317
|
+
return (0, react.createElement)(clickable ? "button" : "span", {
|
|
3318
|
+
type: clickable ? "button" : void 0,
|
|
3319
|
+
className: `dshpc-chip${tone !== "neutral" ? ` dshpc-chip--${tone}` : ""}${size !== "sm" ? ` dshpc-chip--${size}` : ""}${clickable ? " dshpc-chip--clickable" : ""}${props.className === void 0 ? "" : ` ${props.className}`}`,
|
|
3320
|
+
onClick: props.onClick
|
|
3321
|
+
}, props.children ?? null);
|
|
3322
|
+
}
|
|
3323
|
+
//#endregion
|
|
3324
|
+
//#region ../../node_modules/.pnpm/dsh-plugin-core@0.5.0_@babel+runtime@8.0.8_@codemirror+autocomplete@6.20.4_@codemirror+_bddbf1bc7ba0e94be71f734653121d0c/node_modules/dsh-plugin-core/dist/ui/Segmented.js
|
|
3325
|
+
/**
|
|
3326
|
+
* 分段控件(滑动块)—— **全站唯一实现**(L2 组件皮肤,P1)
|
|
3327
|
+
*
|
|
3328
|
+
* 它是「同一份结构 + 两个受控轴」的样板:
|
|
3329
|
+
* - `size`:`sm`(24) / `md`(28) / `lg`(32) —— **离散三档**,调用点**不许**自己写高度
|
|
3330
|
+
* (真不够用才允许在调用点本地覆盖 `--dshpc-control-h-*`,属例外而非常态);
|
|
3331
|
+
* - `bordered`(默认 false):最外再包一圈 1px 描边;总高与无框版逐像素一致
|
|
3332
|
+
* (border 由 padding 抵消),两种模式整行混排不跳高。
|
|
3333
|
+
*
|
|
3334
|
+
* 外观只有一套(灰底轨道 + 白色选中片,阴影来自宿主 elevation token)。
|
|
3335
|
+
* 2026-10-26 删掉 `variant` 轴(原 default / inset 两档在 CSS 里只差 1px 内距,
|
|
3336
|
+
* 且 default 比 `size` 承诺矮 2px,下游照 demo 对图时反复查不出原因 —— 见 docs/design/style.md)。
|
|
3337
|
+
*
|
|
3338
|
+
* 用法:
|
|
3339
|
+
* // 单选
|
|
3340
|
+
* h(Segmented<'a' | 'b'>, { value: v, size: 'md', items: [{ value: 'a', label: '甲' }], onChange: setV })
|
|
3341
|
+
* // 多选(如星期)
|
|
3342
|
+
* h(Segmented<'1' | '2'>, { multiple: true, value: vs, items: [...], onChange: setVs })
|
|
3343
|
+
*
|
|
3344
|
+
* ⚠️ 不许在任何使用点就地写分段样式;要多一档高度 / 多一个外观 ⇒ 走
|
|
3345
|
+
* docs/design/ui-style-guide.md §五 的流程(改基础层,一处改全站生效)。
|
|
3346
|
+
*/
|
|
3347
|
+
/**
|
|
3348
|
+
* 渲染一个分段控件(单选 / 多选同体)。
|
|
3349
|
+
*
|
|
3350
|
+
* @param props 见 {@link SegmentedProps}。
|
|
3351
|
+
* @returns 分段控件元素。
|
|
3352
|
+
*/
|
|
3353
|
+
function Segmented$1(props) {
|
|
3354
|
+
ensureControls();
|
|
3355
|
+
ensureControls();
|
|
3356
|
+
const size = props.size ?? "lg";
|
|
3357
|
+
const multiple = props.multiple === true;
|
|
3358
|
+
const value = props.value;
|
|
3359
|
+
const onChange = props.onChange;
|
|
3360
|
+
const sliding = !multiple && props.items.length > 1;
|
|
3361
|
+
const rootRef = (0, react.useRef)(null);
|
|
3362
|
+
const [thumb, setThumb] = (0, react.useState)(null);
|
|
3363
|
+
const measure = (0, react.useCallback)(() => {
|
|
3364
|
+
const sel = rootRef.current?.querySelector(".dshpc-seg__item[aria-pressed=\"true\"]");
|
|
3365
|
+
if (sel === void 0 || sel === null) {
|
|
3366
|
+
setThumb(null);
|
|
3367
|
+
return;
|
|
3368
|
+
}
|
|
3369
|
+
const next = {
|
|
3370
|
+
left: sel.offsetLeft,
|
|
3371
|
+
top: sel.offsetTop,
|
|
3372
|
+
width: sel.offsetWidth,
|
|
3373
|
+
height: sel.offsetHeight
|
|
3374
|
+
};
|
|
3375
|
+
setThumb((cur) => cur !== null && cur.left === next.left && cur.top === next.top && cur.width === next.width && cur.height === next.height ? cur : next);
|
|
3376
|
+
}, []);
|
|
3377
|
+
(0, react.useLayoutEffect)(() => {
|
|
3378
|
+
if (!sliding) {
|
|
3379
|
+
setThumb(null);
|
|
3380
|
+
return;
|
|
3381
|
+
}
|
|
3382
|
+
measure();
|
|
3383
|
+
const root = rootRef.current;
|
|
3384
|
+
if (root === null || typeof ResizeObserver === "undefined") return;
|
|
3385
|
+
const ro = new ResizeObserver(measure);
|
|
3386
|
+
ro.observe(root);
|
|
3387
|
+
return () => ro.disconnect();
|
|
3388
|
+
}, [
|
|
3389
|
+
sliding,
|
|
3390
|
+
measure,
|
|
3391
|
+
value,
|
|
3392
|
+
size,
|
|
3393
|
+
props.items,
|
|
3394
|
+
props.bordered,
|
|
3395
|
+
props.block
|
|
3396
|
+
]);
|
|
3397
|
+
return (0, react.createElement)("div", {
|
|
3398
|
+
role: "group",
|
|
3399
|
+
"aria-label": props.label,
|
|
3400
|
+
id: props.id,
|
|
3401
|
+
ref: rootRef,
|
|
3402
|
+
className: `dshpc-seg dshpc-seg--${size}${sliding ? " dshpc-seg--slide" : ""}${props.block === true ? " dshpc-seg--block" : ""}${props.bordered === true ? " dshpc-seg--bordered" : ""}${props.className !== void 0 ? ` ${props.className}` : ""}`,
|
|
3403
|
+
style: props.style
|
|
3404
|
+
}, [sliding && thumb !== null ? (0, react.createElement)("span", {
|
|
3405
|
+
key: "__thumb__",
|
|
3406
|
+
className: "dshpc-seg__thumb",
|
|
3407
|
+
"aria-hidden": true,
|
|
3408
|
+
style: {
|
|
3409
|
+
left: `${String(thumb.left)}px`,
|
|
3410
|
+
top: `${String(thumb.top)}px`,
|
|
3411
|
+
width: `${String(thumb.width)}px`,
|
|
3412
|
+
height: `${String(thumb.height)}px`
|
|
3413
|
+
}
|
|
3414
|
+
}) : null, ...props.items.map((item) => {
|
|
3415
|
+
const on = multiple ? value.includes(item.value) : value === item.value;
|
|
3416
|
+
const disabled = item.disabled === true || props.disabled === true;
|
|
3417
|
+
const handle = () => {
|
|
3418
|
+
if (disabled) return;
|
|
3419
|
+
if (multiple) {
|
|
3420
|
+
const arr = value;
|
|
3421
|
+
const next = arr.includes(item.value) ? arr.filter((v) => v !== item.value) : [...arr, item.value];
|
|
3422
|
+
onChange(next);
|
|
3423
|
+
} else onChange(item.value);
|
|
3424
|
+
};
|
|
3425
|
+
const itemButton = (0, react.createElement)("button", {
|
|
3426
|
+
key: item.value,
|
|
3427
|
+
type: "button",
|
|
3428
|
+
className: "dshpc-seg__item",
|
|
3429
|
+
"aria-pressed": on,
|
|
3430
|
+
disabled,
|
|
3431
|
+
onClick: handle
|
|
3432
|
+
}, item.label, item.count !== void 0 && item.count > 0 ? (0, react.createElement)("span", { className: "dshpc-seg__count" }, String(item.count)) : null, item.badge !== void 0 && item.badge > 0 ? (0, react.createElement)("span", { className: "dshpc-seg__badge" }, String(item.badge)) : null);
|
|
3433
|
+
if (item.tooltip !== void 0 && false);
|
|
3434
|
+
return itemButton;
|
|
3435
|
+
})]);
|
|
3436
|
+
}
|
|
3437
|
+
//#endregion
|
|
3438
|
+
//#region ../../node_modules/.pnpm/dsh-plugin-core@0.5.0_@babel+runtime@8.0.8_@codemirror+autocomplete@6.20.4_@codemirror+_bddbf1bc7ba0e94be71f734653121d0c/node_modules/dsh-plugin-core/dist/ui/Field.js
|
|
3439
|
+
/**
|
|
3440
|
+
* 输入类控件 —— **全站唯一实现**(L2 组件皮肤,P3)
|
|
3441
|
+
*
|
|
3442
|
+
* - `Input`:文本输入(size sm 24 / md 28 / lg 32,error 描红);
|
|
3443
|
+
* - `PrefixedInput`:前缀 + 文本输入(如路径 / 接口前缀);
|
|
3444
|
+
* - `NumberInput`:数字步进(显式 `− / +`,替换原生 `<input type="number">` 的浏览器 spinner,
|
|
3445
|
+
* 支持 step / min / max、clamp、Enter 提交、失焦回弹)。
|
|
3446
|
+
*
|
|
3447
|
+
* 高度一律吃 `--dshpc-control-h-*`;有边 / 无边同高(边框在内部补回)。
|
|
3448
|
+
*/
|
|
3449
|
+
/**
|
|
3450
|
+
* 字段 hint 的统一包法:控件 + 问号提示同一行(间距/对齐收进组件,调用方传个
|
|
3451
|
+
* `hint` 字符串就行,不再手动拼排版 —— 用户 2026-10-20 拍板)。
|
|
3452
|
+
*/
|
|
3453
|
+
function withHint(control, hint) {
|
|
3454
|
+
if (hint === void 0) return control;
|
|
3455
|
+
return (0, react.createElement)("span", { className: "dshpc-fieldwrap" }, control, (0, react.createElement)(FieldHint, { text: hint }));
|
|
3456
|
+
}
|
|
3457
|
+
function sizeClass(size) {
|
|
3458
|
+
return size === "lg" ? "--lg" : size === "md" ? "--md" : "--sm";
|
|
3459
|
+
}
|
|
3460
|
+
/** 文本输入。默认铺满容器(width:100%,与 Textarea 同口径);要定宽由调用方在外面包壳(如 192px 搜索槽)。 */
|
|
3461
|
+
function Input(props) {
|
|
3462
|
+
ensureControls();
|
|
3463
|
+
const { value, onChange, placeholder, size = "lg", error, disabled, type, className, style } = props;
|
|
3464
|
+
return withHint((0, react.createElement)("input", {
|
|
3465
|
+
ref: props.inputRef,
|
|
3466
|
+
type: type ?? "text",
|
|
3467
|
+
value,
|
|
3468
|
+
placeholder,
|
|
3469
|
+
disabled,
|
|
3470
|
+
"aria-label": props["aria-label"],
|
|
3471
|
+
title: props.title,
|
|
3472
|
+
className: `dshpc-input dshpc-input${sizeClass(size)}${error === true ? " dshpc-input--error" : ""}${className !== void 0 && className !== "" ? ` ${className}` : ""}`,
|
|
3473
|
+
style,
|
|
3474
|
+
onChange: (event) => {
|
|
3475
|
+
onChange(event.target.value);
|
|
3476
|
+
},
|
|
3477
|
+
onKeyDown: props.onKeyDown,
|
|
3478
|
+
onBlur: props.onBlur
|
|
3479
|
+
}), props.hint);
|
|
3480
|
+
}
|
|
3481
|
+
//#endregion
|
|
9
3482
|
//#region src/client/rows.ts
|
|
10
3483
|
/**
|
|
11
3484
|
* 界面上显示人名的**唯一**口径:显示名(`owner_name` / `creator_name`)优先,
|
|
@@ -402,8 +3875,6 @@ body{
|
|
|
402
3875
|
--dtl-business-soft:color-mix(in srgb,var(--dtl-business) 14%,transparent);
|
|
403
3876
|
/* 他人任务的 doing 色:比「我的」蓝灰一档(用户 2026-10-17:要和我的蓝区分) */
|
|
404
3877
|
--dtl-business-dim:color-mix(in srgb,var(--dtl-business) 55%,var(--dtl-fg-3));
|
|
405
|
-
/* 组标题底:左深蓝竖条后面的那层**浅蓝**(用户 2026-10-18 照参考图) */
|
|
406
|
-
--dtl-group-head-bg:#eaf1ff;
|
|
407
3878
|
--dtl-success-soft:color-mix(in srgb,var(--dtl-success) 8%,transparent);
|
|
408
3879
|
--dtl-warning-soft:color-mix(in srgb,var(--dtl-warning) 8%,transparent);
|
|
409
3880
|
--dtl-danger-soft:color-mix(in srgb,var(--dtl-danger) 8%,transparent);
|
|
@@ -490,8 +3961,6 @@ body[data-ds-dark-theme]{
|
|
|
490
3961
|
/* 语义色浅底在深色下压到 5%(8% 在深底上偏重) */
|
|
491
3962
|
--dtl-business-soft:color-mix(in srgb,var(--dtl-business) 12%,transparent);
|
|
492
3963
|
--dtl-business-dim:color-mix(in srgb,var(--dtl-business) 55%,var(--dtl-fg-3));
|
|
493
|
-
/* 组标题底(暗):**实色**蓝(参考图不是半透明叠加出来的) */
|
|
494
|
-
--dtl-group-head-bg:#1e3a5f;
|
|
495
3964
|
--dtl-success-soft:color-mix(in srgb,var(--dtl-success) 5%,transparent);
|
|
496
3965
|
--dtl-warning-soft:color-mix(in srgb,var(--dtl-warning) 5%,transparent);
|
|
497
3966
|
--dtl-danger-soft:color-mix(in srgb,var(--dtl-danger) 5%,transparent);
|
|
@@ -503,27 +3972,8 @@ body[data-ds-dark-theme]{
|
|
|
503
3972
|
* 高度只取三档,有边框的变体用 1px 真边框 + 内部 padding 补回 ⇒ 有边 / 无边同高。
|
|
504
3973
|
*/
|
|
505
3974
|
const UI_CONTROLS_CSS = `
|
|
506
|
-
/* ──
|
|
507
|
-
|
|
508
|
-
变体只覆盖两个颜色变量(--seg-track / --seg-thumb),结构 / 尺寸 / 交互零重复。 */
|
|
509
|
-
.dtl-seg{display:inline-flex;align-items:center;gap:2px;padding:2px;border-radius:var(--dtl-radius-md);background:var(--seg-track);}
|
|
510
|
-
.dtl-seg--default{--seg-track:var(--dtl-surface-2);--seg-thumb:var(--dtl-surface-raised);border:1px solid var(--dtl-border);}
|
|
511
|
-
.dtl-seg--inset{--seg-track:var(--dtl-hover);--seg-thumb:var(--dtl-surface-raised);border:0;padding:3px;}
|
|
512
|
-
.dtl-seg__item{appearance:none;display:inline-flex;align-items:center;gap:4px;box-sizing:border-box;
|
|
513
|
-
height:calc(var(--dtl-control-h-sm) - 6px);padding:0 12px;border:0;border-radius:var(--dtl-radius-sm);
|
|
514
|
-
background:transparent;color:var(--dtl-fg-2);font-family:inherit;font-size:var(--dtl-font-sm);line-height:var(--dtl-line-sm);
|
|
515
|
-
font-weight:400;white-space:nowrap;cursor:pointer;
|
|
516
|
-
transition:color var(--dtl-dur-fast) var(--dtl-ease),background-color var(--dtl-dur-fast) var(--dtl-ease),box-shadow var(--dtl-dur-fast) var(--dtl-ease);}
|
|
517
|
-
.dtl-seg--md .dtl-seg__item{height:calc(var(--dtl-control-h-md) - 6px);}
|
|
518
|
-
.dtl-seg--lg .dtl-seg__item{height:calc(var(--dtl-control-h-lg) - 6px);}
|
|
519
|
-
.dtl-seg__item:hover:not([aria-pressed='true']):not(:disabled){color:var(--dtl-fg);}
|
|
520
|
-
.dtl-seg__item[aria-pressed='true']{background:var(--seg-thumb);box-shadow:var(--dtl-shadow-raised);color:var(--dtl-fg);font-weight:600;}
|
|
521
|
-
.dtl-seg__item:focus-visible{outline:2px solid var(--dtl-business);outline-offset:-2px;}
|
|
522
|
-
.dtl-seg__item:disabled{cursor:default;opacity:.4;}
|
|
523
|
-
/* 段内计数(如「待认领 3」):**纯文字,无底、无边、无圆角**(用户 2026-10-18:圆圈取了、字再小点)。
|
|
524
|
-
类名用 num 而不是旧 badge —— 万一宿主 DOM 里残留旧版 .dtl-seg__badge 圆圈规则,也匹配不中;0 不渲染 */
|
|
525
|
-
.dtl-seg__num{display:inline;flex:none;margin-left:3px;padding:0;border:0;border-radius:0;
|
|
526
|
-
background:none;color:var(--dtl-fg-3);font-size:10px;line-height:1;font-weight:400;font-variant-numeric:tabular-nums;}
|
|
3975
|
+
/* ── 分段控件(滑动块):已改由核心 Segmented 承担,外观 / 尺寸 / 滑块动画全部在 core,
|
|
3976
|
+
本文件不再写任何分段控件样式(core 0.5.0 起删掉 variant 轴,外观只有一套)。── */
|
|
527
3977
|
|
|
528
3978
|
/* ── 按钮 / 图标钮 ───────────────────────────────────────────────
|
|
529
3979
|
与 Segmented 同一条高度纪律;variant 只换颜色,结构 / 尺寸 / 交互只此一份。 */
|
|
@@ -634,21 +4084,7 @@ body[data-ds-dark-theme]{
|
|
|
634
4084
|
文字加粗放大;表体照旧(行下一条线 + 极浅斑马纹)。 */
|
|
635
4085
|
/* 组与组**零外距**、连体(用户 2026-10-18:上间距去掉,和上面连在一起) */
|
|
636
4086
|
.dtl-group{margin-bottom:0;}
|
|
637
|
-
/*
|
|
638
|
-
工作区名稍小一号(14px);上缘无边 */
|
|
639
|
-
.dtl-group__head{position:relative;display:flex;align-items:center;gap:8px;width:100%;box-sizing:border-box;
|
|
640
|
-
padding:10px var(--dtl-space-3);border:0;border-left:5px solid var(--dtl-business);
|
|
641
|
-
border-radius:0;background:var(--dtl-group-head-bg);
|
|
642
|
-
color:inherit;font:inherit;text-align:left;cursor:pointer;}
|
|
643
|
-
/* 下缘那条线**绝不用 border 画**:border-left(5px) 与 border-bottom(1px) 在左下角
|
|
644
|
-
按 miter 斜接,会切出一个斜缺角(用户 2026-10-18 实锤,不是视觉误差)⇒ 改用伪元素
|
|
645
|
-
独立 1px;定位基于 padding box ⇒ 自动从竖条内缘起笔,竖条保持整直。 */
|
|
646
|
-
.dtl-group__head::after{content:'';position:absolute;left:0;right:0;bottom:0;height:1px;
|
|
647
|
-
background:var(--dtl-border-faint);pointer-events:none;}
|
|
648
|
-
.dtl-group__name{font-size:var(--dtl-font-lg);font-weight:700;line-height:var(--dtl-line-lg);color:var(--dtl-fg);}
|
|
649
|
-
.dtl-group__stats{font-size:var(--dtl-font-xs);color:var(--dtl-fg-2);white-space:nowrap;}
|
|
650
|
-
/* 组标题标识:官方文件夹图标(展开=开、收起=合);图标缺席时回落成竖线 */
|
|
651
|
-
.dtl-group__bar{width:3px;height:14px;flex:none;border-radius:2px;background:var(--dtl-business);}
|
|
4087
|
+
/* 组标题(段头统计条):改由核心 StripCard 承担(色条 / 底色 / 折叠 caret 全在 core) */
|
|
652
4088
|
/* 表格行(.dtl-orow):**零重用**「我的待办」卡片基类——无框、无圆角、无外边距,
|
|
653
4089
|
一行 = 一条底部分隔线 + 极浅斑马纹(用户 2026-10-18:一行一格,不是一块一块的框) */
|
|
654
4090
|
.dtl-orow{padding:13px var(--dtl-space-3);border-bottom:1px solid var(--dtl-border-faint);}
|
|
@@ -747,6 +4183,8 @@ body[data-ds-dark-theme]{
|
|
|
747
4183
|
.dtl-tag--stale{background:var(--dtl-danger);color:var(--dtl-on-signal);font-weight:600;}
|
|
748
4184
|
/* 执行人:浅蓝底(与状态色区分:状态是「事怎么样」,人是「谁在做」) */
|
|
749
4185
|
.dtl-tag--person{background:var(--dtl-open-bg-soft);color:var(--dtl-fg-2);}
|
|
4186
|
+
/* 用核心 Chip 承担标签时的截断(core Chip 无 max-width/省略号 ⇒ 这里只补布局,不改皮肤) */
|
|
4187
|
+
.dshpc-chip.dtl-tagchip{display:inline-block;flex:none;max-width:20ch;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;vertical-align:middle;}
|
|
750
4188
|
/* 分区标题里的计数:与日期徽同款中括号小字(用户 2026-10-17);0 条不渲染 */
|
|
751
4189
|
.dtl-count{font-size:var(--dtl-font-xs);color:var(--dtl-fg-3);font-variant-numeric:tabular-nums;}
|
|
752
4190
|
|
|
@@ -848,70 +4286,74 @@ body[data-ds-dark-theme]{
|
|
|
848
4286
|
style.textContent = css;
|
|
849
4287
|
document.head.appendChild(style);
|
|
850
4288
|
}
|
|
851
|
-
/**
|
|
4289
|
+
/** 分段控件(单选):改由核心 `Segmented` 承担(size/滑块动画全在 core,外观只有一套、无需指定变体,
|
|
4290
|
+
* 见 core/src/ui/Segmented.ts 头注:2026-10-26 起已删除 variant 轴)。
|
|
4291
|
+
* 本地 `badge` 是「灰字计数」语义 ⇒ 映射到 core 的 `count`(core 的 `badge` 是红色危险圆标)。 */
|
|
852
4292
|
function Segmented(props) {
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
4293
|
+
return (0, react.createElement)(Segmented$1, {
|
|
4294
|
+
items: props.items.map((item) => ({
|
|
4295
|
+
value: item.value,
|
|
4296
|
+
label: item.label,
|
|
4297
|
+
count: item.badge
|
|
4298
|
+
})),
|
|
4299
|
+
value: props.value,
|
|
4300
|
+
onChange: props.onChange,
|
|
4301
|
+
size: props.size,
|
|
4302
|
+
label: props.label,
|
|
859
4303
|
id: props.id,
|
|
860
|
-
className: `dtl-seg dtl-seg--${variant} dtl-seg--${size}`,
|
|
861
4304
|
style: props.style
|
|
862
|
-
}
|
|
863
|
-
key: item.value,
|
|
864
|
-
type: "button",
|
|
865
|
-
className: "dtl-seg__item",
|
|
866
|
-
"aria-pressed": item.value === props.value,
|
|
867
|
-
onClick: () => {
|
|
868
|
-
props.onChange(item.value);
|
|
869
|
-
}
|
|
870
|
-
}, item.label, item.badge !== void 0 && item.badge > 0 ? (0, react.createElement)("span", { className: "dtl-seg__num" }, String(item.badge)) : null)));
|
|
4305
|
+
});
|
|
871
4306
|
}
|
|
4307
|
+
/** 按钮:改由核心 `Button` 承担(10 档 variant 里本地用 3 档)。本地默认高度 md(core 默认 lg)。 */
|
|
872
4308
|
function Button(props) {
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
disabled: props.disabled
|
|
4309
|
+
return (0, react.createElement)(Button$1, {
|
|
4310
|
+
variant: props.variant,
|
|
4311
|
+
size: props.size ?? "md",
|
|
4312
|
+
icon: props.icon,
|
|
4313
|
+
disabled: props.disabled,
|
|
878
4314
|
title: props.title,
|
|
879
4315
|
onClick: props.onClick
|
|
880
|
-
}, props.
|
|
4316
|
+
}, props.children);
|
|
881
4317
|
}
|
|
882
|
-
/**
|
|
883
|
-
|
|
4318
|
+
/** 图标钮:改由核心 `IconButton` 承担。 */
|
|
4319
|
+
function IconButton(props) {
|
|
4320
|
+
return (0, react.createElement)(IconButton$1, {
|
|
4321
|
+
icon: props.icon,
|
|
4322
|
+
label: props.label,
|
|
4323
|
+
onClick: props.onClick,
|
|
4324
|
+
variant: props.variant ?? "plain",
|
|
4325
|
+
size: props.size ?? "md",
|
|
4326
|
+
disabled: props.disabled,
|
|
4327
|
+
title: props.title
|
|
4328
|
+
});
|
|
4329
|
+
}
|
|
4330
|
+
/** 下拉:改由核心 `Picker`(单选、受控、portal 菜单)承担。
|
|
4331
|
+
* 本地 `width`/`minWidth` 核心件暂不支持(`PickerProps` 无 style/width),由外层布局决定宽度。 */
|
|
884
4332
|
function Select(props) {
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
"aria-label": props.ariaLabel,
|
|
891
|
-
style,
|
|
4333
|
+
return (0, react.createElement)(Picker, {
|
|
4334
|
+
options: props.options.map((option) => ({
|
|
4335
|
+
value: option.value,
|
|
4336
|
+
label: option.label
|
|
4337
|
+
})),
|
|
892
4338
|
value: props.value,
|
|
893
|
-
onChange: (
|
|
894
|
-
props.onChange(
|
|
895
|
-
}
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
4339
|
+
onChange: (next) => {
|
|
4340
|
+
props.onChange(next);
|
|
4341
|
+
},
|
|
4342
|
+
size: props.size ?? "md",
|
|
4343
|
+
searchable: props.searchable === true,
|
|
4344
|
+
ariaLabel: props.ariaLabel,
|
|
4345
|
+
mode: "single"
|
|
4346
|
+
});
|
|
900
4347
|
}
|
|
901
|
-
/**
|
|
4348
|
+
/** 搜索框:改由核心 `Input`(type=search)承担;默认铺满容器。 */
|
|
902
4349
|
function SearchInput(props) {
|
|
903
|
-
|
|
904
|
-
const size = props.size ?? "md";
|
|
905
|
-
return (0, react.createElement)("input", {
|
|
906
|
-
className: `dtl-input dtl-input--${size}`,
|
|
4350
|
+
return (0, react.createElement)(Input, {
|
|
907
4351
|
type: "search",
|
|
908
|
-
"aria-label": props.ariaLabel,
|
|
909
|
-
placeholder: props.placeholder,
|
|
910
4352
|
value: props.value,
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
4353
|
+
onChange: props.onChange,
|
|
4354
|
+
placeholder: props.placeholder,
|
|
4355
|
+
size: props.size ?? "md",
|
|
4356
|
+
"aria-label": props.ariaLabel
|
|
915
4357
|
});
|
|
916
4358
|
}
|
|
917
4359
|
/** 统计卡:主数字 + 灰色口径小字;点一下联动下方列表筛选。
|
|
@@ -941,24 +4383,37 @@ body[data-ds-dark-theme]{
|
|
|
941
4383
|
for (const char of text) width += (char.codePointAt(0) ?? 0) > 11904 ? 2 : 1;
|
|
942
4384
|
return width;
|
|
943
4385
|
}
|
|
4386
|
+
/** 本地 7 档语义色 → 核心 `Chip` 5 档。core 缺 doing / backlog / overdue / stale / person 的独立色:
|
|
4387
|
+
* overdue 与 stale 都落到 danger、doing 与 person 落到 business(需 core 补 tone 才能精确)。 */
|
|
4388
|
+
const CHIP_TONE = {
|
|
4389
|
+
neutral: "neutral",
|
|
4390
|
+
open: "neutral",
|
|
4391
|
+
backlog: "warning",
|
|
4392
|
+
doing: "business",
|
|
4393
|
+
overdue: "danger",
|
|
4394
|
+
stale: "danger",
|
|
4395
|
+
person: "business"
|
|
4396
|
+
};
|
|
944
4397
|
/**
|
|
945
|
-
*
|
|
946
|
-
* 超过 20 个字符宽 ⇒
|
|
947
|
-
* 不跑马灯;没被截 ⇒ 悬停无反应)。
|
|
4398
|
+
* 标签:状态 / 执行人 / #标签 都走它,只换 tone(改由核心 `Chip` 承担)。
|
|
4399
|
+
* 超过 20 个字符宽 ⇒ 省略号(`.dtl-tagchip` 补),**且只在被截时**挂悬停提示补出全文。
|
|
948
4400
|
*/
|
|
949
4401
|
function Tag(props) {
|
|
950
4402
|
ensureUiBase();
|
|
951
4403
|
const { text, tone = "neutral", title, tip } = props;
|
|
952
4404
|
const long = displayWidth(text) > TAG_MAX_WIDTH;
|
|
953
4405
|
const label = tip ?? (long ? title ?? text : void 0);
|
|
954
|
-
const
|
|
955
|
-
|
|
4406
|
+
const chip = (0, react.createElement)(Chip, {
|
|
4407
|
+
tone: CHIP_TONE[tone],
|
|
4408
|
+
className: "dtl-tagchip"
|
|
4409
|
+
}, text);
|
|
4410
|
+
if (label === void 0) return chip;
|
|
956
4411
|
return (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Tooltip, {
|
|
957
4412
|
label,
|
|
958
4413
|
side: "bottom",
|
|
959
4414
|
portal: true,
|
|
960
4415
|
maxWidth: 240,
|
|
961
|
-
children:
|
|
4416
|
+
children: chip
|
|
962
4417
|
});
|
|
963
4418
|
}
|
|
964
4419
|
/** 空态:`guide` = 真空引导卡(虚线),`filtered` = 筛选空小字。 */
|
|
@@ -1189,20 +4644,23 @@ body[data-ds-dark-theme]{
|
|
|
1189
4644
|
side: "bottom",
|
|
1190
4645
|
portal: true,
|
|
1191
4646
|
maxWidth: 240,
|
|
1192
|
-
children: (0, react.createElement)(
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
4647
|
+
children: (0, react.createElement)(IconButton, {
|
|
4648
|
+
variant: "plain",
|
|
4649
|
+
size: "sm",
|
|
4650
|
+
label: t("viewDetail"),
|
|
4651
|
+
icon: (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.IconSearchOutlineRegular, { size: 14 })
|
|
4652
|
+
})
|
|
1196
4653
|
});
|
|
1197
4654
|
const tipBtn = (icon, actionKey, tipKey) => (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Tooltip, {
|
|
1198
4655
|
label: t(tipKey),
|
|
1199
4656
|
side: "bottom",
|
|
1200
4657
|
portal: true,
|
|
1201
4658
|
maxWidth: 240,
|
|
1202
|
-
children: (0, react.createElement)(
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
4659
|
+
children: (0, react.createElement)(Button, {
|
|
4660
|
+
variant: "ghost",
|
|
4661
|
+
size: "sm",
|
|
4662
|
+
icon: icon ?? void 0
|
|
4663
|
+
}, t(actionKey))
|
|
1206
4664
|
});
|
|
1207
4665
|
const claimButton = tipBtn((0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.IconDownloadOutlineRegular, { size: 14 }), "actionClaim", "tipClaim");
|
|
1208
4666
|
const resumeButton = tipBtn((0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.IconChevronRightOutlineRegular, { size: 14 }), "actionResume", "tipResume");
|
|
@@ -1301,6 +4759,16 @@ body[data-ds-dark-theme]{
|
|
|
1301
4759
|
fontSize: "var(--dtl-font-xl)",
|
|
1302
4760
|
fontWeight: 600
|
|
1303
4761
|
};
|
|
4762
|
+
/** 标题后的版本 + 构建编码:特别小的字(用户 2026-10-26 要求,一眼确认看到的是不是刚 build 的)。 */
|
|
4763
|
+
const buildTagStyle = {
|
|
4764
|
+
marginLeft: "var(--dtl-space-2)",
|
|
4765
|
+
fontSize: "10px",
|
|
4766
|
+
lineHeight: "1",
|
|
4767
|
+
fontWeight: 400,
|
|
4768
|
+
color: "var(--dtl-fg-dim)",
|
|
4769
|
+
fontVariantNumeric: "tabular-nums",
|
|
4770
|
+
whiteSpace: "nowrap"
|
|
4771
|
+
};
|
|
1304
4772
|
/** 统计区:左 8 块(2 行 × 4 列)+ 右趋势图,参考图同款分栏。
|
|
1305
4773
|
* 列数写死 4 → 2(媒体查询在 ui.ts 的 .dtl-stats / .dtl-stats__cards 里),
|
|
1306
4774
|
* 绝不给 3 列——3 列会排出 3+1 的非对称(用户 2026-10-17:必须上下对称)。 */
|
|
@@ -1394,6 +4862,8 @@ body[data-ds-dark-theme]{
|
|
|
1394
4862
|
t
|
|
1395
4863
|
]);
|
|
1396
4864
|
const chartEmpty = chartWeeks.every((week) => week.done === 0 && week.created === 0 && week.remaining === 0);
|
|
4865
|
+
/** 被 skill 脚本整行跳过的历史行(列数不对 / 时间不合法):图表数字已少算,要写出来。 */
|
|
4866
|
+
const trendWarnings = trend?.warnings ?? [];
|
|
1397
4867
|
return (0, react.createElement)("div", { style: pageStyle }, (0, react.createElement)("div", { style: {
|
|
1398
4868
|
display: "flex",
|
|
1399
4869
|
justifyContent: "center"
|
|
@@ -1411,7 +4881,10 @@ body[data-ds-dark-theme]{
|
|
|
1411
4881
|
variant: "outline",
|
|
1412
4882
|
size: "md",
|
|
1413
4883
|
onClick: onBack
|
|
1414
|
-
}, `← ${t("backToConversation")}`), (0, react.createElement)("div", { style: titleStyle }, t("panelTitle")
|
|
4884
|
+
}, `← ${t("backToConversation")}`), (0, react.createElement)("div", { style: titleStyle }, t("panelTitle"), (0, react.createElement)("span", {
|
|
4885
|
+
style: buildTagStyle,
|
|
4886
|
+
title: `v0.0.97 · 261027-114255-561`
|
|
4887
|
+
}, `v0.0.97 261027-114255-561`))), (0, react.createElement)("div", { style: {
|
|
1415
4888
|
display: "flex",
|
|
1416
4889
|
alignItems: "center",
|
|
1417
4890
|
gap: "var(--dtl-space-2)"
|
|
@@ -1429,7 +4902,7 @@ body[data-ds-dark-theme]{
|
|
|
1429
4902
|
onChange: setTab
|
|
1430
4903
|
}), (0, react.createElement)(Button, {
|
|
1431
4904
|
variant: "outline",
|
|
1432
|
-
size: "
|
|
4905
|
+
size: "lg",
|
|
1433
4906
|
icon: (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.IconRefreshOutlineRegular, { size: 16 }),
|
|
1434
4907
|
disabled: state.refreshing,
|
|
1435
4908
|
title: t("refresh"),
|
|
@@ -1471,7 +4944,13 @@ body[data-ds-dark-theme]{
|
|
|
1471
4944
|
doneLabel: t("chartLegendDone"),
|
|
1472
4945
|
remainingLabel: t("chartLegendRemaining"),
|
|
1473
4946
|
createdLabel: t("chartLegendCreated")
|
|
1474
|
-
})
|
|
4947
|
+
}), trendWarnings.length > 0 ? (0, react.createElement)("div", {
|
|
4948
|
+
style: {
|
|
4949
|
+
...hintStyle,
|
|
4950
|
+
color: "var(--dtl-warning)"
|
|
4951
|
+
},
|
|
4952
|
+
title: trendWarnings.join("\n")
|
|
4953
|
+
}, t("chartWarnings", { n: trendWarnings.length })) : null)), state.status === "loading" && board === null ? null : state.status === "error" && board === null ? (0, react.createElement)("div", { style: {
|
|
1475
4954
|
display: "flex",
|
|
1476
4955
|
alignItems: "center",
|
|
1477
4956
|
gap: "var(--dtl-space-2)"
|
|
@@ -1512,6 +4991,8 @@ body[data-ds-dark-theme]{
|
|
|
1512
4991
|
display: "inline-flex",
|
|
1513
4992
|
flex: "none"
|
|
1514
4993
|
} }, (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.IconChecklistOutlineRegular, { size: 16 })), (0, react.createElement)("span", { style: regionHeadTitleStyle }, t("regionMine")), view.mine.length > 0 ? (0, react.createElement)("span", { className: "dtl-count" }, t("mineCount", { n: view.mine.length })) : null, (0, react.createElement)("span", { style: { flex: "1 1 auto" } }), (0, react.createElement)(Select, {
|
|
4994
|
+
searchable: true,
|
|
4995
|
+
size: "lg",
|
|
1515
4996
|
value: workspaceOptions.some((option) => option.value === state.query.workspace) ? state.query.workspace : "",
|
|
1516
4997
|
options: workspaceOptions,
|
|
1517
4998
|
ariaLabel: t("workspaceLabel"),
|
|
@@ -1523,6 +5004,7 @@ body[data-ds-dark-theme]{
|
|
|
1523
5004
|
width: `${SEARCH_WIDTH}px`,
|
|
1524
5005
|
flex: "none"
|
|
1525
5006
|
} }, (0, react.createElement)(SearchInput, {
|
|
5007
|
+
size: "lg",
|
|
1526
5008
|
value: state.query.keyword,
|
|
1527
5009
|
placeholder: t("searchPlaceholder"),
|
|
1528
5010
|
ariaLabel: t("searchPlaceholder"),
|
|
@@ -1589,6 +5071,7 @@ body[data-ds-dark-theme]{
|
|
|
1589
5071
|
width: `${SEARCH_WIDTH}px`,
|
|
1590
5072
|
flex: "none"
|
|
1591
5073
|
} }, (0, react.createElement)(SearchInput, {
|
|
5074
|
+
size: "lg",
|
|
1592
5075
|
value: state.query.othersKeyword,
|
|
1593
5076
|
placeholder: t("searchPlaceholder"),
|
|
1594
5077
|
ariaLabel: t("searchPlaceholder"),
|
|
@@ -1635,19 +5118,35 @@ body[data-ds-dark-theme]{
|
|
|
1635
5118
|
...group.overdueCount > 0 ? [t("groupOverdue", { n: group.overdueCount })] : [],
|
|
1636
5119
|
...group.staleCount > 0 ? [t("groupStale", { n: group.staleCount })] : []
|
|
1637
5120
|
].join(" | ");
|
|
1638
|
-
return (0, react.createElement)("div", { className: "dtl-group" }, (0, react.createElement)(
|
|
1639
|
-
|
|
1640
|
-
|
|
1641
|
-
|
|
1642
|
-
title: open ? t("collapseAria") : t("expandAria"),
|
|
1643
|
-
onClick: () => {
|
|
5121
|
+
return (0, react.createElement)("div", { className: "dtl-group" }, (0, react.createElement)(StripCard, {
|
|
5122
|
+
accent: "business",
|
|
5123
|
+
expanded: open,
|
|
5124
|
+
onToggle: () => {
|
|
1644
5125
|
setOpen(!open);
|
|
1645
|
-
}
|
|
1646
|
-
|
|
5126
|
+
},
|
|
5127
|
+
action: (0, react.createElement)("span", { style: {
|
|
5128
|
+
fontSize: "var(--dtl-font-xs)",
|
|
5129
|
+
color: "var(--dtl-fg-2)",
|
|
5130
|
+
whiteSpace: "nowrap"
|
|
5131
|
+
} }, stats)
|
|
5132
|
+
}, (0, react.createElement)("div", { style: {
|
|
5133
|
+
display: "flex",
|
|
5134
|
+
alignItems: "center",
|
|
5135
|
+
gap: 8,
|
|
5136
|
+
minWidth: 0
|
|
5137
|
+
} }, _deepseek_ai_dsh_client_ui_primitives.IconFolderOpenRegular === void 0 || _deepseek_ai_dsh_client_ui_primitives.IconFolderCloseRegular === void 0 ? null : (0, react.createElement)("span", { style: {
|
|
1647
5138
|
display: "inline-flex",
|
|
1648
5139
|
flex: "none",
|
|
1649
5140
|
color: "var(--dtl-fg-3)"
|
|
1650
|
-
} }, (0, react.createElement)(open ? _deepseek_ai_dsh_client_ui_primitives.IconFolderOpenRegular : _deepseek_ai_dsh_client_ui_primitives.IconFolderCloseRegular, { size: 14 })), (0, react.createElement)("span", {
|
|
5141
|
+
} }, (0, react.createElement)(open ? _deepseek_ai_dsh_client_ui_primitives.IconFolderOpenRegular : _deepseek_ai_dsh_client_ui_primitives.IconFolderCloseRegular, { size: 14 })), (0, react.createElement)("span", { style: {
|
|
5142
|
+
fontSize: "var(--dtl-font-lg)",
|
|
5143
|
+
fontWeight: 700,
|
|
5144
|
+
lineHeight: "var(--dtl-line-lg)",
|
|
5145
|
+
color: "var(--dtl-fg)",
|
|
5146
|
+
overflow: "hidden",
|
|
5147
|
+
textOverflow: "ellipsis",
|
|
5148
|
+
whiteSpace: "nowrap"
|
|
5149
|
+
} }, group.title))), open ? (0, react.createElement)("div", null, group.rows.map((row) => (0, react.createElement)(TaskRowView, {
|
|
1651
5150
|
key: row.key,
|
|
1652
5151
|
t,
|
|
1653
5152
|
row,
|
|
@@ -1702,6 +5201,7 @@ body[data-ds-dark-theme]{
|
|
|
1702
5201
|
chartScopeAll: "所有",
|
|
1703
5202
|
chartScopeMine: "我的",
|
|
1704
5203
|
chartOnlyMine: "只看我的",
|
|
5204
|
+
chartWarnings: "有 {n} 条历史行格式不对被跳过,上面的数字未计入(悬停看明细)",
|
|
1705
5205
|
chartLegendDone: "完成",
|
|
1706
5206
|
chartLegendCreated: "新增",
|
|
1707
5207
|
chartLegendRemaining: "未结",
|
|
@@ -1827,6 +5327,7 @@ body[data-ds-dark-theme]{
|
|
|
1827
5327
|
chartScopeAll: "All",
|
|
1828
5328
|
chartScopeMine: "Mine",
|
|
1829
5329
|
chartOnlyMine: "Mine only",
|
|
5330
|
+
chartWarnings: "{n} history rows were skipped as malformed and are not counted above (hover for detail)",
|
|
1830
5331
|
chartLegendDone: "Done",
|
|
1831
5332
|
chartLegendCreated: "Created",
|
|
1832
5333
|
chartLegendRemaining: "Outstanding",
|
|
@@ -1932,6 +5433,7 @@ body[data-ds-dark-theme]{
|
|
|
1932
5433
|
* 宿主能力一律**本地结构化声明**,不 import 官方包(rc 接口会无声变);
|
|
1933
5434
|
* `t` 席位由宿主渲染器按注册项的 `locale:` 声明合成进组件 props。
|
|
1934
5435
|
*/
|
|
5436
|
+
setStyleKit(createStyleKit({ id: "dsh-task-ledger" }));
|
|
1935
5437
|
/** 命名空间(settings / locale / 面板 id 同名,便于对应)。 */
|
|
1936
5438
|
/** 模块级 t 席位(侧栏 label 渲染期求值用;绑不上就回落键名,绝不上界面)。 */
|
|
1937
5439
|
let runtimeT = (key) => key;
|