dsh-mpkg-wallpaper 3.16.1 → 3.16.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/client.js +248 -105
- package/package.json +1 -1
package/lib/client.js
CHANGED
|
@@ -9390,7 +9390,21 @@ function mpwThumbFail(el, why) {
|
|
|
9390
9390
|
宿主每帧都改 class/style,旧写法每帧同步跑一遍 applyFrostInline)。 */
|
|
9391
9391
|
let fraf = 0;
|
|
9392
9392
|
const frun = () => { fraf = 0; try { applyFrostInline(); } catch (e) {} };
|
|
9393
|
-
|
|
9393
|
+
/* ②(2026-10-05 真机采样定案:"刷新/切子代理会话时标题栏的模糊会闪一下消失")
|
|
9394
|
+
采样读数:`t=2028 frost=false attr=false`、下一帧又回来 —— 宿主切换视图时**重建了 header
|
|
9395
|
+
元素**,我们插在 header 里的磨砂层随旧节点被卸载,而重建走的是 rAF 合并的慢路
|
|
9396
|
+
⇒ 中间有 1~2 帧没有任何磨砂。修法:**新增节点**这一路同步重跑 `syncHeaderFrost()`
|
|
9397
|
+
(MutationObserver 回调是微任务,跑在绘制之前 ⇒ 那一帧就已经带上层),
|
|
9398
|
+
其余(class/style 变更)仍走 rAF 合并,避免动画期间每帧跑。 */
|
|
9399
|
+
frostObserver = new MutationObserver((records) => {
|
|
9400
|
+
let addedEl = false;
|
|
9401
|
+
try {
|
|
9402
|
+
for (const rec of (records || [])) {
|
|
9403
|
+
for (const n2 of (rec.addedNodes || [])) { if (n2 && n2.nodeType === 1) { addedEl = true; break } }
|
|
9404
|
+
if (addedEl) break;
|
|
9405
|
+
}
|
|
9406
|
+
} catch (e) { addedEl = true; }
|
|
9407
|
+
if (addedEl) { try { frun(); } catch (e) {} return; }
|
|
9394
9408
|
if (fraf) return;
|
|
9395
9409
|
try { fraf = (typeof requestAnimationFrame === "function") ? requestAnimationFrame(frun) : setTimeout(frun, 16); }
|
|
9396
9410
|
catch (e) { frun(); }
|
|
@@ -17991,24 +18005,24 @@ ${unifyTakeover ? `
|
|
|
17991
18005
|
现在接管真的做出来:这些表面与左栏**读同一套 token**(同色 + 同厚度 + 同半径),
|
|
17992
18006
|
于是"整屏虚化程度 + 左侧边栏/标题栏透明度"一改,右栏/dock 一起变。
|
|
17993
18007
|
位置在本块最后(与前文选择器同特异性时后者胜)⇒ 不需要额外的权重技巧。 */
|
|
17994
|
-
html body[data-mpw-unify] [data-
|
|
17995
|
-
html body[data-mpw-unify] [data-sidebar-right-float-host],
|
|
17996
|
-
html body[data-mpw-unify] [data-mpw-rs],
|
|
17997
|
-
html body[data-mpw-unify] [data-dockkit-pane],
|
|
17998
|
-
html body[data-mpw-unify] [data-dockkit-strip],
|
|
17999
|
-
html body[data-mpw-unify] [data-dockkit-surface],
|
|
18000
|
-
html body[data-mpw-unify] [data-dockkit-float] {
|
|
18008
|
+
html body[data-mpw-unify] [data-mpw-rs-surface],
|
|
18009
|
+
html body[data-mpw-unify] [data-mpw-rs-surface][data-sidebar-right-float-host],
|
|
18010
|
+
html body[data-mpw-unify] [data-mpw-rs-surface][data-mpw-rs],
|
|
18011
|
+
html body[data-mpw-unify] [data-mpw-rs-surface][data-dockkit-pane],
|
|
18012
|
+
html body[data-mpw-unify] [data-mpw-rs-surface][data-dockkit-strip],
|
|
18013
|
+
html body[data-mpw-unify] [data-mpw-rs-surface][data-dockkit-surface],
|
|
18014
|
+
html body[data-mpw-unify] [data-mpw-rs-surface][data-dockkit-float] {
|
|
18001
18015
|
-webkit-backdrop-filter: ${unifyBlurCss} !important;
|
|
18002
18016
|
backdrop-filter: ${unifyBlurCss} !important;
|
|
18003
18017
|
background-color: var(--mpw-unify-surface) !important;
|
|
18004
18018
|
}
|
|
18005
|
-
html body[data-ds-dark-theme][data-mpw-unify] [data-
|
|
18006
|
-
html body[data-ds-dark-theme][data-mpw-unify] [data-sidebar-right-float-host],
|
|
18007
|
-
html body[data-ds-dark-theme][data-mpw-unify] [data-mpw-rs],
|
|
18008
|
-
html body[data-ds-dark-theme][data-mpw-unify] [data-dockkit-pane],
|
|
18009
|
-
html body[data-ds-dark-theme][data-mpw-unify] [data-dockkit-strip],
|
|
18010
|
-
html body[data-ds-dark-theme][data-mpw-unify] [data-dockkit-surface],
|
|
18011
|
-
html body[data-ds-dark-theme][data-mpw-unify] [data-dockkit-float] {
|
|
18019
|
+
html body[data-ds-dark-theme][data-mpw-unify] [data-mpw-rs-surface],
|
|
18020
|
+
html body[data-ds-dark-theme][data-mpw-unify] [data-mpw-rs-surface][data-sidebar-right-float-host],
|
|
18021
|
+
html body[data-ds-dark-theme][data-mpw-unify] [data-mpw-rs-surface][data-mpw-rs],
|
|
18022
|
+
html body[data-ds-dark-theme][data-mpw-unify] [data-mpw-rs-surface][data-dockkit-pane],
|
|
18023
|
+
html body[data-ds-dark-theme][data-mpw-unify] [data-mpw-rs-surface][data-dockkit-strip],
|
|
18024
|
+
html body[data-ds-dark-theme][data-mpw-unify] [data-mpw-rs-surface][data-dockkit-surface],
|
|
18025
|
+
html body[data-ds-dark-theme][data-mpw-unify] [data-mpw-rs-surface][data-dockkit-float] {
|
|
18012
18026
|
background-color: var(--mpw-unify-surface-dark) !important;
|
|
18013
18027
|
}
|
|
18014
18028
|
/* better-sidebar 的面板 / 底部工作台:**只跟雾色与厚度,不给 backdrop-filter**。
|
|
@@ -18077,6 +18091,9 @@ html body[data-mpw-sblur-off] [data-mpw-rs] {
|
|
|
18077
18091
|
tok("--mpw-pop-surface", mpwSurfaceColor(surfacePlan.left.base, popFallbackAlpha).replace(/[\d.]+%/, `calc(var(--mpw-pop-surface-alpha, ${popFallbackAlpha.toFixed(2)}) * 100%)`));
|
|
18078
18092
|
tok("--mpw-pop-surface-alpha", popFallbackAlpha.toFixed(2));
|
|
18079
18093
|
tok("--mpw-pop-surface-dark", `rgba(18, 22, 30, var(--mpw-pop-surface-alpha, ${popFallbackAlpha.toFixed(2)}))`);
|
|
18094
|
+
/* ③(2026-10-05) C 类弹层(糊不到页面背后 ⇒ 做实在)专用的 88% 表面:**我们自己的 token**,
|
|
18095
|
+
不再借宿主 --dsw-specific-sidebar-fill(真机在侧栏作用域里它算出来是透明的 ⇒ 面板变透明)。 */
|
|
18096
|
+
tok("--mpw-pop-trunc-surface", mpwSurfaceColor(surfacePlan.left.base, 0.88));
|
|
18080
18097
|
tok("--mpw-surface-pop-dark", `rgba(18, 22, 30, var(--mpw-pop-alpha, ${(popSurfaceAlpha / 100).toFixed(2)}))`);
|
|
18081
18098
|
// 弹层**表面**选择器(背景 + 模糊共用一份,避免两处写法漂移)。
|
|
18082
18099
|
// ③(关键收窄 2026-09-13) 只用 [class*="_menu"] 会连**非表面**一起命中:
|
|
@@ -18085,13 +18102,17 @@ html body[data-mpw-sblur-off] [data-mpw-rs] {
|
|
|
18085
18102
|
// `._G5b-a_menuStatus`(说明文字)都含 "_menu" ——
|
|
18086
18103
|
// 给它们加 backdrop-filter 会在界面上糊出一块方块,加底色会糊出白块。
|
|
18087
18104
|
// 这里显式排除 anchor/icon/status/open/item/row/trigger/card 等非表面后缀。
|
|
18088
|
-
|
|
18105
|
+
/* ③(2026-10-05) 末尾追加 `:not([data-mpw-pop-untrunc])`:被我们"去截断"的祖先
|
|
18106
|
+
(见 lib 里的 mpwPopUntruncApply)不再吃这套弹层表面规则 —— 否则我们自己的
|
|
18107
|
+
blur 规则会跟去截断规则互相压制(真机:加号菜单容器的 blur 是**我们自己**给的,
|
|
18108
|
+
特异性还比注入的去截断规则高,摘不掉 ⇒ 内层弹层照旧被截断)。 */
|
|
18109
|
+
const POP_NOT = `:not([role="menuitem"]):not([role="option"]):not([class*="Anchor"]):not([class*="anchor"]):not([class*="Icon"]):not([class*="icon"]):not([class*="Status"]):not([class*="status"]):not([class*="Open"]):not([class*="open"]):not([class*="_item"]):not([class*="Item"]):not([class*="_row"]):not([class*="Row"]):not([class*="_trigger"]):not([class*="Trigger"]):not([class*="_card"]):not([class*="Card"]):not([class*="_groupTitle"]):not([class*="_viewport"]):not([data-mpw-pop-untrunc])`;
|
|
18089
18110
|
/* ①(2026-10-02 用户第 3 条⑥:上下文占用圆圈点开的框是**纯白**、没有玻璃感)
|
|
18090
18111
|
它的真实结构是 div.JObwrW_panel[role="dialog"][aria-label="上下文已用"] ⇒ 既不在
|
|
18091
18112
|
下面这串弹层选择器里(所以没有我们的底),又被"真弹层不做玻璃"那条按 role=dialog
|
|
18092
18113
|
清掉了模糊 ⇒ 纯白。把它(以及同类小面板)纳入弹层表面集合。 */
|
|
18093
18114
|
const popSurfaceSel = `[role="menu"]${POP_NOT}, [role="listbox"]${POP_NOT}, [role="combobox"]${POP_NOT}, [data-dsh-surface]${POP_NOT}, [class*="_menu"]${POP_NOT}, [class*="_popover"]${POP_NOT}, [class*="_dropdown"]${POP_NOT}, [class*="_denseList"]${POP_NOT}, [class*="JObwrW_panel"]${POP_NOT}`;
|
|
18094
|
-
const popTipSel = `[role="tooltip"], [role="alert"]`;
|
|
18115
|
+
const popTipSel = `[role="tooltip"]:not([data-mpw-pop-untrunc]), [role="alert"]:not([data-mpw-pop-untrunc])`;
|
|
18095
18116
|
/* ①(2026-10-02 用户第 3 条:「把这个好用的模糊效果独立成 token,因为还有几个地方也要实现」)
|
|
18096
18117
|
弹层表面 = **底色 + 模糊半径 + 圆角** 三件套,全部由这几枚 token 定义;任何弹层只要被
|
|
18097
18118
|
下面的选择器命中,就自动同一套效果(不再各处写死 rgba/blur)。
|
|
@@ -18133,11 +18154,25 @@ ${popSurfaceSel} {
|
|
|
18133
18154
|
html body [data-mpw-pop-bg] { background-color: var(--mpw-pop-surface) !important; }
|
|
18134
18155
|
/* ②(2026-10-05) 弹层处在一个"自己有底的玻璃祖先"里面(backdrop root 被截断 ⇒ 我们糊不到页面背后):
|
|
18135
18156
|
与其"半透明却没模糊"(真机被读成"只有白色滤镜"),不如**做实在**——表面不透明度抬到 88%,
|
|
18136
|
-
并把 backdrop-filter 撤掉(白算一遍)。注意:只动我们自己的标记属性,宿主元素一个都不碰。
|
|
18137
|
-
|
|
18138
|
-
|
|
18139
|
-
|
|
18140
|
-
html body [data-mpw-pop-
|
|
18157
|
+
并把 backdrop-filter 撤掉(白算一遍)。注意:只动我们自己的标记属性,宿主元素一个都不碰。
|
|
18158
|
+
③(2026-10-05) 底色改用**我们自己的** token(--mpw-pop-trunc-surface):原来借宿主
|
|
18159
|
+
--dsw-specific-sidebar-fill,真机在侧栏作用域里它被算成**透明**(color-mix 嵌套后 α=0)
|
|
18160
|
+
⇒ 面板整个变透明、白字直接看不见(提示气泡就是这么"没有底"的)。 */
|
|
18161
|
+
html body [data-mpw-pop-trunc] { background-color: var(--mpw-pop-trunc-surface, var(--mpw-pop-surface)) !important; backdrop-filter: none !important; -webkit-backdrop-filter: none !important; }
|
|
18162
|
+
/* ②(2026-10-05 v3 定案)「去截断 + 补霜」:弹层自己的 backdrop-filter 采样不到页面,是因为
|
|
18163
|
+
祖先链上有个创建 backdrop root 的元素(真机:输入框卡片 uV2eYG_card blur(14px))。
|
|
18164
|
+
B 类弹层开着期间给那个祖先打 data-mpw-pop-untrunc ⇒ 这条规则把它的 blur 摘掉(root 回到整页,
|
|
18165
|
+
弹层自己的 blur 立刻采样得到页面);丢掉的磨砂由 JS 在它内部补一层对齐霜层(data-mpw-pop-frost)。
|
|
18166
|
+
特异性 (0,2,2):压得过宿主按类名写的 !important 规则;而我们自己的弹层表面规则已经被
|
|
18167
|
+
POP_NOT 里的 :not([data-mpw-pop-untrunc]) 排除,不打架。 */
|
|
18168
|
+
html body [data-mpw-pop-untrunc][data-mpw-pop-untrunc] {
|
|
18169
|
+
backdrop-filter: none !important;
|
|
18170
|
+
-webkit-backdrop-filter: none !important;
|
|
18171
|
+
}
|
|
18172
|
+
/* ②(2026-10-05 v3) 旧「根级模糊层」机制已删除(真机结论:挂在卡片的层 root 被截断;
|
|
18173
|
+
挂 body 的层又会压住弹层——弹层在卡片的层叠上下文里)。data-mpw-pop-glass 现在只是"B 类、
|
|
18174
|
+
祖先截断已被我们摘掉"的**诊断标记**,没有任何 CSS 效果(弹层自己的 blur 照常工作)。 */
|
|
18175
|
+
html body [data-mpw-pop-frost] { background-color: transparent !important; }
|
|
18141
18176
|
html body[data-ds-dark-theme] [data-mpw-pop-bg] { background-color: var(--mpw-pop-surface-dark) !important; }
|
|
18142
18177
|
[role="menu"] [class*="card"],
|
|
18143
18178
|
[role="tooltip"] [class*="card"] {
|
|
@@ -24827,9 +24862,9 @@ body[data-mpw-modal] [role="dialog"] {
|
|
|
24827
24862
|
} catch { sblurObserver = null; }
|
|
24828
24863
|
// 窗口尺寸变化会让"近全屏"阈值与面板 rect 都变(父对话的真机判据就带视口切换)⇒ 一并重算
|
|
24829
24864
|
try { window.addEventListener("resize", recheck); } catch {}
|
|
24830
|
-
/*
|
|
24831
|
-
|
|
24832
|
-
|
|
24865
|
+
/* ③(2026-10-05 v3) 旧「根级模糊层」是 fixed + 按弹层 rect 对齐 ⇒ 那时才需要 scroll/resize 重贴;
|
|
24866
|
+
现在是"摘祖先 blur + 容器内 inset:0 的霜层",尺寸/位置全交给宿主自己的布局 ⇒ 两个监听删掉
|
|
24867
|
+
(顺带省掉滚动期的一路回调)。 */
|
|
24833
24868
|
check();
|
|
24834
24869
|
}
|
|
24835
24870
|
|
|
@@ -24939,10 +24974,22 @@ body[data-mpw-modal] [role="dialog"] {
|
|
|
24939
24974
|
} catch (e) { return 0 }
|
|
24940
24975
|
}
|
|
24941
24976
|
|
|
24977
|
+
/** 我们自己注入的节点(根级模糊层等):它们的突变**绝不能再喂回自己的快路**(否则死循环)。 */
|
|
24978
|
+
function mpwIsOurs(node) {
|
|
24979
|
+
try {
|
|
24980
|
+
if (!node || node.nodeType !== 1) return false;
|
|
24981
|
+
if (node.getAttribute && node.getAttribute("data-plugin") === "dsh-mpkg-wallpaper") return true;
|
|
24982
|
+
for (let p = node.parentElement, k = 0; p && k < 3; p = p.parentElement, k++) {
|
|
24983
|
+
if (p.getAttribute && p.getAttribute("data-plugin") === "dsh-mpkg-wallpaper") return true;
|
|
24984
|
+
}
|
|
24985
|
+
} catch (e) {}
|
|
24986
|
+
return false;
|
|
24987
|
+
}
|
|
24942
24988
|
function mpwTagPopoverFast(records) {
|
|
24943
24989
|
try {
|
|
24944
24990
|
let n = 0;
|
|
24945
24991
|
for (const rec of (records || [])) {
|
|
24992
|
+
if (mpwIsOurs(rec.target)) continue;
|
|
24946
24993
|
/* ②(2026-10-05 真机仍见白帧的根因) 弹层大多是**先插入(隐藏)→ 再靠 class/style 显形**:
|
|
24947
24994
|
只认 addedNodes 时,元素插入那一刻还是 display:none(判定不出"浮层面积",也看不见),
|
|
24948
24995
|
等它显形时走的是 **attributes 突变**,而旧观察器只监听 childList ⇒ 显形那一帧没人管,
|
|
@@ -24966,32 +25013,49 @@ body[data-mpw-modal] [role="dialog"] {
|
|
|
24966
25013
|
for (const el of cands) { if (mpwTagOnePopover(el)) n++; }
|
|
24967
25014
|
}
|
|
24968
25015
|
}
|
|
24969
|
-
|
|
24970
|
-
|
|
25016
|
+
/* ③(2026-10-05 会话里掉帧) 快路里**只留打标记**:mpwSideLiftSync 是全文档扫描
|
|
25017
|
+
(class* 子串匹配,代价随会话 DOM 线性涨),侧栏收起这类"宿主每帧改 DOM"的场景下
|
|
25018
|
+
每个突变批次都跑一次 ⇒ 会话里卡、空会话流畅。它挪去节流的重活路径(见 prun)。 */
|
|
25019
|
+
if (n) { try { mpwPopUntruncSync(); } catch (e) {} }
|
|
24971
25020
|
return n;
|
|
24972
25021
|
} catch (e) { return 0 }
|
|
24973
25022
|
}
|
|
24974
25023
|
/** 单个元素:该不该有我们的兜底底;返回是否发生了变化。 */
|
|
24975
25024
|
function mpwTagOnePopover(el) {
|
|
24976
25025
|
let need = false;
|
|
25026
|
+
let why = "";
|
|
24977
25027
|
try {
|
|
24978
25028
|
const cls = (typeof el.className === "string") ? el.className : "";
|
|
24979
|
-
|
|
25029
|
+
/* ③(2026-10-05 白字修复) **提示气泡(role=tooltip)不接管底色**:宿主的气泡是深底浅字
|
|
25030
|
+
(--dsw-alias-tooltip-bg = #2c2c2e 配 #fff 字),我们那层 58% 浅色表面压上去 ⇒
|
|
25031
|
+
白字看不清(真机:右栏右上角图标的气泡)。它自己的 blur 由 CSS 那条规则照常给。 */
|
|
25032
|
+
let isTip = false;
|
|
25033
|
+
try { isTip = el.getAttribute("role") === "tooltip" } catch (e) {}
|
|
25034
|
+
if (!MPW_POP_TAG_NOT.test(cls) && !isTip) {
|
|
24980
25035
|
const cs = getComputedStyle(el);
|
|
24981
25036
|
const blurred = !!(cs && /blur\(/.test(String(cs.backdropFilter || cs.webkitBackdropFilter || "")));
|
|
24982
25037
|
if (blurred) {
|
|
24983
|
-
|
|
24984
|
-
|
|
24985
|
-
|
|
24986
|
-
|
|
24987
|
-
|
|
24988
|
-
if (
|
|
24989
|
-
else if (
|
|
25038
|
+
/* ③(2026-10-05 闪烁修复) 已经带标记的:**只按当初那条结构性判据复核**,绝不重读底色。
|
|
25039
|
+
标记一生效,底色就变成我们自己画的 58%,重读会得到"宿主有半透明底"⇒ 撤标 ⇒
|
|
25040
|
+
宿主底回来 ⇒ 再打标 …… 逐帧自激(真机:"底色时有时无")。
|
|
25041
|
+
属性值就是当初的理由:empty = 宿主没画底;painted = 宿主画了不透明底。 */
|
|
25042
|
+
const reason = el.getAttribute("data-mpw-pop-bg");
|
|
25043
|
+
if (reason === "empty") { need = !mpwPopHasPaintedAncestor(el); why = "empty" }
|
|
25044
|
+
else if (reason === "painted") { need = mpwPopIsFloating(el); why = "painted" }
|
|
25045
|
+
else {
|
|
25046
|
+
const a = mpwColorAlpha(cs.backgroundColor);
|
|
25047
|
+
/* ②(2026-10-05) 两类分开判:
|
|
25048
|
+
· 宿主**没有底**(α<0.05)的弹层:**不要求此刻可见** —— 隐藏时打标无害,
|
|
25049
|
+
等它显形时表面已经在位(这正是"先插入后显形"那条路的白帧来源);
|
|
25050
|
+
· 宿主画了**不透明底**的小浮层:必须量得到面积(隐藏时 rect=0 ⇒ 留给下一次触发)。 */
|
|
25051
|
+
if (a < 0.05) { need = !mpwPopHasPaintedAncestor(el); why = "empty" }
|
|
25052
|
+
else if (a >= 0.999 && cs.display !== "none" && cs.visibility !== "hidden") { need = mpwPopIsFloating(el); why = "painted" }
|
|
25053
|
+
}
|
|
24990
25054
|
}
|
|
24991
25055
|
}
|
|
24992
25056
|
} catch (e) { need = false; }
|
|
24993
25057
|
try {
|
|
24994
|
-
if (need) { if (
|
|
25058
|
+
if (need) { if (el.getAttribute("data-mpw-pop-bg") !== why) { el.setAttribute("data-mpw-pop-bg", why); return true } }
|
|
24995
25059
|
else if (el.hasAttribute("data-mpw-pop-bg")) { el.removeAttribute("data-mpw-pop-bg"); return true }
|
|
24996
25060
|
} catch (e) {}
|
|
24997
25061
|
return false;
|
|
@@ -25003,7 +25067,8 @@ body[data-mpw-modal] [role="dialog"] {
|
|
|
25003
25067
|
for (let i = 0; i < list.length; i++) mpwTagOnePopover(list[i]);
|
|
25004
25068
|
}
|
|
25005
25069
|
|
|
25006
|
-
/* ①(P3 修复 2026-10-03
|
|
25070
|
+
/* ①(P3 修复 2026-10-03;历史:机制已被下面的 v3 取代,保留沿革与真机读数)
|
|
25071
|
+
弹层玻璃的 backdrop root 被截断 ⇒ 有半透明、没模糊。
|
|
25007
25072
|
读数与机制(docs/POPOVER-BLUR.md):挂在宿主输入框卡片(uV2eYG_card,backdrop-filter:
|
|
25008
25073
|
blur(14px))子树里的弹层,其 backdrop root 被卡片截断 ⇒ 弹层自己的 blur(11px) 只能采样
|
|
25009
25074
|
卡片内部 = 看不出模糊;挂在 body 下的模型选择器正常。实验定案:把表面移出祖先链即恢复
|
|
@@ -25014,64 +25079,100 @@ body[data-mpw-modal] [role="dialog"] {
|
|
|
25014
25079
|
(`[data-mpw-pop-untrunc] { backdrop-filter: none !important; }`)——只在弹层开着期间生效,
|
|
25015
25080
|
弹层关闭(无已标记表面)即摘属性、撤规则元素,宿主逐字还原。代价:属性表 + 一次
|
|
25016
25081
|
querySelectorAll,挂在 prun(已 rAF 合并 + mpwHeavyGate 闸门)里,不开新观察器。 */
|
|
25017
|
-
/* ②(2026-10-05 设计收口) 三类弹层,三条路(宿主元素一个都不碰):
|
|
25082
|
+
/* ②(2026-10-05 设计收口 v1) 三类弹层,三条路(宿主元素一个都不碰):
|
|
25018
25083
|
A. 没有模糊祖先(典型:挂在 body 下的模型/推理选择器)⇒ 我们自己的 58% 表面 + 自己的 blur;
|
|
25019
|
-
B.
|
|
25020
|
-
|
|
25021
|
-
|
|
25022
|
-
|
|
25023
|
-
|
|
25024
|
-
|
|
25025
|
-
|
|
25026
|
-
|
|
25027
|
-
|
|
25028
|
-
|
|
25029
|
-
|
|
25030
|
-
|
|
25031
|
-
|
|
25032
|
-
|
|
25033
|
-
|
|
25034
|
-
|
|
25035
|
-
|
|
25036
|
-
|
|
25037
|
-
|
|
25038
|
-
|
|
25039
|
-
|
|
25040
|
-
|
|
25041
|
-
|
|
25042
|
-
|
|
25043
|
-
|
|
25044
|
-
|
|
25045
|
-
|
|
25046
|
-
|
|
25047
|
-
|
|
25048
|
-
|
|
25049
|
-
|
|
25050
|
-
|
|
25051
|
-
|
|
25052
|
-
|
|
25053
|
-
|
|
25084
|
+
B. 祖先里有模糊、且那个祖先是**已知包装容器**(输入框卡片 / 菜单容器一类);
|
|
25085
|
+
C. 祖先里有模糊、但那不是包装容器(用户正在看的面板,例如子代理展开框)⇒ 88% 实底。 */
|
|
25086
|
+
/* ③(2026-10-05 v3 定案:**去截断 + 补霜**,取代 v2 的「根级模糊层」)
|
|
25087
|
+
为什么 v2 不行(真机读数 tools/host-popover-probe.mjs --groups glass-placement,结构性判据不用像素):
|
|
25088
|
+
· 层挂在**卡片子树里**(v2 最后那版紧挨弹层之前)⇒ 它的 backdrop root 被 uV2eYG_card
|
|
25089
|
+
(宿主自己的 backdrop-filter: blur(14px))截断,采样到的只是卡片内部已经糊过的底色
|
|
25090
|
+
⇒ 观感正好是用户报的"只剩一层白色半透明,模糊没了";
|
|
25091
|
+
· 层挂到 **body**(任何 z)⇒ root 确实干净了,但 `elementsFromPoint` 命中栈显示它**压在整个
|
|
25092
|
+
弹层之上**:弹层在卡片的层叠上下文里(卡片有 backdrop-filter ⇒ 自成层叠上下文),
|
|
25093
|
+
body 级定位元素整体画在它上面 ⇒ 弹层会被我们的层糊掉。两条路都堵死。
|
|
25094
|
+
所以只剩一条路:**把截断源头摘掉**——弹层开着期间给那个祖先打 `data-mpw-pop-untrunc`
|
|
25095
|
+
(静态规则 backdrop-filter:none !important ⇒ backdrop root 回到整页,弹层**自己的** blur
|
|
25096
|
+
立刻采样得到页面,连目标条一起糊),丢掉的磨砂由 `data-mpw-pop-frost` 补回来。
|
|
25097
|
+
真机验证(--groups glass-fix):卡片摘 bf + z-index:0(它本来就是 position:relative)后,
|
|
25098
|
+
弹层截断链**清空**、弹层矩形**一字不动**、补的霜层与卡片矩形完全重合、中心命中仍是弹层自己。
|
|
25099
|
+
代价:一次属性表 + 一次 querySelectorAll(挂在 prun,已 rAF 合并);层是 inset:0 的绝对定位,
|
|
25100
|
+
**不需要**随滚动/缩放重贴(v2 那两个 scroll/resize 监听因此删掉)。 */
|
|
25101
|
+
const popUntruncs = new Map(); // 祖先元素 -> { bf, radius, frost, frostKey, zInline }
|
|
25102
|
+
/** 该祖先能不能给"z-index:-1 的霜层"当层叠上下文:定位元素即可(静态元素我们不碰 ——
|
|
25103
|
+
给它 position:relative 会改包含块、把宿主弹层带跑,真机混账过)。 */
|
|
25104
|
+
function mpwPopCanCtx(el, cs) {
|
|
25105
|
+
try {
|
|
25106
|
+
if (cs && cs.position) return cs.position !== "static";
|
|
25107
|
+
return getComputedStyle(el).position !== "static";
|
|
25108
|
+
} catch (e) { return false }
|
|
25109
|
+
}
|
|
25110
|
+
/** 去截断 + 补霜(幂等:need 里没有的一律还原,宿主逐字回到原样)。 */
|
|
25111
|
+
function mpwPopUntruncApply(need) {
|
|
25112
|
+
let changed = 0;
|
|
25113
|
+
try {
|
|
25114
|
+
for (const el of Array.from(popUntruncs.keys())) {
|
|
25115
|
+
if (need && need.has(el) && el.isConnected !== false) continue;
|
|
25116
|
+
const rec = popUntruncs.get(el);
|
|
25117
|
+
if (rec && rec.frost && rec.frost.parentElement) { try { rec.frost.remove() } catch (e) {} }
|
|
25118
|
+
try { el.removeAttribute("data-mpw-pop-untrunc") } catch (e) {}
|
|
25119
|
+
/* 只还原我们动过的那一项(z-index 是我们为"造层叠上下文"补的) */
|
|
25120
|
+
if (rec && rec.zInline !== null) { try { el.style.zIndex = rec.zInline } catch (e) {} }
|
|
25121
|
+
popUntruncs.delete(el);
|
|
25122
|
+
changed++;
|
|
25054
25123
|
}
|
|
25055
|
-
|
|
25056
|
-
|
|
25057
|
-
|
|
25058
|
-
|
|
25059
|
-
|
|
25060
|
-
|
|
25061
|
-
|
|
25062
|
-
|
|
25063
|
-
|
|
25064
|
-
|
|
25124
|
+
if (!need) return changed;
|
|
25125
|
+
for (const el of need) {
|
|
25126
|
+
let rec = popUntruncs.get(el) || null;
|
|
25127
|
+
if (!rec) {
|
|
25128
|
+
let cs = null;
|
|
25129
|
+
try { cs = getComputedStyle(el) } catch (e) {}
|
|
25130
|
+
const bf = (cs && cs.backdropFilter && cs.backdropFilter !== "none") ? String(cs.backdropFilter) : "";
|
|
25131
|
+
rec = { bf: bf, radius: (cs && cs.borderTopLeftRadius) || "0px", frost: null, frostKey: "", zInline: null };
|
|
25132
|
+
popUntruncs.set(el, rec);
|
|
25133
|
+
try { el.setAttribute("data-mpw-pop-untrunc", "") } catch (e) {}
|
|
25134
|
+
/* 层叠上下文:定位元素且 z-index:auto 时补 z-index:0(auto 与 0 的绘制次序一致,
|
|
25135
|
+
不会把它挪到别的东西上下);已经是数值的不动(它本来就有层叠上下文)。 */
|
|
25136
|
+
try {
|
|
25137
|
+
const pcs = cs || getComputedStyle(el);
|
|
25138
|
+
if (pcs.position !== "static" && pcs.zIndex === "auto") { rec.zInline = el.style.zIndex || ""; el.style.zIndex = "0" }
|
|
25139
|
+
} catch (e) {}
|
|
25140
|
+
changed++;
|
|
25141
|
+
}
|
|
25142
|
+
const key = rec.bf + "|" + rec.radius;
|
|
25143
|
+
/* 存活判据用 parentElement + isConnected === false:桩/异常环境拿不到 isConnected 时
|
|
25144
|
+
也不会每轮重建霜层(重建 = 不可见的 DOM 抖动)。 */
|
|
25145
|
+
const frostAlive = !!(rec.frost && rec.frost.parentElement && rec.frost.isConnected !== false);
|
|
25146
|
+
if (rec.bf && rec.bf.indexOf("blur") >= 0 && (!frostAlive || rec.frostKey !== key)) {
|
|
25147
|
+
try { if (rec.frost && rec.frost.parentElement) rec.frost.remove() } catch (e) {}
|
|
25148
|
+
const frost = document.createElement("div");
|
|
25149
|
+
frost.setAttribute("data-plugin", "dsh-mpkg-wallpaper");
|
|
25150
|
+
frost.setAttribute("data-mpw-pop-frost", "");
|
|
25151
|
+
/* inset:0 + z-index:-1:按 CSS 绘制顺序画在**父元素背景之上、内容之下** ⇒
|
|
25152
|
+
容器自己的磨砂观感、圆角、内容层次全都不变(真机实测矩形与容器逐像素重合)。 */
|
|
25153
|
+
frost.style.cssText = "position:absolute;left:0;top:0;width:100%;height:100%;z-index:-1;pointer-events:none;"
|
|
25154
|
+
+ "border-radius:" + rec.radius + ";backdrop-filter:" + rec.bf + ";";
|
|
25155
|
+
rec.frost = frost;
|
|
25156
|
+
rec.frostKey = key;
|
|
25157
|
+
try { el.insertBefore(frost, el.firstChild) } catch (e) { try { el.appendChild(frost) } catch (e2) {} }
|
|
25158
|
+
changed++;
|
|
25159
|
+
}
|
|
25065
25160
|
}
|
|
25066
25161
|
} catch (e) {}
|
|
25162
|
+
return changed;
|
|
25067
25163
|
}
|
|
25068
25164
|
/* 判据出口(tools/popover-glass-test.mjs 直接用) */
|
|
25069
25165
|
try {
|
|
25070
25166
|
globalThis.__mpwPopUntruncTest = {
|
|
25071
25167
|
sync: () => mpwPopClassifySync(),
|
|
25072
|
-
/*
|
|
25073
|
-
glassCount: () =>
|
|
25074
|
-
|
|
25168
|
+
/* 旧名保留(旧判据引用过"根级模糊层"):v3 已经没有那层了,恒为 0 */
|
|
25169
|
+
glassCount: () => 0,
|
|
25170
|
+
/* 去截断的祖先数(每个都该配一层霜层:无 blur 可补的祖先不计霜层) */
|
|
25171
|
+
untruncCount: () => { try { return document.querySelectorAll("[data-mpw-pop-untrunc]").length } catch (e) { return 0 } },
|
|
25172
|
+
frostCount: () => { try { return document.querySelectorAll("[data-mpw-pop-frost]").length } catch (e) { return 0 } },
|
|
25173
|
+
truncCount: () => { try { return document.querySelectorAll("[data-mpw-pop-trunc]").length } catch (e) { return 0 } },
|
|
25174
|
+
/* 单个元素的兜底底判定(判据要能直接驱动它:闪烁是"打标/撤标"自激,必须单元素可复现) */
|
|
25175
|
+
tag: (el) => mpwTagOnePopover(el),
|
|
25075
25176
|
};
|
|
25076
25177
|
} catch (e) {}
|
|
25077
25178
|
|
|
@@ -25080,26 +25181,43 @@ body[data-mpw-modal] [role="dialog"] {
|
|
|
25080
25181
|
const surfaces = document.querySelectorAll("[data-mpw-pop-bg]");
|
|
25081
25182
|
const glasses = new Set();
|
|
25082
25183
|
const truncated = new Set();
|
|
25184
|
+
const neutralize = new Set();
|
|
25083
25185
|
for (let i = 0; i < surfaces.length; i++) {
|
|
25084
25186
|
const el = surfaces[i];
|
|
25085
25187
|
let cs = null;
|
|
25086
25188
|
try { cs = getComputedStyle(el) } catch (e) {}
|
|
25087
|
-
/* 硬前提:我们自己给了模糊才有"被截断"
|
|
25088
|
-
|
|
25189
|
+
/* 硬前提:我们自己给了模糊才有"被截断"这回事。
|
|
25190
|
+
③(2026-10-05 闪烁修复) **已带标记的表面必须放行**:C 类规则把表面的 backdrop-filter
|
|
25191
|
+
撤成 none,只认 computed blur 的话下一轮就会把刚打的标记摘掉 ⇒ 打标/撤标逐帧自激
|
|
25192
|
+
(真机实测:按钮提示气泡与几个面板底色"时有时无")。 */
|
|
25193
|
+
const marked = el.hasAttribute("data-mpw-pop-glass") || el.hasAttribute("data-mpw-pop-trunc");
|
|
25194
|
+
if (!marked && (!cs || !cs.backdropFilter || String(cs.backdropFilter).indexOf("blur") < 0)) continue;
|
|
25195
|
+
/* ③(2026-10-05) 提示气泡(role=tooltip)一律不接管:宿主的气泡是**深底浅字**
|
|
25196
|
+
(--dsw-alias-tooltip-bg 配 #fff 字),我们的表面/实底压上去 ⇒ 白字看不见。
|
|
25197
|
+
它自己的 blur 由 CSS 那条 [role="tooltip"] 规则照常给。 */
|
|
25198
|
+
try { if (el.getAttribute("role") === "tooltip") continue } catch (e) {}
|
|
25199
|
+
let path = "";
|
|
25200
|
+
const cands = []; // 这条链上"可去截断"的祖先(走完再决定用不用:C 路一个都不摘)
|
|
25089
25201
|
for (let p = el.parentElement, n = 0; p && p !== document.body && p !== document.documentElement && n < 12; p = p.parentElement, n++) {
|
|
25090
25202
|
let acs = null;
|
|
25091
25203
|
try { acs = getComputedStyle(p) } catch (e) { break }
|
|
25092
|
-
|
|
25204
|
+
/* ③(2026-10-05 反自激) 已经被我们"去截断"的祖先照样算截断祖先 —— 否则下一轮
|
|
25205
|
+
看不见它的 blur(被我们摘了)⇒ 判成 A ⇒ 撤标记 ⇒ 还原 blur ⇒ 再判 B … 逐帧自激。 */
|
|
25206
|
+
const declared = !!(p.hasAttribute && p.hasAttribute("data-mpw-pop-untrunc"));
|
|
25207
|
+
const ablur = declared || (acs && acs.backdropFilter && acs.backdropFilter !== "none" && String(acs.backdropFilter).indexOf("blur") >= 0);
|
|
25093
25208
|
if (!ablur) continue;
|
|
25094
|
-
let
|
|
25095
|
-
try {
|
|
25096
|
-
if (isSurface) { truncated.add(el); break } // C:用户正在看的面板 ⇒ 一个像素都不动
|
|
25209
|
+
let isOurDeco = false;
|
|
25210
|
+
try { isOurDeco = !declared && p.matches(MPW_POP_TAG_SEL) && !p.hasAttribute("data-mpw-pop-bg") } catch (e) {}
|
|
25097
25211
|
let wrap = false;
|
|
25098
|
-
try { wrap = /(_card|composer|overlayAnchor|_seat|_stack)/i.test(String(p.className || "")) } catch (e) {}
|
|
25099
|
-
|
|
25100
|
-
|
|
25212
|
+
try { wrap = declared || isOurDeco || /(_card|composer|overlayAnchor|_seat|_stack)/i.test(String(p.className || "")) } catch (e) {}
|
|
25213
|
+
/* B:能摘(它得是定位元素:霜层的 z-index:-1 要有层叠上下文兜住;真机两个截断祖先
|
|
25214
|
+
都是定位的)⇒ 记进待摘表;C:其余的(用户正在看的面板 / 未知祖先 / 静态元素)保守做实在。 */
|
|
25215
|
+
if (wrap && mpwPopCanCtx(p, acs)) { cands.push(p); continue }
|
|
25216
|
+
path = "C";
|
|
25101
25217
|
break;
|
|
25102
25218
|
}
|
|
25219
|
+
if (path === "C") truncated.add(el);
|
|
25220
|
+
else if (cands.length) { for (const p of cands) neutralize.add(p); glasses.add(el) }
|
|
25103
25221
|
}
|
|
25104
25222
|
const sync = (attr, want) => {
|
|
25105
25223
|
const stale = document.querySelectorAll("[" + attr + "]");
|
|
@@ -25108,7 +25226,7 @@ body[data-mpw-modal] [role="dialog"] {
|
|
|
25108
25226
|
};
|
|
25109
25227
|
sync("data-mpw-pop-glass", glasses);
|
|
25110
25228
|
sync("data-mpw-pop-trunc", truncated);
|
|
25111
|
-
|
|
25229
|
+
mpwPopUntruncApply(neutralize);
|
|
25112
25230
|
return glasses.size + truncated.size;
|
|
25113
25231
|
} catch (e) { return 0 }
|
|
25114
25232
|
}
|
|
@@ -25118,28 +25236,53 @@ body[data-mpw-modal] [role="dialog"] {
|
|
|
25118
25236
|
function setupPopTagWatch() {
|
|
25119
25237
|
if (popTagWatch !== null) return;
|
|
25120
25238
|
let praf = 0;
|
|
25239
|
+
/* ③(2026-10-05 会话里掉帧的根因) 下面这三个同步**每个都是全文档扫描**,而且选择器带
|
|
25240
|
+
`[class*=…]` 子串匹配 ⇒ 代价随会话 DOM 线性涨(真机现象正好是"空会话流畅、会话里卡":
|
|
25241
|
+
宿主在侧栏收起/展开动画期间每帧改 DOM ⇒ 每个突变批次都把这三趟全扫一遍)。
|
|
25242
|
+
改成**节流 + 尾随**:距上次 ≥150ms 才立刻跑;否则跳过并挂一个 180ms 的尾随定时器
|
|
25243
|
+
(突发结束一定还会跑一次,状态不会被饿死)。动画在跑时要求 600ms 才放行(优先保动画帧)。
|
|
25244
|
+
注意:标记本身(data-mpw-pop-bg 等)仍走快路,不受这里影响。 */
|
|
25245
|
+
let popHeavyLast = 0, popHeavyTimer = 0;
|
|
25246
|
+
const nowMs = () => { try { return (typeof performance !== "undefined" && performance.now) ? performance.now() : Date.now() } catch (e) { return Date.now() } };
|
|
25247
|
+
const popHeavySync = () => {
|
|
25248
|
+
popHeavyLast = nowMs();
|
|
25249
|
+
try { mpwTagSurfaceOuter(); } catch (e) {}
|
|
25250
|
+
try { mpwPopUntruncSync(); } catch (e) {}
|
|
25251
|
+
try { mpwSideLiftSync(); } catch (e) {}
|
|
25252
|
+
};
|
|
25253
|
+
const popHeavyTail = () => {
|
|
25254
|
+
if (popHeavyTimer) return;
|
|
25255
|
+
try {
|
|
25256
|
+
popHeavyTimer = setTimeout(() => { popHeavyTimer = 0; try { popHeavySync() } catch (e) {} }, 180);
|
|
25257
|
+
} catch (e) { popHeavyTimer = 0; }
|
|
25258
|
+
};
|
|
25121
25259
|
const prun = () => {
|
|
25122
25260
|
praf = 0;
|
|
25123
25261
|
try {
|
|
25124
25262
|
// 左栏收起/展开与拖拽期间宿主每帧改 DOM:跳过(收尾还会再来一次)
|
|
25125
25263
|
if (document.body && document.body.hasAttribute
|
|
25126
25264
|
&& (document.body.hasAttribute("data-dsh-sidebar-dragging") || document.body.hasAttribute("data-dragging"))) return;
|
|
25127
|
-
/*
|
|
25128
|
-
|
|
25129
|
-
|
|
25265
|
+
/* ②(2026-10-05 卡死 + 卡顿修复) 这一路**不再做全文档扫描**(旧写法每帧
|
|
25266
|
+
`querySelectorAll` 全文档,会话里元素多 ⇒ 侧栏动画就掉帧;空会话元素少 ⇒ 流畅,
|
|
25267
|
+
与真机观察完全一致)。全文档扫描只在 apply/初始那一次,突变一律走 fast path。 */
|
|
25130
25268
|
/* ②(2026-10-04) 右栏/dock 的"只留最外层"标记必须**跟着 DOM 走**:右栏面板是
|
|
25131
25269
|
用户打开后才挂载的,apply 那一刻它还不存在 ⇒ 只按一次会把 dock 错标成表面,
|
|
25132
25270
|
之后面板出现就变成两层(真机读数:dockPane/dockStrip 仍是 0.55)。
|
|
25133
|
-
|
|
25134
|
-
|
|
25135
|
-
|
|
25136
|
-
|
|
25137
|
-
/* ①(P3) 弹层开着 ⇒ 摘截断祖先的 blur;关了 ⇒ 还原(同一入口,随突变重算) */
|
|
25138
|
-
try { mpwPopUntruncSync(); } catch (e) {}
|
|
25271
|
+
这里与弹层标记共用同一个节流入口(要素很少时几乎立刻就跑)。 */
|
|
25272
|
+
const since = nowMs() - popHeavyLast;
|
|
25273
|
+
if (since >= 150 && (!mpwHeavyAnimRunning() || since >= 600)) popHeavySync();
|
|
25274
|
+
else popHeavyTail();
|
|
25139
25275
|
} catch (e) {}
|
|
25140
25276
|
};
|
|
25141
25277
|
try {
|
|
25142
25278
|
popTagWatch = new MutationObserver((records) => {
|
|
25279
|
+
/* ②(2026-10-05 卡死修复的第二道保险) 全是**我们自己**的写入(根级模糊层的 style 等)
|
|
25280
|
+
⇒ 直接返回:连 rAF 都不排,杜绝"写→观察→再写"的自激。 */
|
|
25281
|
+
let anyForeign = false;
|
|
25282
|
+
try {
|
|
25283
|
+
for (const rec of (records || [])) { if (!mpwIsOurs(rec.target)) { anyForeign = true; break } }
|
|
25284
|
+
} catch (e) { anyForeign = true; }
|
|
25285
|
+
if (!anyForeign) return;
|
|
25143
25286
|
/* 同步快路:新增的弹层当场判定打标(消灭"先白后变"的过渡态) */
|
|
25144
25287
|
try { mpwTagPopoverFast(records); } catch (e) {}
|
|
25145
25288
|
if (praf) return;
|
package/package.json
CHANGED